This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.git] / lib / msg.c
1 /*
2  * lib/msg.c            Netlink Messages Interface
3  *
4  *      This library is free software; you can redistribute it and/or
5  *      modify it under the terms of the GNU Lesser General Public
6  *      License as published by the Free Software Foundation version 2.1
7  *      of the License.
8  *
9  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup nl
14  * @defgroup msg Messages
15  * Netlink Message Construction/Parsing Interface
16  * 
17  * The following information is partly extracted from RFC3549
18  * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt)
19  *
20  * @par Message Format
21  * Netlink messages consist of a byte stream with one or multiple
22  * Netlink headers and an associated payload.  If the payload is too big
23  * to fit into a single message it, can be split over multiple Netlink
24  * messages, collectively called a multipart message.  For multipart
25  * messages, the first and all following headers have the \c NLM_F_MULTI
26  * Netlink header flag set, except for the last header which has the
27  * Netlink header type \c NLMSG_DONE.
28  *
29  * @par
30  * The Netlink message header (\link nlmsghdr struct nlmsghdr\endlink) is shown below.
31  * @code   
32  * 0                   1                   2                   3
33  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
34  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  * |                          Length                             |
36  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37  * |            Type              |           Flags              |
38  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39  * |                      Sequence Number                        |
40  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41  * |                      Process ID (PID)                       |
42  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43  * @endcode
44  *
45  * @par
46  * The netlink message header and payload must be aligned properly:
47  * @code
48  *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
49  * +----------------------------+- - -+- - - - - - - - - - -+- - -+
50  * |           Header           | Pad |       Payload       | Pad |
51  * |      struct nlmsghdr       |     |                     |     |
52  * +----------------------------+- - -+- - - - - - - - - - -+- - -+
53  * @endcode
54  * @par
55  * Message Format:
56  * @code
57  *    <--- nlmsg_total_size(payload)  --->
58  *    <-- nlmsg_msg_size(payload) ->
59  *   +----------+- - -+-------------+- - -+-------- - -
60  *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
61  *   +----------+- - -+-------------+- - -+-------- - -
62  *   nlmsg_data(nlh)---^                   ^
63  *   nlmsg_next(nlh)-----------------------+
64  * @endcode
65  * @par
66  * The payload may consist of arbitary data but may have strict
67  * alignment and formatting rules depening on the specific netlink
68  * families.
69  * @par
70  * @code
71  *    <---------------------- nlmsg_len(nlh) --------------------->
72  *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
73  *   +----------------------+- - -+--------------------------------+
74  *   |     Family Header    | Pad |           Attributes           |
75  *   +----------------------+- - -+--------------------------------+
76  *   nlmsg_attrdata(nlh, hdrlen)---^
77  * @endcode
78  * @par The ACK Netlink Message
79  * This message is actually used to denote both an ACK and a NACK.
80  * Typically, the direction is from FEC to CPC (in response to an ACK
81  * request message).  However, the CPC should be able to send ACKs back
82  * to FEC when requested.
83  * @code
84  *  0                   1                   2                   3
85  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
86  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87  * |                       Netlink message header                  |
88  * |                       type = NLMSG_ERROR                      |
89  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90  * |                          Error code                           |
91  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92  * |                       OLD Netlink message header              |
93  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94  * @endcode
95  *
96  * @par 1) Creating a new netlink message
97  * @code
98  * // The most common way to start creating a message is by providing an
99  * // defined netlink header to nlmsg_build():
100  * struct nlmsghdr hdr = {
101  *      .nlmsg_type = MY_TYPE,
102  *      .nlmsg_flags = MY_FLAGS,
103  * };
104  * struct nl_msg *msg = nlmsg_build(&hdr);
105  *
106  * // For simple usages where only the message type and flags is of
107  * // interenst a shortcut can be taken:
108  * struct nl_msg *msg = nlmsg_build_simple(MY_TYPE, MY_FLAGS);
109  *
110  * // When using a headerless message for creating nested attributes
111  * // the header is not required and nlmsg_build_no_hdr() may be used:
112  * struct nl_msg *msg = nlmsg_build_no_hdr();
113  *
114  * // The header can later be retrieved with nlmsg_hdr() and changed again:
115  * nlmsg_hdr(msg)->nlmsg_flags |= YET_ANOTHER_FLAG;
116  * @endcode
117  *
118  * @par 2) Appending data to the message
119  * @code
120  * // Payload may be added to the message via nlmsg_append(). The fourth
121  * // parameter specifies whether to pad up to NLMSG_ALIGN to make sure
122  * // that a possible further data block is properly aligned.
123  * nlmsg_append(msg, &mydata, sizeof(mydata), 0);
124  * @endcode
125  *
126  * @par 3) Cleaning up message construction
127  * @code
128  * // After successful use of the message, the memory must be freed
129  * // using nlmsg_free()
130  * nlmsg_free(msg);
131  * @endcode
132  * 
133  * @par Example 2 (Parsing messages):
134  * @code
135  * int n;
136  * unsigned char *buf;
137  * struct nlmsghdr *hdr;
138  *
139  * n = nl_recv(handle, NULL, &buf);
140  * 
141  * hdr = (struct nlmsghdr *) buf;
142  * while (nlmsg_ok(hdr, n)) {
143  *      // Process message here...
144  *      hdr = nlmsg_next(hdr, &n);
145  * }
146  * @endcode
147  * @{
148  */
149
150 #include <netlink-local.h>
151 #include <netlink/netlink.h>
152 #include <netlink/utils.h>
153 #include <netlink/cache.h>
154 #include <netlink/attr.h>
155 #include <linux/socket.h>
156
157 /**
158  * @name Size Calculations
159  * @{
160  */
161
162 /**
163  * length of netlink message not including padding
164  * @arg payload         length of message payload
165  */
166 int nlmsg_msg_size(int payload)
167 {
168         return NLMSG_HDRLEN + payload;
169 }
170
171 /**
172  * length of netlink message including padding
173  * @arg payload         length of message payload
174  */
175 int nlmsg_total_size(int payload)
176 {
177         return NLMSG_ALIGN(nlmsg_msg_size(payload));
178 }
179
180 /**
181  * length of padding at the message's tail
182  * @arg payload         length of message payload
183  */
184 int nlmsg_padlen(int payload)
185 {
186         return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
187 }
188
189 /** @} */
190
191 /**
192  * @name Payload Access
193  * @{
194  */
195
196 /**
197  * head of message payload
198  * @arg nlh             netlink messsage header
199  */
200 void *nlmsg_data(const struct nlmsghdr *nlh)
201 {
202         return (unsigned char *) nlh + NLMSG_HDRLEN;
203 }
204
205 void *nlmsg_tail(const struct nlmsghdr *nlh)
206 {
207         return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
208 }
209
210 /**
211  * length of message payload
212  * @arg nlh             netlink message header
213  */
214 int nlmsg_len(const struct nlmsghdr *nlh)
215 {
216         return nlh->nlmsg_len - NLMSG_HDRLEN;
217 }
218
219 /** @} */
220
221 /**
222  * @name Attribute Access
223  * @{
224  */
225
226 /**
227  * head of attributes data
228  * @arg nlh             netlink message header
229  * @arg hdrlen          length of family specific header
230  */
231 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
232 {
233         unsigned char *data = nlmsg_data(nlh);
234         return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
235 }
236
237 /**
238  * length of attributes data
239  * @arg nlh             netlink message header
240  * @arg hdrlen          length of family specific header
241  */
242 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
243 {
244         return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
245 }
246
247 /** @} */
248
249 /**
250  * @name Message Parsing
251  * @{
252  */
253
254 /**
255  * check if the netlink message fits into the remaining bytes
256  * @arg nlh             netlink message header
257  * @arg remaining       number of bytes remaining in message stream
258  */
259 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
260 {
261         return (remaining >= sizeof(struct nlmsghdr) &&
262                 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
263                 nlh->nlmsg_len <= remaining);
264 }
265
266 /**
267  * next netlink message in message stream
268  * @arg nlh             netlink message header
269  * @arg remaining       number of bytes remaining in message stream
270  *
271  * @returns the next netlink message in the message stream and
272  * decrements remaining by the size of the current message.
273  */
274 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
275 {
276         int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
277
278         *remaining -= totlen;
279
280         return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
281 }
282
283 /**
284  * parse attributes of a netlink message
285  * @arg nlh             netlink message header
286  * @arg hdrlen          length of family specific header
287  * @arg tb              destination array with maxtype+1 elements
288  * @arg maxtype         maximum attribute type to be expected
289  * @arg policy          validation policy
290  *
291  * See nla_parse()
292  */
293 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
294                 int maxtype, struct nla_policy *policy)
295 {
296         if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
297                 return nl_errno(EINVAL);
298
299         return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
300                          nlmsg_attrlen(nlh, hdrlen), policy);
301 }
302
303 /**
304  * nlmsg_find_attr - find a specific attribute in a netlink message
305  * @arg nlh             netlink message header
306  * @arg hdrlen          length of familiy specific header
307  * @arg attrtype        type of attribute to look for
308  *
309  * Returns the first attribute which matches the specified type.
310  */
311 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
312 {
313         return nla_find(nlmsg_attrdata(nlh, hdrlen),
314                         nlmsg_attrlen(nlh, hdrlen), attrtype);
315 }
316
317 /**
318  * nlmsg_validate - validate a netlink message including attributes
319  * @arg nlh             netlinket message header
320  * @arg hdrlen          length of familiy specific header
321  * @arg maxtype         maximum attribute type to be expected
322  * @arg policy          validation policy
323  */
324 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
325                    struct nla_policy *policy)
326 {
327         if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
328                 return nl_errno(EINVAL);
329
330         return nla_validate(nlmsg_attrdata(nlh, hdrlen),
331                             nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
332 }
333
334 /** @} */
335
336 /**
337  * @name Message Building/Access
338  * @{
339  */
340
341 struct nl_msg *nlmsg_new(void)
342 {
343         struct nl_msg *nm;
344
345         nm = calloc(1, sizeof(*nm));
346         if (!nm)
347                 goto errout;
348
349         nm->nm_nlh = calloc(1, nlmsg_msg_size(0));
350         if (!nm->nm_nlh)
351                 goto errout;
352
353         nm->nm_nlh->nlmsg_len = nlmsg_msg_size(0);
354         return nm;
355 errout:
356         free(nm);
357         nl_errno(ENOMEM);
358         return NULL;
359 }
360
361
362 /**
363  * Build a new netlink message
364  * @arg hdr             Netlink message header template
365  *
366  * Builds a new netlink message with a tailroom for the netlink
367  * message header. If \a hdr is not NULL it will be used as a
368  * template for the netlink message header, otherwise the header
369  * is left blank.
370  * 
371  * @return Newly allocated netlink message or NULL
372  */ 
373 struct nl_msg *nlmsg_build(struct nlmsghdr *hdr)
374 {
375         struct nl_msg *nm;
376
377         nm = nlmsg_new();
378         if (nm && hdr) {
379                 int size = nm->nm_nlh->nlmsg_len;
380                 memcpy(nm->nm_nlh, hdr, sizeof(*hdr));
381                 nm->nm_nlh->nlmsg_len = size;
382         }
383
384         return nm;
385 }
386
387 struct nl_msg *nlmsg_build_simple(int nlmsgtype, int flags)
388 {
389         struct nlmsghdr nlh = {
390                 .nlmsg_type = nlmsgtype,
391                 .nlmsg_flags = flags,
392         };
393
394         return nlmsg_build(&nlh);
395 }
396
397 struct nl_msg *nlmsg_build_no_hdr(void)
398 {
399         return nlmsg_build(NULL);
400 }
401
402 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
403 {
404         struct nl_msg *nm;
405
406         nm = calloc(1, sizeof(struct nl_msg));
407         if (!nm)
408                 goto errout;
409
410         nm->nm_nlh = calloc(1, NLMSG_ALIGN(hdr->nlmsg_len));
411         if (!nm->nm_nlh)
412                 goto errout;
413
414         memcpy(nm->nm_nlh, hdr, NLMSG_ALIGN(hdr->nlmsg_len));
415
416         return nm;
417 errout:
418         free(nm);
419         nl_errno(ENOMEM);
420         return NULL;
421 }
422
423 /**
424  * Append raw data to a netlink message
425  * @arg n               netlink message
426  * @arg data            data to add
427  * @arg len             length of data
428  * @arg pad             add padding at the end?
429  *
430  * Extends the netlink message as needed and appends the data of given
431  * length to the message. The length of the message is not aligned to
432  * anything. The caller is responsible to provide a length and
433  * evtentually padded data to fullfil any alignment requirements.
434  *
435  * @return 0 on success or a negative error code
436  * @attention Appending of improperly aligned raw data may result in
437  *            a corrupt message. It is left to you to add the right
438  *            amount of data to have the message aligned to NLMSG_ALIGNTO
439  *            in the end.
440  */
441 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
442 {
443         void *tmp;
444
445         if (pad)
446                 len = NLMSG_ALIGN(len);
447
448         tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + len);
449         if (!tmp)
450                 return nl_errno(ENOMEM);
451
452         n->nm_nlh = tmp;
453         memcpy((void *) n->nm_nlh + n->nm_nlh->nlmsg_len, data, len);
454         n->nm_nlh->nlmsg_len += len;
455
456         return 0;
457 }
458
459
460 /**
461  * nlmsg_put - Add a netlink message header
462  * @arg n               netlink message
463  * @arg pid             netlink process id
464  * @arg seq             sequence number of message
465  * @arg type            message type
466  * @arg payload         length of message payload
467  * @arg flags           message flags
468  */
469 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
470                            int type, int payload, int flags)
471 {
472         struct nlmsghdr *nlh;
473
474         if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
475                 BUG();
476
477         nlh = (struct nlmsghdr *) n->nm_nlh;
478         nlh->nlmsg_type = type;
479         nlh->nlmsg_len = nlmsg_msg_size(payload);
480         nlh->nlmsg_flags = flags;
481         nlh->nlmsg_pid = pid;
482         nlh->nlmsg_seq = seq;
483
484         memset((unsigned char *) nlmsg_data(nlh) + payload, 0,
485                nlmsg_padlen(payload));
486
487         return nlh;
488 }
489
490 /**
491  * Return actual netlink message
492  * @arg n               netlink message
493  * 
494  * Returns the actual netlink message casted to the type of the netlink
495  * message header.
496  * 
497  * @return A pointer to the netlink message.
498  */
499 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
500 {
501         return n->nm_nlh;
502 }
503
504 /**
505  * Free a netlink message
506  * @arg n               netlink message
507  *
508  * Destroys a netlink message and frees up all used memory.
509  *
510  * @pre The message must be unused.
511  */
512 void nlmsg_free(struct nl_msg *n)
513 {
514         if (!n)
515                 return;
516
517         free(n->nm_nlh);
518         free(n);
519 }
520
521 /** @} */
522
523 /**
524  * @name Attribute Modification
525  * @{
526  */
527
528 void nlmsg_set_proto(struct nl_msg *msg, int protocol)
529 {
530         msg->nm_protocol = protocol;
531 }
532
533 int nlmsg_get_proto(struct nl_msg *msg)
534 {
535         return msg->nm_protocol;
536 }
537
538 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
539 {
540         memcpy(&msg->nm_src, addr, sizeof(*addr));
541 }
542
543 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
544 {
545         return &msg->nm_src;
546 }
547
548 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
549 {
550         memcpy(&msg->nm_dst, addr, sizeof(*addr));
551 }
552
553 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
554 {
555         return &msg->nm_dst;
556 }
557
558 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
559 {
560         memcpy(&msg->nm_creds, creds, sizeof(*creds));
561         msg->nm_flags |= NL_MSG_CRED_PRESENT;
562 }
563
564 struct ucred *nlmsg_get_creds(struct nl_msg *msg)
565 {
566         if (msg->nm_flags & NL_MSG_CRED_PRESENT)
567                 return &msg->nm_creds;
568         return NULL;
569 }
570
571 /** @} */
572
573 /**
574  * @name Netlink Message Type Translations
575  * @{
576  */
577
578 static struct trans_tbl nl_msgtypes[] = {
579         __ADD(NLMSG_NOOP,NOOP)
580         __ADD(NLMSG_ERROR,ERROR)
581         __ADD(NLMSG_DONE,DONE)
582         __ADD(NLMSG_OVERRUN,OVERRUN)
583 };
584
585 /**
586  * Convert netlink message type number to character string.
587  * @arg type            Netlink message type.
588  * @arg buf             Destination buffer.
589  * @arg size            Size of destination buffer.
590  *
591  * Converts a netlink message type number to a character string and stores
592  * it in the provided buffer.
593  *
594  * @return The destination buffer or the type encoded in hexidecimal form
595  *         if no match was found.
596  */
597 char *nl_nlmsgtype2str(int type, char *buf, size_t size)
598 {
599         return __type2str(type, buf, size, nl_msgtypes,
600                           ARRAY_SIZE(nl_msgtypes));
601 }
602
603 /**
604  * Convert character string to netlink message type.
605  * @arg name            Name of netlink message type.
606  *
607  * Converts the provided character string specifying a netlink message type
608  * into the corresponding numeric value
609  *
610  * @return Numeric netlink message type or a negative value
611  *         if no match was found.
612  */
613 int nl_str2nlmsgtype(const char *name)
614 {
615         return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
616 }
617
618 /** @} */
619
620 /**
621  * @name Netlink Message Flags Translations
622  * @{
623  */
624
625 /**
626  * Translate netlink message flags into a character string (Reentrant).
627  * @arg flags           netlink message flags
628  * @arg buf             destination buffer
629  * @arg len             buffer length
630  *
631  * Translates netlink message flags into a character string and stores
632  * it in the provided buffer.
633  *
634  * @return The destination buffer
635  */
636 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
637 {
638         memset(buf, 0, len);
639
640 #define PRINT_FLAG(f) \
641         if (flags & NLM_F_##f) { \
642                 flags &= ~NLM_F_##f; \
643                 strncat(buf, #f, len - strlen(buf) - 1); \
644                 if (flags) \
645                         strncat(buf, ",", len - strlen(buf) - 1); \
646         }
647         
648         PRINT_FLAG(REQUEST);
649         PRINT_FLAG(MULTI);
650         PRINT_FLAG(ACK);
651         PRINT_FLAG(ECHO);
652         PRINT_FLAG(ROOT);
653         PRINT_FLAG(MATCH);
654         PRINT_FLAG(ATOMIC);
655         PRINT_FLAG(REPLACE);
656         PRINT_FLAG(EXCL);
657         PRINT_FLAG(CREATE);
658         PRINT_FLAG(APPEND);
659
660         if (flags) {
661                 char s[32];
662                 snprintf(s, sizeof(s), "0x%x", flags);
663                 strncat(buf, s, len - strlen(buf) - 1);
664         }
665 #undef PRINT_FLAG
666
667         return buf;
668 }
669
670 /** @} */
671
672 /**
673  * @name Direct Parsing
674  * @{
675  */
676
677 /** @cond SKIP */
678 struct dp_xdata {
679         void (*cb)(struct nl_object *, void *);
680         void *arg;
681 };
682 /** @endcond */
683
684 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
685 {
686         struct dp_xdata *x = p->pp_arg;
687
688         x->cb(obj, x->arg);
689         nl_object_put(obj);
690         return 0;
691 }
692
693 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
694                  void *arg)
695 {
696         struct nl_cache_ops *ops;
697         struct nl_parser_param p = {
698                 .pp_cb = parse_cb
699         };
700         struct dp_xdata x = {
701                 .cb = cb,
702                 .arg = arg,
703         };
704
705         ops = nl_cache_mngt_associate(nlmsg_get_proto(msg),
706                                       nlmsg_hdr(msg)->nlmsg_type);
707         if (ops == NULL)
708                 return nl_error(ENOENT, "Unknown message type %d",
709                                 nlmsg_hdr(msg)->nlmsg_type);
710         p.pp_arg = &x;
711
712         return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
713 }
714
715 /** @} */
716
717 /** @} */