• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libnl-tiny/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-2008 Thomas Graf <tgraf@suug.ch>
 10  */
 11 
 12 /**
 13  * @ingroup core
 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 Example
 97  * @code
 98  * // Various methods exist to create/allocate a new netlink
 99  * // message. 
100  * //
101  * // nlmsg_alloc() will allocate an empty netlink message with
102  * // a maximum payload size which defaults to the page size of
103  * // the system. This default size can be modified using the
104  * // function nlmsg_set_default_size().
105  * struct nl_msg *msg = nlmsg_alloc();
106  *
107  * // Very often, the message type and message flags are known
108  * // at allocation time while the other fields are auto generated:
109  * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS);
110  *
111  * // Alternatively an existing netlink message header can be used
112  * // to inherit the header values:
113  * struct nlmsghdr hdr = {
114  *      .nlmsg_type = MY_TYPE,
115  *      .nlmsg_flags = MY_FLAGS,
116  * };
117  * struct nl_msg *msg = nlmsg_inherit(&hdr);
118  *
119  * // Last but not least, netlink messages received from netlink sockets
120  * // can be converted into nl_msg objects using nlmsg_convert(). This
121  * // will create a message with a maximum payload size which equals the
122  * // length of the existing netlink message, therefore no more data can
123  * // be appened without calling nlmsg_expand() first.
124  * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock);
125  *
126  * // Payload may be added to the message via nlmsg_append(). The fourth
127  * // parameter specifies the number of alignment bytes the data should
128  * // be padding with at the end. Common values are 0 to disable it or
129  * // NLMSG_ALIGNTO to ensure proper netlink message padding.
130  * nlmsg_append(msg, &mydata, sizeof(mydata), 0);
131  *
132  * // Sometimes it may be necessary to reserve room for data but defer
133  * // the actual copying to a later point, nlmsg_reserve() can be used
134  * // for this purpose:
135  * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO);
136  *
137  * // Attributes may be added using the attributes interface.
138  *
139  * // After successful use of the message, the memory must be freed
140  * // using nlmsg_free()
141  * nlmsg_free(msg);
142  * @endcode
143  * 
144  * @par 4) Parsing messages
145  * @code
146  * int n;
147  * unsigned char *buf;
148  * struct nlmsghdr *hdr;
149  *
150  * n = nl_recv(handle, NULL, &buf);
151  * 
152  * hdr = (struct nlmsghdr *) buf;
153  * while (nlmsg_ok(hdr, n)) {
154  *      // Process message here...
155  *      hdr = nlmsg_next(hdr, &n);
156  * }
157  * @endcode
158  * @{
159  */
160 
161 #include <netlink-local.h>
162 #include <netlink/netlink.h>
163 #include <netlink/utils.h>
164 #include <netlink/cache.h>
165 #include <netlink/attr.h>
166 #include <netlink/msg.h>
167 #include <linux/socket.h>
168 
169 static size_t default_msg_size = 4096;
170 
171 /**
172  * @name Attribute Access
173  * @{
174  */
175 
176 //** @} */
177 
178 /**
179  * @name Message Parsing
180  * @{
181  */
182 
183 /**
184  * check if the netlink message fits into the remaining bytes
185  * @arg nlh             netlink message header
186  * @arg remaining       number of bytes remaining in message stream
187  */
188 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
189 {
190         size_t r = remaining;
191 
192         return (r >= sizeof(struct nlmsghdr) &&
193                 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
194                 nlh->nlmsg_len <= r);
195 }
196 
197 /**
198  * next netlink message in message stream
199  * @arg nlh             netlink message header
200  * @arg remaining       number of bytes remaining in message stream
201  *
202  * @returns the next netlink message in the message stream and
203  * decrements remaining by the size of the current message.
204  */
205 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
206 {
207         int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
208 
209         *remaining -= totlen;
210 
211         return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
212 }
213 
214 /**
215  * parse attributes of a netlink message
216  * @arg nlh             netlink message header
217  * @arg hdrlen          length of family specific header
218  * @arg tb              destination array with maxtype+1 elements
219  * @arg maxtype         maximum attribute type to be expected
220  * @arg policy          validation policy
221  *
222  * See nla_parse()
223  */
224 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
225                 int maxtype, struct nla_policy *policy)
226 {
227         if (!nlmsg_valid_hdr(nlh, hdrlen))
228                 return -NLE_MSG_TOOSHORT;
229 
230         return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
231                          nlmsg_attrlen(nlh, hdrlen), policy);
232 }
233 
234 /**
235  * nlmsg_validate - validate a netlink message including attributes
236  * @arg nlh             netlinket message header
237  * @arg hdrlen          length of familiy specific header
238  * @arg maxtype         maximum attribute type to be expected
239  * @arg policy          validation policy
240  */
241 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
242                    struct nla_policy *policy)
243 {
244         if (!nlmsg_valid_hdr(nlh, hdrlen))
245                 return -NLE_MSG_TOOSHORT;
246 
247         return nla_validate(nlmsg_attrdata(nlh, hdrlen),
248                             nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
249 }
250 
251 /** @} */
252 
253 /**
254  * @name Message Building/Access
255  * @{
256  */
257 
258 static struct nl_msg *__nlmsg_alloc(size_t len)
259 {
260         struct nl_msg *nm;
261 
262         nm = calloc(1, sizeof(*nm));
263         if (!nm)
264                 goto errout;
265 
266         nm->nm_refcnt = 1;
267 
268         nm->nm_nlh = malloc(len);
269         if (!nm->nm_nlh)
270                 goto errout;
271 
272         memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
273 
274         nm->nm_protocol = -1;
275         nm->nm_size = len;
276         nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
277 
278         NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
279 
280         return nm;
281 errout:
282         free(nm);
283         return NULL;
284 }
285 
286 /**
287  * Allocate a new netlink message with the default maximum payload size.
288  *
289  * Allocates a new netlink message without any further payload. The
290  * maximum payload size defaults to PAGESIZE or as otherwise specified
291  * with nlmsg_set_default_size().
292  *
293  * @return Newly allocated netlink message or NULL.
294  */
295 struct nl_msg *nlmsg_alloc(void)
296 {
297         return __nlmsg_alloc(default_msg_size);
298 }
299 
300 /**
301  * Allocate a new netlink message with maximum payload size specified.
302  */
303 struct nl_msg *nlmsg_alloc_size(size_t max)
304 {
305         return __nlmsg_alloc(max);
306 }
307 
308 /**
309  * Allocate a new netlink message and inherit netlink message header
310  * @arg hdr             Netlink message header template
311  *
312  * Allocates a new netlink message and inherits the original message
313  * header. If \a hdr is not NULL it will be used as a template for
314  * the netlink message header, otherwise the header is left blank.
315  * 
316  * @return Newly allocated netlink message or NULL
317  */
318 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
319 {
320         struct nl_msg *nm;
321 
322         nm = nlmsg_alloc();
323         if (nm && hdr) {
324                 struct nlmsghdr *new = nm->nm_nlh;
325 
326                 new->nlmsg_type = hdr->nlmsg_type;
327                 new->nlmsg_flags = hdr->nlmsg_flags;
328                 new->nlmsg_seq = hdr->nlmsg_seq;
329                 new->nlmsg_pid = hdr->nlmsg_pid;
330         }
331 
332         return nm;
333 }
334 
335 /**
336  * Allocate a new netlink message
337  * @arg nlmsgtype       Netlink message type
338  * @arg flags           Message flags.
339  *
340  * @return Newly allocated netlink message or NULL.
341  */
342 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
343 {
344         struct nl_msg *msg;
345         struct nlmsghdr nlh = {
346                 .nlmsg_type = nlmsgtype,
347                 .nlmsg_flags = flags,
348         };
349 
350         msg = nlmsg_inherit(&nlh);
351         if (msg)
352                 NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
353 
354         return msg;
355 }
356 
357 /**
358  * Set the default maximum message payload size for allocated messages
359  * @arg max             Size of payload in bytes.
360  */
361 void nlmsg_set_default_size(size_t max)
362 {
363         if (max < (size_t) nlmsg_total_size(0))
364                 max = nlmsg_total_size(0);
365 
366         default_msg_size = max;
367 }
368 
369 /**
370  * Convert a netlink message received from a netlink socket to a nl_msg
371  * @arg hdr             Netlink message received from netlink socket.
372  *
373  * Allocates a new netlink message and copies all of the data pointed to
374  * by \a hdr into the new message object.
375  *
376  * @return Newly allocated netlink message or NULL.
377  */
378 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
379 {
380         struct nl_msg *nm;
381 
382         nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
383         if (!nm)
384                 goto errout;
385 
386         memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
387 
388         return nm;
389 errout:
390         nlmsg_free(nm);
391         return NULL;
392 }
393 
394 /**
395  * Reserve room for additional data in a netlink message
396  * @arg n               netlink message
397  * @arg len             length of additional data to reserve room for
398  * @arg pad             number of bytes to align data to
399  *
400  * Reserves room for additional data at the tail of the an
401  * existing netlink message. Eventual padding required will
402  * be zeroed out.
403  *
404  * @return Pointer to start of additional data tailroom or NULL.
405  */
406 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
407 {
408         void *buf = n->nm_nlh;
409         size_t nlmsg_len = n->nm_nlh->nlmsg_len;
410         size_t tlen;
411 
412         tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
413 
414         if ((tlen + nlmsg_len) > n->nm_size)
415                 return NULL;
416 
417         buf += nlmsg_len;
418         n->nm_nlh->nlmsg_len += tlen;
419 
420         if (tlen > len)
421                 memset(buf + len, 0, tlen - len);
422 
423         NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
424                   n, len, pad, n->nm_nlh->nlmsg_len);
425 
426         return buf;
427 }
428 
429 /**
430  * Append data to tail of a netlink message
431  * @arg n               netlink message
432  * @arg data            data to add
433  * @arg len             length of data
434  * @arg pad             Number of bytes to align data to.
435  *
436  * Extends the netlink message as needed and appends the data of given
437  * length to the message. 
438  *
439  * @return 0 on success or a negative error code
440  */
441 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
442 {
443         void *tmp;
444 
445         tmp = nlmsg_reserve(n, len, pad);
446         if (tmp == NULL)
447                 return -NLE_NOMEM;
448 
449         memcpy(tmp, data, len);
450         NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
451 
452         return 0;
453 }
454 
455 /**
456  * Add a netlink message header to a netlink message
457  * @arg n               netlink message
458  * @arg pid             netlink process id or NL_AUTO_PID
459  * @arg seq             sequence number of message or NL_AUTO_SEQ
460  * @arg type            message type
461  * @arg payload         length of message payload
462  * @arg flags           message flags
463  *
464  * Adds or overwrites the netlink message header in an existing message
465  * object. If \a payload is greater-than zero additional room will be
466  * reserved, f.e. for family specific headers. It can be accesed via
467  * nlmsg_data().
468  *
469  * @return A pointer to the netlink message header or NULL.
470  */
471 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
472                            int type, int payload, int flags)
473 {
474         struct nlmsghdr *nlh;
475 
476         if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
477                 BUG();
478 
479         nlh = (struct nlmsghdr *) n->nm_nlh;
480         nlh->nlmsg_type = type;
481         nlh->nlmsg_flags = flags;
482         nlh->nlmsg_pid = pid;
483         nlh->nlmsg_seq = seq;
484 
485         NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
486                   "seq=%d\n", n, type, flags, pid, seq);
487 
488         if (payload > 0 &&
489             nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
490                 return NULL;
491 
492         return nlh;
493 }
494 
495 /**
496  * Release a reference from an netlink message
497  * @arg msg             message to release reference from
498  *
499  * Frees memory after the last reference has been released.
500  */
501 void nlmsg_free(struct nl_msg *msg)
502 {
503         if (!msg)
504                 return;
505 
506         msg->nm_refcnt--;
507         NL_DBG(4, "Returned message reference %p, %d remaining\n",
508                msg, msg->nm_refcnt);
509 
510         if (msg->nm_refcnt < 0)
511                 BUG();
512 
513         if (msg->nm_refcnt <= 0) {
514                 free(msg->nm_nlh);
515                 free(msg);
516                 NL_DBG(2, "msg %p: Freed\n", msg);
517         }
518 }
519 
520 /** @} */
521 
522 /**
523  * @name Direct Parsing
524  * @{
525  */
526 
527 /** @cond SKIP */
528 struct dp_xdata {
529         void (*cb)(struct nl_object *, void *);
530         void *arg;
531 };
532 /** @endcond */
533 
534 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
535 {
536         struct dp_xdata *x = p->pp_arg;
537 
538         x->cb(obj, x->arg);
539         return 0;
540 }
541 
542 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
543                  void *arg)
544 {
545         struct nl_cache_ops *ops;
546         struct nl_parser_param p = {
547                 .pp_cb = parse_cb
548         };
549         struct dp_xdata x = {
550                 .cb = cb,
551                 .arg = arg,
552         };
553 
554         ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
555                                      nlmsg_hdr(msg)->nlmsg_type);
556         if (ops == NULL)
557                 return -NLE_MSGTYPE_NOSUPPORT;
558         p.pp_arg = &x;
559 
560         return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
561 }
562 
563 /** @} */
564 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt