Home | History | Annotate | Download | only in lib
      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 (at) 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 <linux/socket.h>
    167 
    168 static size_t default_msg_size;
    169 
    170 static void __init init_msg_size(void)
    171 {
    172 	default_msg_size = getpagesize();
    173 }
    174 
    175 /**
    176  * @name Size Calculations
    177  * @{
    178  */
    179 
    180 /**
    181  * length of netlink message not including padding
    182  * @arg payload		length of message payload
    183  */
    184 int nlmsg_msg_size(int payload)
    185 {
    186 	return NLMSG_HDRLEN + payload;
    187 }
    188 
    189 /**
    190  * length of netlink message including padding
    191  * @arg payload		length of message payload
    192  */
    193 int nlmsg_total_size(int payload)
    194 {
    195 	return NLMSG_ALIGN(nlmsg_msg_size(payload));
    196 }
    197 
    198 /**
    199  * length of padding at the message's tail
    200  * @arg payload		length of message payload
    201  */
    202 int nlmsg_padlen(int payload)
    203 {
    204 	return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
    205 }
    206 
    207 /** @} */
    208 
    209 /**
    210  * @name Payload Access
    211  * @{
    212  */
    213 
    214 /**
    215  * head of message payload
    216  * @arg nlh		netlink messsage header
    217  */
    218 void *nlmsg_data(const struct nlmsghdr *nlh)
    219 {
    220 	return (unsigned char *) nlh + NLMSG_HDRLEN;
    221 }
    222 
    223 void *nlmsg_tail(const struct nlmsghdr *nlh)
    224 {
    225 	return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
    226 }
    227 
    228 /**
    229  * length of message payload
    230  * @arg nlh		netlink message header
    231  */
    232 int nlmsg_len(const struct nlmsghdr *nlh)
    233 {
    234 	return nlh->nlmsg_len - NLMSG_HDRLEN;
    235 }
    236 
    237 /** @} */
    238 
    239 /**
    240  * @name Attribute Access
    241  * @{
    242  */
    243 
    244 /**
    245  * head of attributes data
    246  * @arg nlh		netlink message header
    247  * @arg hdrlen		length of family specific header
    248  */
    249 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
    250 {
    251 	unsigned char *data = nlmsg_data(nlh);
    252 	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
    253 }
    254 
    255 /**
    256  * length of attributes data
    257  * @arg nlh		netlink message header
    258  * @arg hdrlen		length of family specific header
    259  */
    260 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
    261 {
    262 	return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
    263 }
    264 
    265 /** @} */
    266 
    267 /**
    268  * @name Message Parsing
    269  * @{
    270  */
    271 
    272 int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
    273 {
    274 	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
    275 		return 0;
    276 
    277 	return 1;
    278 }
    279 
    280 /**
    281  * check if the netlink message fits into the remaining bytes
    282  * @arg nlh		netlink message header
    283  * @arg remaining	number of bytes remaining in message stream
    284  */
    285 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
    286 {
    287 	return (remaining >= (int)sizeof(struct nlmsghdr) &&
    288 		nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
    289 		nlh->nlmsg_len <= remaining);
    290 }
    291 
    292 /**
    293  * next netlink message in message stream
    294  * @arg nlh		netlink message header
    295  * @arg remaining	number of bytes remaining in message stream
    296  *
    297  * @returns the next netlink message in the message stream and
    298  * decrements remaining by the size of the current message.
    299  */
    300 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
    301 {
    302 	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
    303 
    304 	*remaining -= totlen;
    305 
    306 	return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
    307 }
    308 
    309 /**
    310  * parse attributes of a netlink message
    311  * @arg nlh		netlink message header
    312  * @arg hdrlen		length of family specific header
    313  * @arg tb		destination array with maxtype+1 elements
    314  * @arg maxtype		maximum attribute type to be expected
    315  * @arg policy		validation policy
    316  *
    317  * See nla_parse()
    318  */
    319 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
    320 		int maxtype, struct nla_policy *policy)
    321 {
    322 	if (!nlmsg_valid_hdr(nlh, hdrlen))
    323 		return -NLE_MSG_TOOSHORT;
    324 
    325 	return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
    326 			 nlmsg_attrlen(nlh, hdrlen), policy);
    327 }
    328 
    329 /**
    330  * nlmsg_find_attr - find a specific attribute in a netlink message
    331  * @arg nlh		netlink message header
    332  * @arg hdrlen		length of familiy specific header
    333  * @arg attrtype	type of attribute to look for
    334  *
    335  * Returns the first attribute which matches the specified type.
    336  */
    337 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
    338 {
    339 	return nla_find(nlmsg_attrdata(nlh, hdrlen),
    340 			nlmsg_attrlen(nlh, hdrlen), attrtype);
    341 }
    342 
    343 /**
    344  * nlmsg_validate - validate a netlink message including attributes
    345  * @arg nlh		netlinket message header
    346  * @arg hdrlen		length of familiy specific header
    347  * @arg maxtype		maximum attribute type to be expected
    348  * @arg policy		validation policy
    349  */
    350 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
    351 		   struct nla_policy *policy)
    352 {
    353 	if (!nlmsg_valid_hdr(nlh, hdrlen))
    354 		return -NLE_MSG_TOOSHORT;
    355 
    356 	return nla_validate(nlmsg_attrdata(nlh, hdrlen),
    357 			    nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
    358 }
    359 
    360 /** @} */
    361 
    362 /**
    363  * @name Message Building/Access
    364  * @{
    365  */
    366 
    367 static struct nl_msg *__nlmsg_alloc(size_t len)
    368 {
    369 	struct nl_msg *nm;
    370 
    371 	nm = calloc(1, sizeof(*nm));
    372 	if (!nm)
    373 		goto errout;
    374 
    375 	nm->nm_refcnt = 1;
    376 
    377 	nm->nm_nlh = malloc(len);
    378 	if (!nm->nm_nlh)
    379 		goto errout;
    380 
    381 	memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
    382 
    383 	nm->nm_protocol = -1;
    384 	nm->nm_size = len;
    385 	nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
    386 
    387 	NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
    388 
    389 	return nm;
    390 errout:
    391 	free(nm);
    392 	return NULL;
    393 }
    394 
    395 /**
    396  * Allocate a new netlink message with the default maximum payload size.
    397  *
    398  * Allocates a new netlink message without any further payload. The
    399  * maximum payload size defaults to PAGESIZE or as otherwise specified
    400  * with nlmsg_set_default_size().
    401  *
    402  * @return Newly allocated netlink message or NULL.
    403  */
    404 struct nl_msg *nlmsg_alloc(void)
    405 {
    406 	return __nlmsg_alloc(default_msg_size);
    407 }
    408 
    409 /**
    410  * Allocate a new netlink message with maximum payload size specified.
    411  */
    412 struct nl_msg *nlmsg_alloc_size(size_t max)
    413 {
    414 	return __nlmsg_alloc(max);
    415 }
    416 
    417 /**
    418  * Allocate a new netlink message and inherit netlink message header
    419  * @arg hdr		Netlink message header template
    420  *
    421  * Allocates a new netlink message and inherits the original message
    422  * header. If \a hdr is not NULL it will be used as a template for
    423  * the netlink message header, otherwise the header is left blank.
    424  *
    425  * @return Newly allocated netlink message or NULL
    426  */
    427 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
    428 {
    429 	struct nl_msg *nm;
    430 
    431 	nm = nlmsg_alloc();
    432 	if (nm && hdr) {
    433 		struct nlmsghdr *new = nm->nm_nlh;
    434 
    435 		new->nlmsg_type = hdr->nlmsg_type;
    436 		new->nlmsg_flags = hdr->nlmsg_flags;
    437 		new->nlmsg_seq = hdr->nlmsg_seq;
    438 		new->nlmsg_pid = hdr->nlmsg_pid;
    439 	}
    440 
    441 	return nm;
    442 }
    443 
    444 /**
    445  * Allocate a new netlink message
    446  * @arg nlmsgtype	Netlink message type
    447  * @arg flags		Message flags.
    448  *
    449  * @return Newly allocated netlink message or NULL.
    450  */
    451 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
    452 {
    453 	struct nl_msg *msg;
    454 	struct nlmsghdr nlh = {
    455 		.nlmsg_type = nlmsgtype,
    456 		.nlmsg_flags = flags,
    457 	};
    458 
    459 	msg = nlmsg_inherit(&nlh);
    460 	if (msg)
    461 		NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
    462 
    463 	return msg;
    464 }
    465 
    466 /**
    467  * Set the default maximum message payload size for allocated messages
    468  * @arg max		Size of payload in bytes.
    469  */
    470 void nlmsg_set_default_size(size_t max)
    471 {
    472 	if (max < nlmsg_total_size(0))
    473 		max = nlmsg_total_size(0);
    474 
    475 	default_msg_size = max;
    476 }
    477 
    478 /**
    479  * Convert a netlink message received from a netlink socket to a nl_msg
    480  * @arg hdr		Netlink message received from netlink socket.
    481  *
    482  * Allocates a new netlink message and copies all of the data pointed to
    483  * by \a hdr into the new message object.
    484  *
    485  * @return Newly allocated netlink message or NULL.
    486  */
    487 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
    488 {
    489 	struct nl_msg *nm;
    490 
    491 	nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
    492 	if (!nm)
    493 		goto errout;
    494 
    495 	memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
    496 
    497 	return nm;
    498 errout:
    499 	nlmsg_free(nm);
    500 	return NULL;
    501 }
    502 
    503 /**
    504  * Reserve room for additional data in a netlink message
    505  * @arg n		netlink message
    506  * @arg len		length of additional data to reserve room for
    507  * @arg pad		number of bytes to align data to
    508  *
    509  * Reserves room for additional data at the tail of the an
    510  * existing netlink message. Eventual padding required will
    511  * be zeroed out.
    512  *
    513  * @return Pointer to start of additional data tailroom or NULL.
    514  */
    515 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
    516 {
    517 	void *buf = n->nm_nlh;
    518 	size_t nlmsg_len = n->nm_nlh->nlmsg_len;
    519 	size_t tlen;
    520 
    521 	tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
    522 
    523 	if ((tlen + nlmsg_len) > n->nm_size)
    524 		return NULL;
    525 
    526 	buf += nlmsg_len;
    527 	n->nm_nlh->nlmsg_len += tlen;
    528 
    529 	if (tlen > len)
    530 		memset(buf + len, 0, tlen - len);
    531 
    532 	NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
    533 		  n, len, pad, n->nm_nlh->nlmsg_len);
    534 
    535 	return buf;
    536 }
    537 
    538 /**
    539  * Append data to tail of a netlink message
    540  * @arg n		netlink message
    541  * @arg data		data to add
    542  * @arg len		length of data
    543  * @arg pad		Number of bytes to align data to.
    544  *
    545  * Extends the netlink message as needed and appends the data of given
    546  * length to the message.
    547  *
    548  * @return 0 on success or a negative error code
    549  */
    550 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
    551 {
    552 	void *tmp;
    553 
    554 	tmp = nlmsg_reserve(n, len, pad);
    555 	if (tmp == NULL)
    556 		return -NLE_NOMEM;
    557 
    558 	memcpy(tmp, data, len);
    559 	NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
    560 
    561 	return 0;
    562 }
    563 
    564 /**
    565  * Expand maximum payload size of a netlink message
    566  * @arg n		Netlink message.
    567  * @arg newlen		New maximum payload size.
    568  *
    569  * Reallocates the payload section of a netlink message and increases
    570  * the maximum payload size of the message.
    571  *
    572  * @note Any pointers pointing to old payload block will be stale and
    573  *       need to be refetched. Therfore, do not expand while constructing
    574  *       nested attributes or while reserved data blocks are held.
    575  *
    576  * @return 0 on success or a negative error code.
    577  */
    578 int nlmsg_expand(struct nl_msg *n, size_t newlen)
    579 {
    580 	void *tmp;
    581 
    582 	if (newlen <= n->nm_size)
    583 		return -NLE_INVAL;
    584 
    585 	tmp = realloc(n->nm_nlh, newlen);
    586 	if (tmp == NULL)
    587 		return -NLE_NOMEM;
    588 
    589 	n->nm_nlh = tmp;
    590 	n->nm_size = newlen;
    591 
    592 	return 0;
    593 }
    594 
    595 /**
    596  * Add a netlink message header to a netlink message
    597  * @arg n		netlink message
    598  * @arg pid		netlink process id or NL_AUTO_PID
    599  * @arg seq		sequence number of message or NL_AUTO_SEQ
    600  * @arg type		message type
    601  * @arg payload		length of message payload
    602  * @arg flags		message flags
    603  *
    604  * Adds or overwrites the netlink message header in an existing message
    605  * object. If \a payload is greater-than zero additional room will be
    606  * reserved, f.e. for family specific headers. It can be accesed via
    607  * nlmsg_data().
    608  *
    609  * @return A pointer to the netlink message header or NULL.
    610  */
    611 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
    612 			   int type, int payload, int flags)
    613 {
    614 	struct nlmsghdr *nlh;
    615 
    616 	if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
    617 		BUG();
    618 
    619 	nlh = (struct nlmsghdr *) n->nm_nlh;
    620 	nlh->nlmsg_type = type;
    621 	nlh->nlmsg_flags = flags;
    622 	nlh->nlmsg_pid = pid;
    623 	nlh->nlmsg_seq = seq;
    624 
    625 	NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
    626 		  "seq=%d\n", n, type, flags, pid, seq);
    627 
    628 	if (payload > 0 &&
    629 	    nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
    630 		return NULL;
    631 
    632 	return nlh;
    633 }
    634 
    635 /**
    636  * Return actual netlink message
    637  * @arg n		netlink message
    638  *
    639  * Returns the actual netlink message casted to the type of the netlink
    640  * message header.
    641  *
    642  * @return A pointer to the netlink message.
    643  */
    644 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
    645 {
    646 	return n->nm_nlh;
    647 }
    648 
    649 /**
    650  * Acquire a reference on a netlink message
    651  * @arg msg		message to acquire reference from
    652  */
    653 void nlmsg_get(struct nl_msg *msg)
    654 {
    655 	msg->nm_refcnt++;
    656 	NL_DBG(4, "New reference to message %p, total %d\n",
    657 	       msg, msg->nm_refcnt);
    658 }
    659 
    660 /**
    661  * Release a reference from an netlink message
    662  * @arg msg		message to release reference from
    663  *
    664  * Frees memory after the last reference has been released.
    665  */
    666 void nlmsg_free(struct nl_msg *msg)
    667 {
    668 	if (!msg)
    669 		return;
    670 
    671 	msg->nm_refcnt--;
    672 	NL_DBG(4, "Returned message reference %p, %d remaining\n",
    673 	       msg, msg->nm_refcnt);
    674 
    675 	if (msg->nm_refcnt < 0)
    676 		BUG();
    677 
    678 	if (msg->nm_refcnt <= 0) {
    679 		free(msg->nm_nlh);
    680 		free(msg);
    681 		NL_DBG(2, "msg %p: Freed\n", msg);
    682 	}
    683 }
    684 
    685 /** @} */
    686 
    687 /**
    688  * @name Attributes
    689  * @{
    690  */
    691 
    692 void nlmsg_set_proto(struct nl_msg *msg, int protocol)
    693 {
    694 	msg->nm_protocol = protocol;
    695 }
    696 
    697 int nlmsg_get_proto(struct nl_msg *msg)
    698 {
    699 	return msg->nm_protocol;
    700 }
    701 
    702 size_t nlmsg_get_max_size(struct nl_msg *msg)
    703 {
    704 	return msg->nm_size;
    705 }
    706 
    707 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
    708 {
    709 	memcpy(&msg->nm_src, addr, sizeof(*addr));
    710 }
    711 
    712 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
    713 {
    714 	return &msg->nm_src;
    715 }
    716 
    717 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
    718 {
    719 	memcpy(&msg->nm_dst, addr, sizeof(*addr));
    720 }
    721 
    722 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
    723 {
    724 	return &msg->nm_dst;
    725 }
    726 
    727 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
    728 {
    729 	memcpy(&msg->nm_creds, creds, sizeof(*creds));
    730 	msg->nm_flags |= NL_MSG_CRED_PRESENT;
    731 }
    732 
    733 struct ucred *nlmsg_get_creds(struct nl_msg *msg)
    734 {
    735 	if (msg->nm_flags & NL_MSG_CRED_PRESENT)
    736 		return &msg->nm_creds;
    737 	return NULL;
    738 }
    739 
    740 /** @} */
    741 
    742 /**
    743  * @name Netlink Message Type Translations
    744  * @{
    745  */
    746 
    747 static struct trans_tbl nl_msgtypes[] = {
    748 	__ADD(NLMSG_NOOP,NOOP)
    749 	__ADD(NLMSG_ERROR,ERROR)
    750 	__ADD(NLMSG_DONE,DONE)
    751 	__ADD(NLMSG_OVERRUN,OVERRUN)
    752 };
    753 
    754 char *nl_nlmsgtype2str(int type, char *buf, size_t size)
    755 {
    756 	return __type2str(type, buf, size, nl_msgtypes,
    757 			  ARRAY_SIZE(nl_msgtypes));
    758 }
    759 
    760 int nl_str2nlmsgtype(const char *name)
    761 {
    762 	return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
    763 }
    764 
    765 /** @} */
    766 
    767 /**
    768  * @name Netlink Message Flags Translations
    769  * @{
    770  */
    771 
    772 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
    773 {
    774 	memset(buf, 0, len);
    775 
    776 #define PRINT_FLAG(f) \
    777 	if (flags & NLM_F_##f) { \
    778 		flags &= ~NLM_F_##f; \
    779 		strncat(buf, #f, len - strlen(buf) - 1); \
    780 		if (flags) \
    781 			strncat(buf, ",", len - strlen(buf) - 1); \
    782 	}
    783 
    784 	PRINT_FLAG(REQUEST);
    785 	PRINT_FLAG(MULTI);
    786 	PRINT_FLAG(ACK);
    787 	PRINT_FLAG(ECHO);
    788 	PRINT_FLAG(ROOT);
    789 	PRINT_FLAG(MATCH);
    790 	PRINT_FLAG(ATOMIC);
    791 	PRINT_FLAG(REPLACE);
    792 	PRINT_FLAG(EXCL);
    793 	PRINT_FLAG(CREATE);
    794 	PRINT_FLAG(APPEND);
    795 
    796 	if (flags) {
    797 		char s[32];
    798 		snprintf(s, sizeof(s), "0x%x", flags);
    799 		strncat(buf, s, len - strlen(buf) - 1);
    800 	}
    801 #undef PRINT_FLAG
    802 
    803 	return buf;
    804 }
    805 
    806 /** @} */
    807 
    808 /**
    809  * @name Direct Parsing
    810  * @{
    811  */
    812 
    813 /** @cond SKIP */
    814 struct dp_xdata {
    815 	void (*cb)(struct nl_object *, void *);
    816 	void *arg;
    817 };
    818 /** @endcond */
    819 
    820 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
    821 {
    822 	struct dp_xdata *x = p->pp_arg;
    823 
    824 	x->cb(obj, x->arg);
    825 	return 0;
    826 }
    827 
    828 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
    829 		 void *arg)
    830 {
    831 	struct nl_cache_ops *ops;
    832 	struct nl_parser_param p = {
    833 		.pp_cb = parse_cb
    834 	};
    835 	struct dp_xdata x = {
    836 		.cb = cb,
    837 		.arg = arg,
    838 	};
    839 
    840 	ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
    841 				     nlmsg_hdr(msg)->nlmsg_type);
    842 	if (ops == NULL)
    843 		return -NLE_MSGTYPE_NOSUPPORT;
    844 	p.pp_arg = &x;
    845 
    846 	return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
    847 }
    848 
    849 /** @} */
    850 
    851 /**
    852  * @name Dumping
    853  * @{
    854  */
    855 
    856 static void prefix_line(FILE *ofd, int prefix)
    857 {
    858 	int i;
    859 
    860 	for (i = 0; i < prefix; i++)
    861 		fprintf(ofd, "  ");
    862 }
    863 
    864 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
    865 {
    866 	int i, a, c, limit;
    867 	char ascii[21] = {0};
    868 
    869 	limit = 18 - (prefix * 2);
    870 	prefix_line(ofd, prefix);
    871 	fprintf(ofd, "    ");
    872 
    873 	for (i = 0, a = 0, c = 0; i < len; i++) {
    874 		int v = *(uint8_t *) (start + i);
    875 
    876 		fprintf(ofd, "%02x ", v);
    877 		ascii[a++] = isprint(v) ? v : '.';
    878 
    879 		if (c == limit-1) {
    880 			fprintf(ofd, "%s\n", ascii);
    881 			if (i < (len - 1)) {
    882 				prefix_line(ofd, prefix);
    883 				fprintf(ofd, "    ");
    884 			}
    885 			a = c = 0;
    886 			memset(ascii, 0, sizeof(ascii));
    887 		} else
    888 			c++;
    889 	}
    890 
    891 	if (c != 0) {
    892 		for (i = 0; i < (limit - c); i++)
    893 			fprintf(ofd, "   ");
    894 		fprintf(ofd, "%s\n", ascii);
    895 	}
    896 }
    897 
    898 static void print_hdr(FILE *ofd, struct nl_msg *msg)
    899 {
    900 	struct nlmsghdr *nlh = nlmsg_hdr(msg);
    901 	struct nl_cache_ops *ops;
    902 	struct nl_msgtype *mt;
    903 	char buf[128];
    904 
    905 	fprintf(ofd, "    .nlmsg_len = %d\n", nlh->nlmsg_len);
    906 
    907 	ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
    908 	if (ops) {
    909 		mt = nl_msgtype_lookup(ops, nlh->nlmsg_type);
    910 		if (!mt)
    911 			BUG();
    912 
    913 		snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name);
    914 	} else
    915 		nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
    916 
    917 	fprintf(ofd, "    .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf);
    918 	fprintf(ofd, "    .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
    919 		nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
    920 	fprintf(ofd, "    .nlmsg_seq = %d\n", nlh->nlmsg_seq);
    921 	fprintf(ofd, "    .nlmsg_pid = %d\n", nlh->nlmsg_pid);
    922 
    923 }
    924 
    925 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
    926 		       int prefix)
    927 {
    928 	int rem;
    929 	struct nlattr *nla;
    930 
    931 	nla_for_each_attr(nla, attrs, attrlen, rem) {
    932 		int padlen, alen = nla_len(nla);
    933 
    934 		prefix_line(ofd, prefix);
    935 		fprintf(ofd, "  [ATTR %02d%s] %d octets\n", nla_type(nla),
    936 			nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
    937 			alen);
    938 
    939 		if (nla->nla_type & NLA_F_NESTED)
    940 			dump_attrs(ofd, nla_data(nla), alen, prefix+1);
    941 		else
    942 			dump_hex(ofd, nla_data(nla), alen, prefix);
    943 
    944 		padlen = nla_padlen(alen);
    945 		if (padlen > 0) {
    946 			prefix_line(ofd, prefix);
    947 			fprintf(ofd, "  [PADDING] %d octets\n",
    948 				padlen);
    949 			dump_hex(ofd, nla_data(nla) + alen,
    950 				 padlen, prefix);
    951 		}
    952 	}
    953 
    954 	if (rem) {
    955 		prefix_line(ofd, prefix);
    956 		fprintf(ofd, "  [LEFTOVER] %d octets\n", rem);
    957 	}
    958 }
    959 
    960 /**
    961  * Dump message in human readable format to file descriptor
    962  * @arg msg		Message to print
    963  * @arg ofd		File descriptor.
    964  */
    965 void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
    966 {
    967 	struct nlmsghdr *hdr = nlmsg_hdr(msg);
    968 
    969 	fprintf(ofd,
    970 	"--------------------------   BEGIN NETLINK MESSAGE "
    971 	"---------------------------\n");
    972 
    973 	fprintf(ofd, "  [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
    974 	print_hdr(ofd, msg);
    975 
    976 	if (hdr->nlmsg_type == NLMSG_ERROR &&
    977 	    hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
    978 		struct nl_msg *errmsg;
    979 		struct nlmsgerr *err = nlmsg_data(hdr);
    980 
    981 		fprintf(ofd, "  [ERRORMSG] %Zu octets\n", sizeof(*err));
    982 		fprintf(ofd, "    .error = %d \"%s\"\n", err->error,
    983 			strerror(-err->error));
    984 		fprintf(ofd, "  [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
    985 
    986 		errmsg = nlmsg_inherit(&err->msg);
    987 		print_hdr(ofd, errmsg);
    988 		nlmsg_free(errmsg);
    989 	} else if (nlmsg_len(hdr) > 0) {
    990 		struct nl_cache_ops *ops;
    991 		int payloadlen = nlmsg_len(hdr);
    992 		int attrlen = 0;
    993 
    994 		ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
    995 					     hdr->nlmsg_type);
    996 		if (ops) {
    997 			attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
    998 			payloadlen -= attrlen;
    999 		}
   1000 
   1001 		fprintf(ofd, "  [PAYLOAD] %d octets\n", payloadlen);
   1002 		dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
   1003 
   1004 		if (attrlen) {
   1005 			struct nlattr *attrs;
   1006 			int attrlen;
   1007 
   1008 			attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
   1009 			attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
   1010 			dump_attrs(ofd, attrs, attrlen, 0);
   1011 		}
   1012 	}
   1013 
   1014 	fprintf(ofd,
   1015 	"---------------------------  END NETLINK MESSAGE   "
   1016 	"---------------------------\n");
   1017 }
   1018 
   1019 /** @} */
   1020 
   1021 /** @} */
   1022