blob: caae744bdaeffba2f7b1941ba168873ffd5488f2 [file] [log] [blame]
Thomas Graf44d36242007-09-15 01:28:01 +02001/*
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 * // Netlink messages can be allocated in various ways, you may
99 * // allocate an empty netlink message by using nlmsg_alloc():
100 * struct nl_msg *msg = nlmsg_alloc();
101 *
102 * // Very often, the message type and message flags are known
103 * // at allocation time while the other fields are auto generated:
104 * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS);
105 *
106 * // Alternatively an existing netlink message header can be used
107 * // to inherit header values from:
108 * struct nlmsghdr hdr = {
109 * .nlmsg_type = MY_TYPE,
110 * .nlmsg_flags = MY_FLAGS,
111 * };
112 * struct nl_msg *msg = nlmsg_inherit(&hdr);
113 *
114 * // Last but not least, netlink messages received from netlink sockets
115 * // can be converted into nl_msg objects using nlmsg_convert():
116 * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock);
117 *
118 * // The header can later be retrieved with nlmsg_hdr() and changed again:
119 * nlmsg_hdr(msg)->nlmsg_flags |= YET_ANOTHER_FLAG;
120 * @endcode
121 *
122 * @par 2) Appending data to the message
123 * @code
124 * // Payload may be added to the message via nlmsg_append(). The fourth
125 * // parameter specifies the number of alignment bytes the data should
126 * // be padding with at the end. Common values are 0 to disable it or
127 * // NLMSG_ALIGNTO to ensure proper netlink message padding.
128 * nlmsg_append(msg, &mydata, sizeof(mydata), 0);
129 *
130 * // Sometimes it may be necessary to reserve room for data but defer
131 * // the actual copying to a later point, nlmsg_reserve() can be used
132 * // for this purpose:
133 * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO);
134 * @endcode
135 *
136 * @par 3) Cleaning up message construction
137 * @code
138 * // After successful use of the message, the memory must be freed
139 * // using nlmsg_free()
140 * nlmsg_free(msg);
141 * @endcode
142 *
143 * @par 4) Parsing messages
144 * @code
145 * int n;
146 * unsigned char *buf;
147 * struct nlmsghdr *hdr;
148 *
149 * n = nl_recv(handle, NULL, &buf);
150 *
151 * hdr = (struct nlmsghdr *) buf;
152 * while (nlmsg_ok(hdr, n)) {
153 * // Process message here...
154 * hdr = nlmsg_next(hdr, &n);
155 * }
156 * @endcode
157 * @{
158 */
159
160#include <netlink-local.h>
161#include <netlink/netlink.h>
162#include <netlink/utils.h>
163#include <netlink/cache.h>
164#include <netlink/attr.h>
165#include <linux/socket.h>
166
167/**
168 * @name Size Calculations
169 * @{
170 */
171
172/**
173 * length of netlink message not including padding
174 * @arg payload length of message payload
175 */
176int nlmsg_msg_size(int payload)
177{
178 return NLMSG_HDRLEN + payload;
179}
180
181/**
182 * length of netlink message including padding
183 * @arg payload length of message payload
184 */
185int nlmsg_total_size(int payload)
186{
187 return NLMSG_ALIGN(nlmsg_msg_size(payload));
188}
189
190/**
191 * length of padding at the message's tail
192 * @arg payload length of message payload
193 */
194int nlmsg_padlen(int payload)
195{
196 return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
197}
198
199/** @} */
200
201/**
202 * @name Payload Access
203 * @{
204 */
205
206/**
207 * head of message payload
208 * @arg nlh netlink messsage header
209 */
210void *nlmsg_data(const struct nlmsghdr *nlh)
211{
212 return (unsigned char *) nlh + NLMSG_HDRLEN;
213}
214
215void *nlmsg_tail(const struct nlmsghdr *nlh)
216{
217 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
218}
219
220/**
221 * length of message payload
222 * @arg nlh netlink message header
223 */
224int nlmsg_len(const struct nlmsghdr *nlh)
225{
226 return nlh->nlmsg_len - NLMSG_HDRLEN;
227}
228
229/** @} */
230
231/**
232 * @name Attribute Access
233 * @{
234 */
235
236/**
237 * head of attributes data
238 * @arg nlh netlink message header
239 * @arg hdrlen length of family specific header
240 */
241struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
242{
243 unsigned char *data = nlmsg_data(nlh);
244 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
245}
246
247/**
248 * length of attributes data
249 * @arg nlh netlink message header
250 * @arg hdrlen length of family specific header
251 */
252int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
253{
254 return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
255}
256
257/** @} */
258
259/**
260 * @name Message Parsing
261 * @{
262 */
263
264/**
265 * check if the netlink message fits into the remaining bytes
266 * @arg nlh netlink message header
267 * @arg remaining number of bytes remaining in message stream
268 */
269int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
270{
271 return (remaining >= sizeof(struct nlmsghdr) &&
272 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
273 nlh->nlmsg_len <= remaining);
274}
275
276/**
277 * next netlink message in message stream
278 * @arg nlh netlink message header
279 * @arg remaining number of bytes remaining in message stream
280 *
281 * @returns the next netlink message in the message stream and
282 * decrements remaining by the size of the current message.
283 */
284struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
285{
286 int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
287
288 *remaining -= totlen;
289
290 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
291}
292
293/**
294 * parse attributes of a netlink message
295 * @arg nlh netlink message header
296 * @arg hdrlen length of family specific header
297 * @arg tb destination array with maxtype+1 elements
298 * @arg maxtype maximum attribute type to be expected
299 * @arg policy validation policy
300 *
301 * See nla_parse()
302 */
303int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
304 int maxtype, struct nla_policy *policy)
305{
306 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
307 return nl_errno(EINVAL);
308
309 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
310 nlmsg_attrlen(nlh, hdrlen), policy);
311}
312
313/**
314 * nlmsg_find_attr - find a specific attribute in a netlink message
315 * @arg nlh netlink message header
316 * @arg hdrlen length of familiy specific header
317 * @arg attrtype type of attribute to look for
318 *
319 * Returns the first attribute which matches the specified type.
320 */
321struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
322{
323 return nla_find(nlmsg_attrdata(nlh, hdrlen),
324 nlmsg_attrlen(nlh, hdrlen), attrtype);
325}
326
327/**
328 * nlmsg_validate - validate a netlink message including attributes
329 * @arg nlh netlinket message header
330 * @arg hdrlen length of familiy specific header
331 * @arg maxtype maximum attribute type to be expected
332 * @arg policy validation policy
333 */
334int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
335 struct nla_policy *policy)
336{
337 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
338 return nl_errno(EINVAL);
339
340 return nla_validate(nlmsg_attrdata(nlh, hdrlen),
341 nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
342}
343
344/** @} */
345
346/**
347 * @name Message Building/Access
348 * @{
349 */
350
351static struct nl_msg *__nlmsg_alloc(size_t len)
352{
353 struct nl_msg *nm;
354
355 nm = calloc(1, sizeof(*nm));
356 if (!nm)
357 goto errout;
358
359 nm->nm_nlh = calloc(1, len);
360 if (!nm->nm_nlh)
361 goto errout;
362
363 nm->nm_protocol = -1;
364 nm->nm_nlh->nlmsg_len = len;
365
366 NL_DBG(2, "msg %p: Allocated new message, nlmsg_len=%d\n", nm, len);
367
368 return nm;
369errout:
370 free(nm);
371 nl_errno(ENOMEM);
372 return NULL;
373}
374
375/**
376 * Allocate a new netlink message
377 *
378 * Allocates a new netlink message without any further payload.
379 *
380 * @return Newly allocated netlink message or NULL.
381 */
382struct nl_msg *nlmsg_alloc(void)
383{
384 return __nlmsg_alloc(nlmsg_total_size(0));
385}
386
387/**
388 * Allocate a new netlink message and inherit netlink message header
389 * @arg hdr Netlink message header template
390 *
391 * Allocates a new netlink message with a tailroom for the netlink
392 * message header. If \a hdr is not NULL it will be used as a
393 * template for the netlink message header, otherwise the header
394 * is left blank.
395 *
396 * @return Newly allocated netlink message or NULL
397 */
398struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
399{
400 struct nl_msg *nm;
401
402 nm = nlmsg_alloc();
403 if (nm && hdr) {
404 struct nlmsghdr *new = nm->nm_nlh;
405
406 new->nlmsg_type = hdr->nlmsg_type;
407 new->nlmsg_flags = hdr->nlmsg_flags;
408 new->nlmsg_seq = hdr->nlmsg_seq;
409 new->nlmsg_pid = hdr->nlmsg_pid;
410 }
411
412 return nm;
413}
414
415/**
416 * Allocate a new netlink message
417 * @arg nlmsgtype Netlink message type
418 * @arg flags Message flags.
419 *
420 * @return Newly allocated netlink message or NULL.
421 */
422struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
423{
424 struct nl_msg *msg;
425 struct nlmsghdr nlh = {
426 .nlmsg_type = nlmsgtype,
427 .nlmsg_flags = flags,
428 };
429
430 msg = nlmsg_inherit(&nlh);
431 if (msg)
432 NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
433
434 return msg;
435}
436
437/**
438 * Convert a netlink message received from a netlink socket to a nl_msg
439 * @arg hdr Netlink message received from netlink socket.
440 *
441 * Allocates a new netlink message and copies all of the data pointed to
442 * by \a hdr into the new message object.
443 *
444 * @return Newly allocated netlink message or NULL.
445 */
446struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
447{
448 struct nl_msg *nm;
449
450 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
451 if (!nm)
452 goto errout;
453
454 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
455
456 return nm;
457errout:
458 nlmsg_free(nm);
459 return NULL;
460}
461
462/**
463 * Reserve room for additional data in a netlink message
464 * @arg n netlink message
465 * @arg len length of additional data to reserve room for
466 * @arg pad number of bytes to align data to
467 *
468 * Reserves room for additional data at the tail of the an
469 * existing netlink message. Eventual padding required will
470 * be zeroed out.
471 *
472 * @note All existing pointers into the old data section may have
473 * become obsolete and illegal to reference after this call.
474 *
475 * @return Pointer to start of additional data tailroom or NULL.
476 */
477void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
478{
479 void *tmp;
480 size_t tlen;
481
482 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
483
484 tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + tlen);
485 if (!tmp) {
486 nl_errno(ENOMEM);
487 return NULL;
488 }
489
490 n->nm_nlh = tmp;
491 tmp += n->nm_nlh->nlmsg_len;
492 n->nm_nlh->nlmsg_len += tlen;
493
494 if (tlen > len)
495 memset(tmp + len, 0, tlen - len);
496
497 NL_DBG(2, "msg %p: Reserved %d bytes, pad=%d, nlmsg_len=%d\n",
498 n, len, pad, n->nm_nlh->nlmsg_len);
499
500 return tmp;
501}
502
503/**
504 * Append data to tail of a netlink message
505 * @arg n netlink message
506 * @arg data data to add
507 * @arg len length of data
508 * @arg pad Number of bytes to align data to.
509 *
510 * Extends the netlink message as needed and appends the data of given
511 * length to the message.
512 *
513 * @note All existing pointers into the old data section may have
514 * become obsolete and illegal to reference after this call.
515 *
516 * @return 0 on success or a negative error code
517 */
518int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
519{
520 void *tmp;
521
522 tmp = nlmsg_reserve(n, len, pad);
523 if (tmp == NULL)
524 return nl_errno(ENOMEM);
525
526 memcpy(tmp, data, len);
527 NL_DBG(2, "msg %p: Appended %d bytes with padding %d\n", n, len, pad);
528
529 return 0;
530}
531
532/**
533 * Add a netlink message header to a netlink message
534 * @arg n netlink message
535 * @arg pid netlink process id or NL_AUTO_PID
536 * @arg seq sequence number of message or NL_AUTO_SEQ
537 * @arg type message type
538 * @arg payload length of message payload
539 * @arg flags message flags
540 *
541 * Adds or overwrites the netlink message header in an existing message
542 * object. If \a payload is greater-than zero additional room will be
543 * reserved, f.e. for family specific headers. It can be accesed via
544 * nlmsg_data().
545 *
546 * @return A pointer to the netlink message header or NULL.
547 */
548struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
549 int type, int payload, int flags)
550{
551 struct nlmsghdr *nlh;
552
553 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
554 BUG();
555
556 nlh = (struct nlmsghdr *) n->nm_nlh;
557 nlh->nlmsg_type = type;
558 nlh->nlmsg_flags = flags;
559 nlh->nlmsg_pid = pid;
560 nlh->nlmsg_seq = seq;
561
562 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
563 "seq=%d\n", n, type, flags, pid, seq);
564
565 if (payload > 0 &&
566 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
567 return NULL;
568
569 return nlh;
570}
571
572/**
573 * Return actual netlink message
574 * @arg n netlink message
575 *
576 * Returns the actual netlink message casted to the type of the netlink
577 * message header.
578 *
579 * @return A pointer to the netlink message.
580 */
581struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
582{
583 return n->nm_nlh;
584}
585
586/**
587 * Free a netlink message
588 * @arg n netlink message
589 *
590 * Destroys a netlink message and frees up all used memory.
591 *
592 * @pre The message must be unused.
593 */
594void nlmsg_free(struct nl_msg *n)
595{
596 if (!n)
597 return;
598
599 free(n->nm_nlh);
600 free(n);
601 NL_DBG(2, "msg %p: Freed\n", n);
602}
603
604/** @} */
605
606/**
607 * @name Attributes
608 * @{
609 */
610
611void nlmsg_set_proto(struct nl_msg *msg, int protocol)
612{
613 msg->nm_protocol = protocol;
614}
615
616int nlmsg_get_proto(struct nl_msg *msg)
617{
618 return msg->nm_protocol;
619}
620
621void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
622{
623 memcpy(&msg->nm_src, addr, sizeof(*addr));
624}
625
626struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
627{
628 return &msg->nm_src;
629}
630
631void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
632{
633 memcpy(&msg->nm_dst, addr, sizeof(*addr));
634}
635
636struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
637{
638 return &msg->nm_dst;
639}
640
641void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
642{
643 memcpy(&msg->nm_creds, creds, sizeof(*creds));
644 msg->nm_flags |= NL_MSG_CRED_PRESENT;
645}
646
647struct ucred *nlmsg_get_creds(struct nl_msg *msg)
648{
649 if (msg->nm_flags & NL_MSG_CRED_PRESENT)
650 return &msg->nm_creds;
651 return NULL;
652}
653
654/** @} */
655
656/**
657 * @name Netlink Message Type Translations
658 * @{
659 */
660
661static struct trans_tbl nl_msgtypes[] = {
662 __ADD(NLMSG_NOOP,NOOP)
663 __ADD(NLMSG_ERROR,ERROR)
664 __ADD(NLMSG_DONE,DONE)
665 __ADD(NLMSG_OVERRUN,OVERRUN)
666};
667
668char *nl_nlmsgtype2str(int type, char *buf, size_t size)
669{
670 return __type2str(type, buf, size, nl_msgtypes,
671 ARRAY_SIZE(nl_msgtypes));
672}
673
674int nl_str2nlmsgtype(const char *name)
675{
676 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
677}
678
679/** @} */
680
681/**
682 * @name Netlink Message Flags Translations
683 * @{
684 */
685
686char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
687{
688 memset(buf, 0, len);
689
690#define PRINT_FLAG(f) \
691 if (flags & NLM_F_##f) { \
692 flags &= ~NLM_F_##f; \
693 strncat(buf, #f, len - strlen(buf) - 1); \
694 if (flags) \
695 strncat(buf, ",", len - strlen(buf) - 1); \
696 }
697
698 PRINT_FLAG(REQUEST);
699 PRINT_FLAG(MULTI);
700 PRINT_FLAG(ACK);
701 PRINT_FLAG(ECHO);
702 PRINT_FLAG(ROOT);
703 PRINT_FLAG(MATCH);
704 PRINT_FLAG(ATOMIC);
705 PRINT_FLAG(REPLACE);
706 PRINT_FLAG(EXCL);
707 PRINT_FLAG(CREATE);
708 PRINT_FLAG(APPEND);
709
710 if (flags) {
711 char s[32];
712 snprintf(s, sizeof(s), "0x%x", flags);
713 strncat(buf, s, len - strlen(buf) - 1);
714 }
715#undef PRINT_FLAG
716
717 return buf;
718}
719
720/** @} */
721
722/**
723 * @name Direct Parsing
724 * @{
725 */
726
727/** @cond SKIP */
728struct dp_xdata {
729 void (*cb)(struct nl_object *, void *);
730 void *arg;
731};
732/** @endcond */
733
734static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
735{
736 struct dp_xdata *x = p->pp_arg;
737
738 x->cb(obj, x->arg);
739 nl_object_put(obj);
740 return 0;
741}
742
743int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
744 void *arg)
745{
746 struct nl_cache_ops *ops;
747 struct nl_parser_param p = {
748 .pp_cb = parse_cb
749 };
750 struct dp_xdata x = {
751 .cb = cb,
752 .arg = arg,
753 };
754
755 ops = nl_cache_mngt_associate(nlmsg_get_proto(msg),
756 nlmsg_hdr(msg)->nlmsg_type);
757 if (ops == NULL)
758 return nl_error(ENOENT, "Unknown message type %d",
759 nlmsg_hdr(msg)->nlmsg_type);
760 p.pp_arg = &x;
761
762 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
763}
764
765/** @} */
766
767/**
768 * @name Dumping
769 * @{
770 */
771
772static void prefix_line(FILE *ofd, int prefix)
773{
774 int i;
775
776 for (i = 0; i < prefix; i++)
777 fprintf(ofd, " ");
778}
779
780static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
781{
782 int i, a, c, limit;
783 char ascii[21] = {0};
784
785 limit = 18 - (prefix * 2);
786 prefix_line(ofd, prefix);
787 fprintf(ofd, " ");
788
789 for (i = 0, a = 0, c = 0; i < len; i++) {
790 int v = *(uint8_t *) (start + i);
791
792 fprintf(ofd, "%02x ", v);
793 ascii[a++] = isprint(v) ? v : '.';
794
795 if (c == limit-1) {
796 fprintf(ofd, "%s\n", ascii);
797 if (i < (len - 1)) {
798 prefix_line(ofd, prefix);
799 fprintf(ofd, " ");
800 }
801 a = c = 0;
802 memset(ascii, 0, sizeof(ascii));
803 } else
804 c++;
805 }
806
807 if (c != 0) {
808 for (i = 0; i < (limit - c); i++)
809 fprintf(ofd, " ");
810 fprintf(ofd, "%s\n", ascii);
811 }
812}
813
814static void print_hdr(FILE *ofd, struct nl_msg *msg)
815{
816 struct nlmsghdr *nlh = nlmsg_hdr(msg);
817 struct nl_cache_ops *ops;
818 char buf[128];
819
820 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len);
821
822 ops = nl_cache_mngt_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
823
824 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type,
825 ops ? nl_cache_mngt_type2name(ops, msg->nm_protocol,
826 nlh->nlmsg_type, buf, sizeof(buf))
827 : nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)));
828 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
829 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
830 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq);
831 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid);
832
833}
834
835static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
836 int prefix)
837{
838 int rem;
839 struct nlattr *nla;
840
841 nla_for_each_attr(nla, attrs, attrlen, rem) {
842 int padlen, alen = nla_len(nla);
843
844 prefix_line(ofd, prefix);
845 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla),
846 nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
847 alen);
848
849 if (nla->nla_type & NLA_F_NESTED)
850 dump_attrs(ofd, nla_data(nla), alen, prefix+1);
851 else
852 dump_hex(ofd, nla_data(nla), alen, prefix);
853
854 padlen = nla_padlen(alen);
855 if (padlen > 0) {
856 prefix_line(ofd, prefix);
857 fprintf(ofd, " [PADDING] %d octets\n",
858 padlen);
859 dump_hex(ofd, nla_data(nla) + alen,
860 padlen, prefix);
861 }
862 }
863
864 if (rem) {
865 prefix_line(ofd, prefix);
866 fprintf(ofd, " [LEFTOVER] %d octets\n", rem);
867 }
868}
869
870/**
871 * Dump message in human readable format to file descriptor
872 * @arg msg Message to print
873 * @arg ofd File descriptor.
874 */
875void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
876{
877 struct nlmsghdr *hdr = nlmsg_hdr(msg);
878
879 fprintf(ofd,
880 "-------------------------- BEGIN NETLINK MESSAGE "
881 "---------------------------\n");
882
883 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
884 print_hdr(ofd, msg);
885
886 if (hdr->nlmsg_type == NLMSG_ERROR &&
887 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
888 struct nl_msg *errmsg;
889 struct nlmsgerr *err = nlmsg_data(hdr);
890
891 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err));
892 fprintf(ofd, " .error = %d \"%s\"\n", err->error,
893 strerror(-err->error));
894 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
895
896 errmsg = nlmsg_inherit(&err->msg);
897 print_hdr(ofd, errmsg);
898 nlmsg_free(errmsg);
899 } else if (nlmsg_len(hdr) > 0) {
900 struct nl_cache_ops *ops;
901 int payloadlen = nlmsg_len(hdr);
902 int attrlen = 0;
903
904 ops = nl_cache_mngt_associate(nlmsg_get_proto(msg),
905 hdr->nlmsg_type);
906 if (ops) {
907 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
908 payloadlen -= attrlen;
909 }
910
911 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen);
912 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
913
914 if (attrlen) {
915 struct nlattr *attrs;
916 int attrlen;
917
918 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
919 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
920 dump_attrs(ofd, attrs, attrlen, 0);
921 }
922 }
923
924 fprintf(ofd,
925 "--------------------------- END NETLINK MESSAGE "
926 "---------------------------\n");
927}
928
929/** @} */
930
931/** @} */