2 * lib/msg.c Netlink Messages Interface
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
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
14 * @defgroup msg Messages
15 * Netlink Message Construction/Parsing Interface
17 * The following information is partly extracted from RFC3549
18 * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt)
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.
30 * The Netlink message header (\link nlmsghdr struct nlmsghdr\endlink) is shown below.
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | Process ID (PID) |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * The netlink message header and payload must be aligned properly:
48 * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
49 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
50 * | Header | Pad | Payload | Pad |
51 * | struct nlmsghdr | | | |
52 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
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)-----------------------+
66 * The payload may consist of arbitary data but may have strict
67 * alignment and formatting rules depening on the specific netlink
71 * <---------------------- nlmsg_len(nlh) --------------------->
72 * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) ->
73 * +----------------------+- - -+--------------------------------+
74 * | Family Header | Pad | Attributes |
75 * +----------------------+- - -+--------------------------------+
76 * nlmsg_attrdata(nlh, hdrlen)---^
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.
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92 * | OLD Netlink message header |
93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96 * @par 1) Creating a new netlink message
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,
104 * struct nl_msg *msg = nlmsg_build(&hdr);
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);
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();
114 * // The header can later be retrieved with nlmsg_hdr() and changed again:
115 * nlmsg_hdr(msg)->nlmsg_flags |= YET_ANOTHER_FLAG;
118 * @par 2) Appending data to the message
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);
126 * @par 3) Cleaning up message construction
128 * // After successful use of the message, the memory must be freed
129 * // using nlmsg_free()
133 * @par Example 2 (Parsing messages):
136 * unsigned char *buf;
137 * struct nlmsghdr *hdr;
139 * n = nl_recv(handle, NULL, &buf);
141 * hdr = (struct nlmsghdr *) buf;
142 * while (nlmsg_ok(hdr, n)) {
143 * // Process message here...
144 * hdr = nlmsg_next(hdr, &n);
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>
158 * @name Size Calculations
163 * length of netlink message not including padding
164 * @arg payload length of message payload
166 int nlmsg_msg_size(int payload)
168 return NLMSG_HDRLEN + payload;
172 * length of netlink message including padding
173 * @arg payload length of message payload
175 int nlmsg_total_size(int payload)
177 return NLMSG_ALIGN(nlmsg_msg_size(payload));
181 * length of padding at the message's tail
182 * @arg payload length of message payload
184 int nlmsg_padlen(int payload)
186 return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
192 * @name Payload Access
197 * head of message payload
198 * @arg nlh netlink messsage header
200 void *nlmsg_data(const struct nlmsghdr *nlh)
202 return (unsigned char *) nlh + NLMSG_HDRLEN;
205 void *nlmsg_tail(const struct nlmsghdr *nlh)
207 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
211 * length of message payload
212 * @arg nlh netlink message header
214 int nlmsg_len(const struct nlmsghdr *nlh)
216 return nlh->nlmsg_len - NLMSG_HDRLEN;
222 * @name Attribute Access
227 * head of attributes data
228 * @arg nlh netlink message header
229 * @arg hdrlen length of family specific header
231 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
233 unsigned char *data = nlmsg_data(nlh);
234 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
238 * length of attributes data
239 * @arg nlh netlink message header
240 * @arg hdrlen length of family specific header
242 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
244 return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
250 * @name Message Parsing
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
259 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
261 return (remaining >= sizeof(struct nlmsghdr) &&
262 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
263 nlh->nlmsg_len <= remaining);
267 * next netlink message in message stream
268 * @arg nlh netlink message header
269 * @arg remaining number of bytes remaining in message stream
271 * @returns the next netlink message in the message stream and
272 * decrements remaining by the size of the current message.
274 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
276 int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
278 *remaining -= totlen;
280 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
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
293 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
294 int maxtype, struct nla_policy *policy)
296 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
297 return nl_errno(EINVAL);
299 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
300 nlmsg_attrlen(nlh, hdrlen), policy);
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
309 * Returns the first attribute which matches the specified type.
311 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
313 return nla_find(nlmsg_attrdata(nlh, hdrlen),
314 nlmsg_attrlen(nlh, hdrlen), attrtype);
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
324 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
325 struct nla_policy *policy)
327 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
328 return nl_errno(EINVAL);
330 return nla_validate(nlmsg_attrdata(nlh, hdrlen),
331 nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
337 * @name Message Building/Access
341 struct nl_msg *nlmsg_new(void)
345 nm = calloc(1, sizeof(*nm));
349 nm->nm_nlh = calloc(1, nlmsg_msg_size(0));
353 nm->nm_nlh->nlmsg_len = nlmsg_msg_size(0);
363 * Build a new netlink message
364 * @arg hdr Netlink message header template
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
371 * @return Newly allocated netlink message or NULL
373 struct nl_msg *nlmsg_build(struct nlmsghdr *hdr)
379 int size = nm->nm_nlh->nlmsg_len;
380 memcpy(nm->nm_nlh, hdr, sizeof(*hdr));
381 nm->nm_nlh->nlmsg_len = size;
387 struct nl_msg *nlmsg_build_simple(int nlmsgtype, int flags)
389 struct nlmsghdr nlh = {
390 .nlmsg_type = nlmsgtype,
391 .nlmsg_flags = flags,
394 return nlmsg_build(&nlh);
397 struct nl_msg *nlmsg_build_no_hdr(void)
399 return nlmsg_build(NULL);
402 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
406 nm = calloc(1, sizeof(struct nl_msg));
410 nm->nm_nlh = calloc(1, NLMSG_ALIGN(hdr->nlmsg_len));
414 memcpy(nm->nm_nlh, hdr, NLMSG_ALIGN(hdr->nlmsg_len));
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?
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.
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
441 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
446 len = NLMSG_ALIGN(len);
448 tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + len);
450 return nl_errno(ENOMEM);
453 memcpy((void *) n->nm_nlh + n->nm_nlh->nlmsg_len, data, len);
454 n->nm_nlh->nlmsg_len += len;
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
469 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
470 int type, int payload, int flags)
472 struct nlmsghdr *nlh;
474 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
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;
484 memset((unsigned char *) nlmsg_data(nlh) + payload, 0,
485 nlmsg_padlen(payload));
491 * Return actual netlink message
492 * @arg n netlink message
494 * Returns the actual netlink message casted to the type of the netlink
497 * @return A pointer to the netlink message.
499 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
505 * Free a netlink message
506 * @arg n netlink message
508 * Destroys a netlink message and frees up all used memory.
510 * @pre The message must be unused.
512 void nlmsg_free(struct nl_msg *n)
524 * @name Attribute Modification
528 void nlmsg_set_proto(struct nl_msg *msg, int protocol)
530 msg->nm_protocol = protocol;
533 int nlmsg_get_proto(struct nl_msg *msg)
535 return msg->nm_protocol;
538 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
540 memcpy(&msg->nm_src, addr, sizeof(*addr));
543 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
548 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
550 memcpy(&msg->nm_dst, addr, sizeof(*addr));
553 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
558 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
560 memcpy(&msg->nm_creds, creds, sizeof(*creds));
561 msg->nm_flags |= NL_MSG_CRED_PRESENT;
564 struct ucred *nlmsg_get_creds(struct nl_msg *msg)
566 if (msg->nm_flags & NL_MSG_CRED_PRESENT)
567 return &msg->nm_creds;
574 * @name Netlink Message Type Translations
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)
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.
591 * Converts a netlink message type number to a character string and stores
592 * it in the provided buffer.
594 * @return The destination buffer or the type encoded in hexidecimal form
595 * if no match was found.
597 char *nl_nlmsgtype2str(int type, char *buf, size_t size)
599 return __type2str(type, buf, size, nl_msgtypes,
600 ARRAY_SIZE(nl_msgtypes));
604 * Convert character string to netlink message type.
605 * @arg name Name of netlink message type.
607 * Converts the provided character string specifying a netlink message type
608 * into the corresponding numeric value
610 * @return Numeric netlink message type or a negative value
611 * if no match was found.
613 int nl_str2nlmsgtype(const char *name)
615 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
621 * @name Netlink Message Flags Translations
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
631 * Translates netlink message flags into a character string and stores
632 * it in the provided buffer.
634 * @return The destination buffer
636 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
640 #define PRINT_FLAG(f) \
641 if (flags & NLM_F_##f) { \
642 flags &= ~NLM_F_##f; \
643 strncat(buf, #f, len - strlen(buf) - 1); \
645 strncat(buf, ",", len - strlen(buf) - 1); \
662 snprintf(s, sizeof(s), "0x%x", flags);
663 strncat(buf, s, len - strlen(buf) - 1);
673 * @name Direct Parsing
679 void (*cb)(struct nl_object *, void *);
684 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
686 struct dp_xdata *x = p->pp_arg;
693 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
696 struct nl_cache_ops *ops;
697 struct nl_parser_param p = {
700 struct dp_xdata x = {
705 ops = nl_cache_mngt_associate(nlmsg_get_proto(msg),
706 nlmsg_hdr(msg)->nlmsg_type);
708 return nl_error(ENOENT, "Unknown message type %d",
709 nlmsg_hdr(msg)->nlmsg_type);
712 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);