blob: 3ae890911ab42678ea6ecf35c2ee8665e016e92b [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
Thomas Grafc8a0a5c2008-01-10 12:35:38 +0100264int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
265{
266 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
267 return 0;
268
269 return 1;
270}
271
Thomas Graf44d36242007-09-15 01:28:01 +0200272/**
273 * check if the netlink message fits into the remaining bytes
274 * @arg nlh netlink message header
275 * @arg remaining number of bytes remaining in message stream
276 */
277int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
278{
279 return (remaining >= sizeof(struct nlmsghdr) &&
280 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
281 nlh->nlmsg_len <= remaining);
282}
283
284/**
285 * next netlink message in message stream
286 * @arg nlh netlink message header
287 * @arg remaining number of bytes remaining in message stream
288 *
289 * @returns the next netlink message in the message stream and
290 * decrements remaining by the size of the current message.
291 */
292struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
293{
294 int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
295
296 *remaining -= totlen;
297
298 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
299}
300
301/**
302 * parse attributes of a netlink message
303 * @arg nlh netlink message header
304 * @arg hdrlen length of family specific header
305 * @arg tb destination array with maxtype+1 elements
306 * @arg maxtype maximum attribute type to be expected
307 * @arg policy validation policy
308 *
309 * See nla_parse()
310 */
311int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
312 int maxtype, struct nla_policy *policy)
313{
Thomas Grafc8a0a5c2008-01-10 12:35:38 +0100314 if (!nlmsg_valid_hdr(nlh, hdrlen))
Thomas Graf44d36242007-09-15 01:28:01 +0200315 return nl_errno(EINVAL);
316
317 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
318 nlmsg_attrlen(nlh, hdrlen), policy);
319}
320
321/**
322 * nlmsg_find_attr - find a specific attribute in a netlink message
323 * @arg nlh netlink message header
324 * @arg hdrlen length of familiy specific header
325 * @arg attrtype type of attribute to look for
326 *
327 * Returns the first attribute which matches the specified type.
328 */
329struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
330{
331 return nla_find(nlmsg_attrdata(nlh, hdrlen),
332 nlmsg_attrlen(nlh, hdrlen), attrtype);
333}
334
335/**
336 * nlmsg_validate - validate a netlink message including attributes
337 * @arg nlh netlinket message header
338 * @arg hdrlen length of familiy specific header
339 * @arg maxtype maximum attribute type to be expected
340 * @arg policy validation policy
341 */
342int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
343 struct nla_policy *policy)
344{
Thomas Grafc8a0a5c2008-01-10 12:35:38 +0100345 if (!nlmsg_valid_hdr(nlh, hdrlen))
Thomas Graf44d36242007-09-15 01:28:01 +0200346 return nl_errno(EINVAL);
347
348 return nla_validate(nlmsg_attrdata(nlh, hdrlen),
349 nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
350}
351
352/** @} */
353
354/**
355 * @name Message Building/Access
356 * @{
357 */
358
359static struct nl_msg *__nlmsg_alloc(size_t len)
360{
361 struct nl_msg *nm;
362
363 nm = calloc(1, sizeof(*nm));
364 if (!nm)
365 goto errout;
366
367 nm->nm_nlh = calloc(1, len);
368 if (!nm->nm_nlh)
369 goto errout;
370
371 nm->nm_protocol = -1;
372 nm->nm_nlh->nlmsg_len = len;
373
Patrick McHardy936c9842007-12-13 12:09:45 +0100374 NL_DBG(2, "msg %p: Allocated new message, nlmsg_len=%zu\n", nm, len);
Thomas Graf44d36242007-09-15 01:28:01 +0200375
376 return nm;
377errout:
378 free(nm);
379 nl_errno(ENOMEM);
380 return NULL;
381}
382
383/**
384 * Allocate a new netlink message
385 *
386 * Allocates a new netlink message without any further payload.
387 *
388 * @return Newly allocated netlink message or NULL.
389 */
390struct nl_msg *nlmsg_alloc(void)
391{
392 return __nlmsg_alloc(nlmsg_total_size(0));
393}
394
395/**
396 * Allocate a new netlink message and inherit netlink message header
397 * @arg hdr Netlink message header template
398 *
399 * Allocates a new netlink message with a tailroom for the netlink
400 * message header. If \a hdr is not NULL it will be used as a
401 * template for the netlink message header, otherwise the header
402 * is left blank.
403 *
404 * @return Newly allocated netlink message or NULL
405 */
406struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
407{
408 struct nl_msg *nm;
409
410 nm = nlmsg_alloc();
411 if (nm && hdr) {
412 struct nlmsghdr *new = nm->nm_nlh;
413
414 new->nlmsg_type = hdr->nlmsg_type;
415 new->nlmsg_flags = hdr->nlmsg_flags;
416 new->nlmsg_seq = hdr->nlmsg_seq;
417 new->nlmsg_pid = hdr->nlmsg_pid;
418 }
419
420 return nm;
421}
422
423/**
424 * Allocate a new netlink message
425 * @arg nlmsgtype Netlink message type
426 * @arg flags Message flags.
427 *
428 * @return Newly allocated netlink message or NULL.
429 */
430struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
431{
432 struct nl_msg *msg;
433 struct nlmsghdr nlh = {
434 .nlmsg_type = nlmsgtype,
435 .nlmsg_flags = flags,
436 };
437
438 msg = nlmsg_inherit(&nlh);
439 if (msg)
440 NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
441
442 return msg;
443}
444
445/**
446 * Convert a netlink message received from a netlink socket to a nl_msg
447 * @arg hdr Netlink message received from netlink socket.
448 *
449 * Allocates a new netlink message and copies all of the data pointed to
450 * by \a hdr into the new message object.
451 *
452 * @return Newly allocated netlink message or NULL.
453 */
454struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
455{
456 struct nl_msg *nm;
457
458 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
459 if (!nm)
460 goto errout;
461
462 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
463
464 return nm;
465errout:
466 nlmsg_free(nm);
467 return NULL;
468}
469
470/**
471 * Reserve room for additional data in a netlink message
472 * @arg n netlink message
473 * @arg len length of additional data to reserve room for
474 * @arg pad number of bytes to align data to
475 *
476 * Reserves room for additional data at the tail of the an
477 * existing netlink message. Eventual padding required will
478 * be zeroed out.
479 *
480 * @note All existing pointers into the old data section may have
481 * become obsolete and illegal to reference after this call.
482 *
483 * @return Pointer to start of additional data tailroom or NULL.
484 */
485void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
486{
487 void *tmp;
488 size_t tlen;
489
490 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
491
492 tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + tlen);
493 if (!tmp) {
494 nl_errno(ENOMEM);
495 return NULL;
496 }
497
498 n->nm_nlh = tmp;
499 tmp += n->nm_nlh->nlmsg_len;
500 n->nm_nlh->nlmsg_len += tlen;
501
502 if (tlen > len)
503 memset(tmp + len, 0, tlen - len);
504
Patrick McHardy936c9842007-12-13 12:09:45 +0100505 NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
Thomas Graf44d36242007-09-15 01:28:01 +0200506 n, len, pad, n->nm_nlh->nlmsg_len);
507
508 return tmp;
509}
510
511/**
512 * Append data to tail of a netlink message
513 * @arg n netlink message
514 * @arg data data to add
515 * @arg len length of data
516 * @arg pad Number of bytes to align data to.
517 *
518 * Extends the netlink message as needed and appends the data of given
519 * length to the message.
520 *
521 * @note All existing pointers into the old data section may have
522 * become obsolete and illegal to reference after this call.
523 *
524 * @return 0 on success or a negative error code
525 */
526int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
527{
528 void *tmp;
529
530 tmp = nlmsg_reserve(n, len, pad);
531 if (tmp == NULL)
532 return nl_errno(ENOMEM);
533
534 memcpy(tmp, data, len);
Patrick McHardy936c9842007-12-13 12:09:45 +0100535 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
Thomas Graf44d36242007-09-15 01:28:01 +0200536
537 return 0;
538}
539
540/**
541 * Add a netlink message header to a netlink message
542 * @arg n netlink message
543 * @arg pid netlink process id or NL_AUTO_PID
544 * @arg seq sequence number of message or NL_AUTO_SEQ
545 * @arg type message type
546 * @arg payload length of message payload
547 * @arg flags message flags
548 *
549 * Adds or overwrites the netlink message header in an existing message
550 * object. If \a payload is greater-than zero additional room will be
551 * reserved, f.e. for family specific headers. It can be accesed via
552 * nlmsg_data().
553 *
554 * @return A pointer to the netlink message header or NULL.
555 */
556struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
557 int type, int payload, int flags)
558{
559 struct nlmsghdr *nlh;
560
561 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
562 BUG();
563
564 nlh = (struct nlmsghdr *) n->nm_nlh;
565 nlh->nlmsg_type = type;
566 nlh->nlmsg_flags = flags;
567 nlh->nlmsg_pid = pid;
568 nlh->nlmsg_seq = seq;
569
570 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
571 "seq=%d\n", n, type, flags, pid, seq);
572
573 if (payload > 0 &&
574 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
575 return NULL;
576
577 return nlh;
578}
579
580/**
581 * Return actual netlink message
582 * @arg n netlink message
583 *
584 * Returns the actual netlink message casted to the type of the netlink
585 * message header.
586 *
587 * @return A pointer to the netlink message.
588 */
589struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
590{
591 return n->nm_nlh;
592}
593
594/**
595 * Free a netlink message
596 * @arg n netlink message
597 *
598 * Destroys a netlink message and frees up all used memory.
599 *
600 * @pre The message must be unused.
601 */
602void nlmsg_free(struct nl_msg *n)
603{
604 if (!n)
605 return;
606
607 free(n->nm_nlh);
608 free(n);
609 NL_DBG(2, "msg %p: Freed\n", n);
610}
611
612/** @} */
613
614/**
615 * @name Attributes
616 * @{
617 */
618
619void nlmsg_set_proto(struct nl_msg *msg, int protocol)
620{
621 msg->nm_protocol = protocol;
622}
623
624int nlmsg_get_proto(struct nl_msg *msg)
625{
626 return msg->nm_protocol;
627}
628
629void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
630{
631 memcpy(&msg->nm_src, addr, sizeof(*addr));
632}
633
634struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
635{
636 return &msg->nm_src;
637}
638
639void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
640{
641 memcpy(&msg->nm_dst, addr, sizeof(*addr));
642}
643
644struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
645{
646 return &msg->nm_dst;
647}
648
649void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
650{
651 memcpy(&msg->nm_creds, creds, sizeof(*creds));
652 msg->nm_flags |= NL_MSG_CRED_PRESENT;
653}
654
655struct ucred *nlmsg_get_creds(struct nl_msg *msg)
656{
657 if (msg->nm_flags & NL_MSG_CRED_PRESENT)
658 return &msg->nm_creds;
659 return NULL;
660}
661
662/** @} */
663
664/**
665 * @name Netlink Message Type Translations
666 * @{
667 */
668
669static struct trans_tbl nl_msgtypes[] = {
670 __ADD(NLMSG_NOOP,NOOP)
671 __ADD(NLMSG_ERROR,ERROR)
672 __ADD(NLMSG_DONE,DONE)
673 __ADD(NLMSG_OVERRUN,OVERRUN)
674};
675
676char *nl_nlmsgtype2str(int type, char *buf, size_t size)
677{
678 return __type2str(type, buf, size, nl_msgtypes,
679 ARRAY_SIZE(nl_msgtypes));
680}
681
682int nl_str2nlmsgtype(const char *name)
683{
684 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
685}
686
687/** @} */
688
689/**
690 * @name Netlink Message Flags Translations
691 * @{
692 */
693
694char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
695{
696 memset(buf, 0, len);
697
698#define PRINT_FLAG(f) \
699 if (flags & NLM_F_##f) { \
700 flags &= ~NLM_F_##f; \
701 strncat(buf, #f, len - strlen(buf) - 1); \
702 if (flags) \
703 strncat(buf, ",", len - strlen(buf) - 1); \
704 }
705
706 PRINT_FLAG(REQUEST);
707 PRINT_FLAG(MULTI);
708 PRINT_FLAG(ACK);
709 PRINT_FLAG(ECHO);
710 PRINT_FLAG(ROOT);
711 PRINT_FLAG(MATCH);
712 PRINT_FLAG(ATOMIC);
713 PRINT_FLAG(REPLACE);
714 PRINT_FLAG(EXCL);
715 PRINT_FLAG(CREATE);
716 PRINT_FLAG(APPEND);
717
718 if (flags) {
719 char s[32];
720 snprintf(s, sizeof(s), "0x%x", flags);
721 strncat(buf, s, len - strlen(buf) - 1);
722 }
723#undef PRINT_FLAG
724
725 return buf;
726}
727
728/** @} */
729
730/**
731 * @name Direct Parsing
732 * @{
733 */
734
735/** @cond SKIP */
736struct dp_xdata {
737 void (*cb)(struct nl_object *, void *);
738 void *arg;
739};
740/** @endcond */
741
742static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
743{
744 struct dp_xdata *x = p->pp_arg;
745
746 x->cb(obj, x->arg);
Thomas Graf44d36242007-09-15 01:28:01 +0200747 return 0;
748}
749
750int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
751 void *arg)
752{
753 struct nl_cache_ops *ops;
754 struct nl_parser_param p = {
755 .pp_cb = parse_cb
756 };
757 struct dp_xdata x = {
758 .cb = cb,
759 .arg = arg,
760 };
761
Thomas Grafd36d3962007-10-11 23:09:49 +0200762 ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
763 nlmsg_hdr(msg)->nlmsg_type);
Thomas Graf44d36242007-09-15 01:28:01 +0200764 if (ops == NULL)
765 return nl_error(ENOENT, "Unknown message type %d",
766 nlmsg_hdr(msg)->nlmsg_type);
767 p.pp_arg = &x;
768
769 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
770}
771
772/** @} */
773
774/**
775 * @name Dumping
776 * @{
777 */
778
779static void prefix_line(FILE *ofd, int prefix)
780{
781 int i;
782
783 for (i = 0; i < prefix; i++)
784 fprintf(ofd, " ");
785}
786
787static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
788{
789 int i, a, c, limit;
790 char ascii[21] = {0};
791
792 limit = 18 - (prefix * 2);
793 prefix_line(ofd, prefix);
794 fprintf(ofd, " ");
795
796 for (i = 0, a = 0, c = 0; i < len; i++) {
797 int v = *(uint8_t *) (start + i);
798
799 fprintf(ofd, "%02x ", v);
800 ascii[a++] = isprint(v) ? v : '.';
801
802 if (c == limit-1) {
803 fprintf(ofd, "%s\n", ascii);
804 if (i < (len - 1)) {
805 prefix_line(ofd, prefix);
806 fprintf(ofd, " ");
807 }
808 a = c = 0;
809 memset(ascii, 0, sizeof(ascii));
810 } else
811 c++;
812 }
813
814 if (c != 0) {
815 for (i = 0; i < (limit - c); i++)
816 fprintf(ofd, " ");
817 fprintf(ofd, "%s\n", ascii);
818 }
819}
820
821static void print_hdr(FILE *ofd, struct nl_msg *msg)
822{
823 struct nlmsghdr *nlh = nlmsg_hdr(msg);
824 struct nl_cache_ops *ops;
Thomas Grafd36d3962007-10-11 23:09:49 +0200825 struct nl_msgtype *mt;
Thomas Graf44d36242007-09-15 01:28:01 +0200826 char buf[128];
827
828 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len);
829
Thomas Grafd36d3962007-10-11 23:09:49 +0200830 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
831 if (ops) {
832 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type);
833 if (!mt)
834 BUG();
Thomas Graf44d36242007-09-15 01:28:01 +0200835
Thomas Grafd36d3962007-10-11 23:09:49 +0200836 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name);
837 } else
838 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
839
840 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf);
Thomas Graf44d36242007-09-15 01:28:01 +0200841 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
842 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
843 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq);
844 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid);
845
846}
847
848static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
849 int prefix)
850{
851 int rem;
852 struct nlattr *nla;
853
854 nla_for_each_attr(nla, attrs, attrlen, rem) {
855 int padlen, alen = nla_len(nla);
856
857 prefix_line(ofd, prefix);
858 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla),
859 nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
860 alen);
861
862 if (nla->nla_type & NLA_F_NESTED)
863 dump_attrs(ofd, nla_data(nla), alen, prefix+1);
864 else
865 dump_hex(ofd, nla_data(nla), alen, prefix);
866
867 padlen = nla_padlen(alen);
868 if (padlen > 0) {
869 prefix_line(ofd, prefix);
870 fprintf(ofd, " [PADDING] %d octets\n",
871 padlen);
872 dump_hex(ofd, nla_data(nla) + alen,
873 padlen, prefix);
874 }
875 }
876
877 if (rem) {
878 prefix_line(ofd, prefix);
879 fprintf(ofd, " [LEFTOVER] %d octets\n", rem);
880 }
881}
882
883/**
884 * Dump message in human readable format to file descriptor
885 * @arg msg Message to print
886 * @arg ofd File descriptor.
887 */
888void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
889{
890 struct nlmsghdr *hdr = nlmsg_hdr(msg);
891
892 fprintf(ofd,
893 "-------------------------- BEGIN NETLINK MESSAGE "
894 "---------------------------\n");
895
896 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
897 print_hdr(ofd, msg);
898
899 if (hdr->nlmsg_type == NLMSG_ERROR &&
900 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
901 struct nl_msg *errmsg;
902 struct nlmsgerr *err = nlmsg_data(hdr);
903
904 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err));
905 fprintf(ofd, " .error = %d \"%s\"\n", err->error,
906 strerror(-err->error));
907 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
908
909 errmsg = nlmsg_inherit(&err->msg);
910 print_hdr(ofd, errmsg);
911 nlmsg_free(errmsg);
912 } else if (nlmsg_len(hdr) > 0) {
913 struct nl_cache_ops *ops;
914 int payloadlen = nlmsg_len(hdr);
915 int attrlen = 0;
916
Thomas Grafd36d3962007-10-11 23:09:49 +0200917 ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
918 hdr->nlmsg_type);
Thomas Graf44d36242007-09-15 01:28:01 +0200919 if (ops) {
920 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
921 payloadlen -= attrlen;
922 }
923
924 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen);
925 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
926
927 if (attrlen) {
928 struct nlattr *attrs;
929 int attrlen;
930
931 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
932 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
933 dump_attrs(ofd, attrs, attrlen, 0);
934 }
935 }
936
937 fprintf(ofd,
938 "--------------------------- END NETLINK MESSAGE "
939 "---------------------------\n");
940}
941
942/** @} */
943
944/** @} */