libnl
3.2.3
|
00001 /* 00002 * lib/msg.c Netlink Messages Interface 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup core 00014 * @defgroup msg Messages 00015 * Netlink Message Construction/Parsing Interface 00016 * 00017 * The following information is partly extracted from RFC3549 00018 * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt) 00019 * 00020 * @par Message Format 00021 * Netlink messages consist of a byte stream with one or multiple 00022 * Netlink headers and an associated payload. If the payload is too big 00023 * to fit into a single message it, can be split over multiple Netlink 00024 * messages, collectively called a multipart message. For multipart 00025 * messages, the first and all following headers have the \c NLM_F_MULTI 00026 * Netlink header flag set, except for the last header which has the 00027 * Netlink header type \c NLMSG_DONE. 00028 * 00029 * @par 00030 * The Netlink message header (struct nlmsghdr) is shown below. 00031 * @code 00032 * 0 1 2 3 00033 * 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 00034 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00035 * | Length | 00036 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00037 * | Type | Flags | 00038 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00039 * | Sequence Number | 00040 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00041 * | Process ID (PID) | 00042 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00043 * @endcode 00044 * 00045 * @par 00046 * The netlink message header and payload must be aligned properly: 00047 * @code 00048 * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) ---> 00049 * +----------------------------+- - -+- - - - - - - - - - -+- - -+ 00050 * | Header | Pad | Payload | Pad | 00051 * | struct nlmsghdr | | | | 00052 * +----------------------------+- - -+- - - - - - - - - - -+- - -+ 00053 * @endcode 00054 * @par 00055 * Message Format: 00056 * @code 00057 * <--- nlmsg_total_size(payload) ---> 00058 * <-- nlmsg_msg_size(payload) -> 00059 * +----------+- - -+-------------+- - -+-------- - - 00060 * | nlmsghdr | Pad | Payload | Pad | nlmsghdr 00061 * +----------+- - -+-------------+- - -+-------- - - 00062 * nlmsg_data(nlh)---^ ^ 00063 * nlmsg_next(nlh)-----------------------+ 00064 * @endcode 00065 * @par 00066 * The payload may consist of arbitary data but may have strict 00067 * alignment and formatting rules depening on the specific netlink 00068 * families. 00069 * @par 00070 * @code 00071 * <---------------------- nlmsg_len(nlh) ---------------------> 00072 * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> 00073 * +----------------------+- - -+--------------------------------+ 00074 * | Family Header | Pad | Attributes | 00075 * +----------------------+- - -+--------------------------------+ 00076 * nlmsg_attrdata(nlh, hdrlen)---^ 00077 * @endcode 00078 * @par The ACK Netlink Message 00079 * This message is actually used to denote both an ACK and a NACK. 00080 * Typically, the direction is from FEC to CPC (in response to an ACK 00081 * request message). However, the CPC should be able to send ACKs back 00082 * to FEC when requested. 00083 * @code 00084 * 0 1 2 3 00085 * 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 00086 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00087 * | Netlink message header | 00088 * | type = NLMSG_ERROR | 00089 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00090 * | Error code | 00091 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00092 * | OLD Netlink message header | 00093 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00094 * @endcode 00095 * 00096 * @par Example 00097 * @code 00098 * // Various methods exist to create/allocate a new netlink 00099 * // message. 00100 * // 00101 * // nlmsg_alloc() will allocate an empty netlink message with 00102 * // a maximum payload size which defaults to the page size of 00103 * // the system. This default size can be modified using the 00104 * // function nlmsg_set_default_size(). 00105 * struct nl_msg *msg = nlmsg_alloc(); 00106 * 00107 * // Very often, the message type and message flags are known 00108 * // at allocation time while the other fields are auto generated: 00109 * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS); 00110 * 00111 * // Alternatively an existing netlink message header can be used 00112 * // to inherit the header values: 00113 * struct nlmsghdr hdr = { 00114 * .nlmsg_type = MY_TYPE, 00115 * .nlmsg_flags = MY_FLAGS, 00116 * }; 00117 * struct nl_msg *msg = nlmsg_inherit(&hdr); 00118 * 00119 * // Last but not least, netlink messages received from netlink sockets 00120 * // can be converted into nl_msg objects using nlmsg_convert(). This 00121 * // will create a message with a maximum payload size which equals the 00122 * // length of the existing netlink message, therefore no more data can 00123 * // be appened without calling nlmsg_expand() first. 00124 * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock); 00125 * 00126 * // Payload may be added to the message via nlmsg_append(). The fourth 00127 * // parameter specifies the number of alignment bytes the data should 00128 * // be padding with at the end. Common values are 0 to disable it or 00129 * // NLMSG_ALIGNTO to ensure proper netlink message padding. 00130 * nlmsg_append(msg, &mydata, sizeof(mydata), 0); 00131 * 00132 * // Sometimes it may be necessary to reserve room for data but defer 00133 * // the actual copying to a later point, nlmsg_reserve() can be used 00134 * // for this purpose: 00135 * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO); 00136 * 00137 * // Attributes may be added using the attributes interface. 00138 * 00139 * // After successful use of the message, the memory must be freed 00140 * // using nlmsg_free() 00141 * nlmsg_free(msg); 00142 * @endcode 00143 * 00144 * @par 4) Parsing messages 00145 * @code 00146 * int n; 00147 * unsigned char *buf; 00148 * struct nlmsghdr *hdr; 00149 * 00150 * n = nl_recv(handle, NULL, &buf); 00151 * 00152 * hdr = (struct nlmsghdr *) buf; 00153 * while (nlmsg_ok(hdr, n)) { 00154 * // Process message here... 00155 * hdr = nlmsg_next(hdr, &n); 00156 * } 00157 * @endcode 00158 * @{ 00159 */ 00160 00161 #include <netlink-local.h> 00162 #include <netlink/netlink.h> 00163 #include <netlink/utils.h> 00164 #include <netlink/cache.h> 00165 #include <netlink/attr.h> 00166 #include <linux/socket.h> 00167 00168 static size_t default_msg_size; 00169 00170 static void __init init_msg_size(void) 00171 { 00172 default_msg_size = getpagesize(); 00173 } 00174 00175 /** 00176 * @name Size Calculations 00177 * @{ 00178 */ 00179 00180 /** 00181 * Calculates size of netlink message based on payload length. 00182 * @arg payload Length of payload 00183 * 00184 * @return size of netlink message without padding. 00185 */ 00186 int nlmsg_size(int payload) 00187 { 00188 return NLMSG_HDRLEN + payload; 00189 } 00190 00191 static int nlmsg_msg_size(int payload) 00192 { 00193 return nlmsg_size(payload); 00194 } 00195 00196 /** 00197 * Calculates size of netlink message including padding based on payload length 00198 * @arg payload Length of payload 00199 * 00200 * This function is idential to nlmsg_size() + nlmsg_padlen(). 00201 * 00202 * @return Size of netlink message including padding. 00203 */ 00204 int nlmsg_total_size(int payload) 00205 { 00206 return NLMSG_ALIGN(nlmsg_msg_size(payload)); 00207 } 00208 00209 /** 00210 * Size of padding that needs to be added at end of message 00211 * @arg payload Length of payload 00212 * 00213 * Calculates the number of bytes of padding which is required to be added to 00214 * the end of the message to ensure that the next netlink message header begins 00215 * properly aligned to NLMSG_ALIGNTO. 00216 * 00217 * @return Number of bytes of padding needed. 00218 */ 00219 int nlmsg_padlen(int payload) 00220 { 00221 return nlmsg_total_size(payload) - nlmsg_msg_size(payload); 00222 } 00223 00224 /** @} */ 00225 00226 /** 00227 * @name Access to Message Payload 00228 * @{ 00229 */ 00230 00231 /** 00232 * Return pointer to message payload 00233 * @arg nlh Netlink message header 00234 * 00235 * @return Pointer to start of message payload. 00236 */ 00237 void *nlmsg_data(const struct nlmsghdr *nlh) 00238 { 00239 return (unsigned char *) nlh + NLMSG_HDRLEN; 00240 } 00241 00242 void *nlmsg_tail(const struct nlmsghdr *nlh) 00243 { 00244 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); 00245 } 00246 00247 /** 00248 * Return length of message payload 00249 * @arg nlh Netlink message header 00250 * 00251 * @return Length of message payload in bytes. 00252 */ 00253 int nlmsg_datalen(const struct nlmsghdr *nlh) 00254 { 00255 return nlh->nlmsg_len - NLMSG_HDRLEN; 00256 } 00257 00258 static int nlmsg_len(const struct nlmsghdr *nlh) 00259 { 00260 return nlmsg_datalen(nlh); 00261 } 00262 00263 /** @} */ 00264 00265 /** 00266 * @name Attribute Access 00267 * @{ 00268 */ 00269 00270 /** 00271 * head of attributes data 00272 * @arg nlh netlink message header 00273 * @arg hdrlen length of family specific header 00274 */ 00275 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen) 00276 { 00277 unsigned char *data = nlmsg_data(nlh); 00278 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); 00279 } 00280 00281 /** 00282 * length of attributes data 00283 * @arg nlh netlink message header 00284 * @arg hdrlen length of family specific header 00285 */ 00286 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) 00287 { 00288 return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); 00289 } 00290 00291 /** @} */ 00292 00293 /** 00294 * @name Message Parsing 00295 * @{ 00296 */ 00297 00298 int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) 00299 { 00300 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) 00301 return 0; 00302 00303 return 1; 00304 } 00305 00306 /** 00307 * check if the netlink message fits into the remaining bytes 00308 * @arg nlh netlink message header 00309 * @arg remaining number of bytes remaining in message stream 00310 */ 00311 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) 00312 { 00313 return (remaining >= (int)sizeof(struct nlmsghdr) && 00314 nlh->nlmsg_len >= sizeof(struct nlmsghdr) && 00315 nlh->nlmsg_len <= remaining); 00316 } 00317 00318 /** 00319 * next netlink message in message stream 00320 * @arg nlh netlink message header 00321 * @arg remaining number of bytes remaining in message stream 00322 * 00323 * @returns the next netlink message in the message stream and 00324 * decrements remaining by the size of the current message. 00325 */ 00326 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) 00327 { 00328 int totlen = NLMSG_ALIGN(nlh->nlmsg_len); 00329 00330 *remaining -= totlen; 00331 00332 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); 00333 } 00334 00335 /** 00336 * parse attributes of a netlink message 00337 * @arg nlh netlink message header 00338 * @arg hdrlen length of family specific header 00339 * @arg tb destination array with maxtype+1 elements 00340 * @arg maxtype maximum attribute type to be expected 00341 * @arg policy validation policy 00342 * 00343 * See nla_parse() 00344 */ 00345 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], 00346 int maxtype, struct nla_policy *policy) 00347 { 00348 if (!nlmsg_valid_hdr(nlh, hdrlen)) 00349 return -NLE_MSG_TOOSHORT; 00350 00351 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), 00352 nlmsg_attrlen(nlh, hdrlen), policy); 00353 } 00354 00355 /** 00356 * nlmsg_find_attr - find a specific attribute in a netlink message 00357 * @arg nlh netlink message header 00358 * @arg hdrlen length of familiy specific header 00359 * @arg attrtype type of attribute to look for 00360 * 00361 * Returns the first attribute which matches the specified type. 00362 */ 00363 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) 00364 { 00365 return nla_find(nlmsg_attrdata(nlh, hdrlen), 00366 nlmsg_attrlen(nlh, hdrlen), attrtype); 00367 } 00368 00369 /** 00370 * nlmsg_validate - validate a netlink message including attributes 00371 * @arg nlh netlinket message header 00372 * @arg hdrlen length of familiy specific header 00373 * @arg maxtype maximum attribute type to be expected 00374 * @arg policy validation policy 00375 */ 00376 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, 00377 struct nla_policy *policy) 00378 { 00379 if (!nlmsg_valid_hdr(nlh, hdrlen)) 00380 return -NLE_MSG_TOOSHORT; 00381 00382 return nla_validate(nlmsg_attrdata(nlh, hdrlen), 00383 nlmsg_attrlen(nlh, hdrlen), maxtype, policy); 00384 } 00385 00386 /** @} */ 00387 00388 /** 00389 * @name Message Building/Access 00390 * @{ 00391 */ 00392 00393 static struct nl_msg *__nlmsg_alloc(size_t len) 00394 { 00395 struct nl_msg *nm; 00396 00397 if (len < sizeof(struct nlmsghdr)) 00398 len = sizeof(struct nlmsghdr); 00399 00400 nm = calloc(1, sizeof(*nm)); 00401 if (!nm) 00402 goto errout; 00403 00404 nm->nm_refcnt = 1; 00405 00406 nm->nm_nlh = calloc(1, len); 00407 if (!nm->nm_nlh) 00408 goto errout; 00409 00410 memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr)); 00411 00412 nm->nm_protocol = -1; 00413 nm->nm_size = len; 00414 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); 00415 00416 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); 00417 00418 return nm; 00419 errout: 00420 free(nm); 00421 return NULL; 00422 } 00423 00424 /** 00425 * Allocate a new netlink message with the default maximum payload size. 00426 * 00427 * Allocates a new netlink message without any further payload. The 00428 * maximum payload size defaults to PAGESIZE or as otherwise specified 00429 * with nlmsg_set_default_size(). 00430 * 00431 * @return Newly allocated netlink message or NULL. 00432 */ 00433 struct nl_msg *nlmsg_alloc(void) 00434 { 00435 return __nlmsg_alloc(default_msg_size); 00436 } 00437 00438 /** 00439 * Allocate a new netlink message with maximum payload size specified. 00440 */ 00441 struct nl_msg *nlmsg_alloc_size(size_t max) 00442 { 00443 return __nlmsg_alloc(max); 00444 } 00445 00446 /** 00447 * Allocate a new netlink message and inherit netlink message header 00448 * @arg hdr Netlink message header template 00449 * 00450 * Allocates a new netlink message and inherits the original message 00451 * header. If \a hdr is not NULL it will be used as a template for 00452 * the netlink message header, otherwise the header is left blank. 00453 * 00454 * @return Newly allocated netlink message or NULL 00455 */ 00456 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) 00457 { 00458 struct nl_msg *nm; 00459 00460 nm = nlmsg_alloc(); 00461 if (nm && hdr) { 00462 struct nlmsghdr *new = nm->nm_nlh; 00463 00464 new->nlmsg_type = hdr->nlmsg_type; 00465 new->nlmsg_flags = hdr->nlmsg_flags; 00466 new->nlmsg_seq = hdr->nlmsg_seq; 00467 new->nlmsg_pid = hdr->nlmsg_pid; 00468 } 00469 00470 return nm; 00471 } 00472 00473 /** 00474 * Allocate a new netlink message 00475 * @arg nlmsgtype Netlink message type 00476 * @arg flags Message flags. 00477 * 00478 * @return Newly allocated netlink message or NULL. 00479 */ 00480 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) 00481 { 00482 struct nl_msg *msg; 00483 struct nlmsghdr nlh = { 00484 .nlmsg_type = nlmsgtype, 00485 .nlmsg_flags = flags, 00486 }; 00487 00488 msg = nlmsg_inherit(&nlh); 00489 if (msg) 00490 NL_DBG(2, "msg %p: Allocated new simple message\n", msg); 00491 00492 return msg; 00493 } 00494 00495 /** 00496 * Set the default maximum message payload size for allocated messages 00497 * @arg max Size of payload in bytes. 00498 */ 00499 void nlmsg_set_default_size(size_t max) 00500 { 00501 if (max < nlmsg_total_size(0)) 00502 max = nlmsg_total_size(0); 00503 00504 default_msg_size = max; 00505 } 00506 00507 /** 00508 * Convert a netlink message received from a netlink socket to a nl_msg 00509 * @arg hdr Netlink message received from netlink socket. 00510 * 00511 * Allocates a new netlink message and copies all of the data pointed to 00512 * by \a hdr into the new message object. 00513 * 00514 * @return Newly allocated netlink message or NULL. 00515 */ 00516 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) 00517 { 00518 struct nl_msg *nm; 00519 00520 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); 00521 if (!nm) 00522 goto errout; 00523 00524 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); 00525 00526 return nm; 00527 errout: 00528 nlmsg_free(nm); 00529 return NULL; 00530 } 00531 00532 /** 00533 * Reserve room for additional data in a netlink message 00534 * @arg n netlink message 00535 * @arg len length of additional data to reserve room for 00536 * @arg pad number of bytes to align data to 00537 * 00538 * Reserves room for additional data at the tail of the an 00539 * existing netlink message. Eventual padding required will 00540 * be zeroed out. 00541 * 00542 * @return Pointer to start of additional data tailroom or NULL. 00543 */ 00544 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) 00545 { 00546 void *buf = n->nm_nlh; 00547 size_t nlmsg_len = n->nm_nlh->nlmsg_len; 00548 size_t tlen; 00549 00550 if (len > n->nm_size) 00551 return NULL; 00552 00553 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 00554 00555 if ((tlen + nlmsg_len) > n->nm_size) 00556 return NULL; 00557 00558 buf += nlmsg_len; 00559 n->nm_nlh->nlmsg_len += tlen; 00560 00561 if (tlen > len) 00562 memset(buf + len, 0, tlen - len); 00563 00564 NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n", 00565 n, tlen, len, pad, n->nm_nlh->nlmsg_len); 00566 00567 return buf; 00568 } 00569 00570 /** 00571 * Append data to tail of a netlink message 00572 * @arg n netlink message 00573 * @arg data data to add 00574 * @arg len length of data 00575 * @arg pad Number of bytes to align data to. 00576 * 00577 * Extends the netlink message as needed and appends the data of given 00578 * length to the message. 00579 * 00580 * @return 0 on success or a negative error code 00581 */ 00582 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 00583 { 00584 void *tmp; 00585 00586 tmp = nlmsg_reserve(n, len, pad); 00587 if (tmp == NULL) 00588 return -NLE_NOMEM; 00589 00590 memcpy(tmp, data, len); 00591 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 00592 00593 return 0; 00594 } 00595 00596 /** 00597 * Expand maximum payload size of a netlink message 00598 * @arg n Netlink message. 00599 * @arg newlen New maximum payload size. 00600 * 00601 * Reallocates the payload section of a netlink message and increases 00602 * the maximum payload size of the message. 00603 * 00604 * @note Any pointers pointing to old payload block will be stale and 00605 * need to be refetched. Therfore, do not expand while constructing 00606 * nested attributes or while reserved data blocks are held. 00607 * 00608 * @return 0 on success or a negative error code. 00609 */ 00610 int nlmsg_expand(struct nl_msg *n, size_t newlen) 00611 { 00612 void *tmp; 00613 00614 if (newlen <= n->nm_size) 00615 return -NLE_INVAL; 00616 00617 tmp = realloc(n->nm_nlh, newlen); 00618 if (tmp == NULL) 00619 return -NLE_NOMEM; 00620 00621 n->nm_nlh = tmp; 00622 n->nm_size = newlen; 00623 00624 return 0; 00625 } 00626 00627 /** 00628 * Add a netlink message header to a netlink message 00629 * @arg n netlink message 00630 * @arg pid netlink process id or NL_AUTO_PID 00631 * @arg seq sequence number of message or NL_AUTO_SEQ 00632 * @arg type message type 00633 * @arg payload length of message payload 00634 * @arg flags message flags 00635 * 00636 * Adds or overwrites the netlink message header in an existing message 00637 * object. If \a payload is greater-than zero additional room will be 00638 * reserved, f.e. for family specific headers. It can be accesed via 00639 * nlmsg_data(). 00640 * 00641 * @return A pointer to the netlink message header or NULL. 00642 */ 00643 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 00644 int type, int payload, int flags) 00645 { 00646 struct nlmsghdr *nlh; 00647 00648 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 00649 BUG(); 00650 00651 nlh = (struct nlmsghdr *) n->nm_nlh; 00652 nlh->nlmsg_type = type; 00653 nlh->nlmsg_flags = flags; 00654 nlh->nlmsg_pid = pid; 00655 nlh->nlmsg_seq = seq; 00656 00657 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 00658 "seq=%d\n", n, type, flags, pid, seq); 00659 00660 if (payload > 0 && 00661 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 00662 return NULL; 00663 00664 return nlh; 00665 } 00666 00667 /** 00668 * Return actual netlink message 00669 * @arg n netlink message 00670 * 00671 * Returns the actual netlink message casted to the type of the netlink 00672 * message header. 00673 * 00674 * @return A pointer to the netlink message. 00675 */ 00676 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) 00677 { 00678 return n->nm_nlh; 00679 } 00680 00681 /** 00682 * Acquire a reference on a netlink message 00683 * @arg msg message to acquire reference from 00684 */ 00685 void nlmsg_get(struct nl_msg *msg) 00686 { 00687 msg->nm_refcnt++; 00688 NL_DBG(4, "New reference to message %p, total %d\n", 00689 msg, msg->nm_refcnt); 00690 } 00691 00692 /** 00693 * Release a reference from an netlink message 00694 * @arg msg message to release reference from 00695 * 00696 * Frees memory after the last reference has been released. 00697 */ 00698 void nlmsg_free(struct nl_msg *msg) 00699 { 00700 if (!msg) 00701 return; 00702 00703 msg->nm_refcnt--; 00704 NL_DBG(4, "Returned message reference %p, %d remaining\n", 00705 msg, msg->nm_refcnt); 00706 00707 if (msg->nm_refcnt < 0) 00708 BUG(); 00709 00710 if (msg->nm_refcnt <= 0) { 00711 free(msg->nm_nlh); 00712 free(msg); 00713 NL_DBG(2, "msg %p: Freed\n", msg); 00714 } 00715 } 00716 00717 /** @} */ 00718 00719 /** 00720 * @name Attributes 00721 * @{ 00722 */ 00723 00724 void nlmsg_set_proto(struct nl_msg *msg, int protocol) 00725 { 00726 msg->nm_protocol = protocol; 00727 } 00728 00729 int nlmsg_get_proto(struct nl_msg *msg) 00730 { 00731 return msg->nm_protocol; 00732 } 00733 00734 size_t nlmsg_get_max_size(struct nl_msg *msg) 00735 { 00736 return msg->nm_size; 00737 } 00738 00739 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) 00740 { 00741 memcpy(&msg->nm_src, addr, sizeof(*addr)); 00742 } 00743 00744 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) 00745 { 00746 return &msg->nm_src; 00747 } 00748 00749 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) 00750 { 00751 memcpy(&msg->nm_dst, addr, sizeof(*addr)); 00752 } 00753 00754 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) 00755 { 00756 return &msg->nm_dst; 00757 } 00758 00759 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) 00760 { 00761 memcpy(&msg->nm_creds, creds, sizeof(*creds)); 00762 msg->nm_flags |= NL_MSG_CRED_PRESENT; 00763 } 00764 00765 struct ucred *nlmsg_get_creds(struct nl_msg *msg) 00766 { 00767 if (msg->nm_flags & NL_MSG_CRED_PRESENT) 00768 return &msg->nm_creds; 00769 return NULL; 00770 } 00771 00772 /** @} */ 00773 00774 /** 00775 * @name Netlink Message Type Translations 00776 * @{ 00777 */ 00778 00779 static const struct trans_tbl nl_msgtypes[] = { 00780 __ADD(NLMSG_NOOP,NOOP) 00781 __ADD(NLMSG_ERROR,ERROR) 00782 __ADD(NLMSG_DONE,DONE) 00783 __ADD(NLMSG_OVERRUN,OVERRUN) 00784 }; 00785 00786 char *nl_nlmsgtype2str(int type, char *buf, size_t size) 00787 { 00788 return __type2str(type, buf, size, nl_msgtypes, 00789 ARRAY_SIZE(nl_msgtypes)); 00790 } 00791 00792 int nl_str2nlmsgtype(const char *name) 00793 { 00794 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); 00795 } 00796 00797 /** @} */ 00798 00799 /** 00800 * @name Netlink Message Flags Translations 00801 * @{ 00802 */ 00803 00804 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) 00805 { 00806 memset(buf, 0, len); 00807 00808 #define PRINT_FLAG(f) \ 00809 if (flags & NLM_F_##f) { \ 00810 flags &= ~NLM_F_##f; \ 00811 strncat(buf, #f, len - strlen(buf) - 1); \ 00812 if (flags) \ 00813 strncat(buf, ",", len - strlen(buf) - 1); \ 00814 } 00815 00816 PRINT_FLAG(REQUEST); 00817 PRINT_FLAG(MULTI); 00818 PRINT_FLAG(ACK); 00819 PRINT_FLAG(ECHO); 00820 PRINT_FLAG(ROOT); 00821 PRINT_FLAG(MATCH); 00822 PRINT_FLAG(ATOMIC); 00823 PRINT_FLAG(REPLACE); 00824 PRINT_FLAG(EXCL); 00825 PRINT_FLAG(CREATE); 00826 PRINT_FLAG(APPEND); 00827 00828 if (flags) { 00829 char s[32]; 00830 snprintf(s, sizeof(s), "0x%x", flags); 00831 strncat(buf, s, len - strlen(buf) - 1); 00832 } 00833 #undef PRINT_FLAG 00834 00835 return buf; 00836 } 00837 00838 /** @} */ 00839 00840 /** 00841 * @name Direct Parsing 00842 * @{ 00843 */ 00844 00845 /** @cond SKIP */ 00846 struct dp_xdata { 00847 void (*cb)(struct nl_object *, void *); 00848 void *arg; 00849 }; 00850 /** @endcond */ 00851 00852 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 00853 { 00854 struct dp_xdata *x = p->pp_arg; 00855 00856 x->cb(obj, x->arg); 00857 return 0; 00858 } 00859 00860 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 00861 void *arg) 00862 { 00863 struct nl_cache_ops *ops; 00864 struct nl_parser_param p = { 00865 .pp_cb = parse_cb 00866 }; 00867 struct dp_xdata x = { 00868 .cb = cb, 00869 .arg = arg, 00870 }; 00871 00872 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 00873 nlmsg_hdr(msg)->nlmsg_type); 00874 if (ops == NULL) 00875 return -NLE_MSGTYPE_NOSUPPORT; 00876 p.pp_arg = &x; 00877 00878 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 00879 } 00880 00881 /** @} */ 00882 00883 /** 00884 * @name Dumping 00885 * @{ 00886 */ 00887 00888 static void prefix_line(FILE *ofd, int prefix) 00889 { 00890 int i; 00891 00892 for (i = 0; i < prefix; i++) 00893 fprintf(ofd, " "); 00894 } 00895 00896 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) 00897 { 00898 int i, a, c, limit; 00899 char ascii[21] = {0}; 00900 00901 limit = 18 - (prefix * 2); 00902 prefix_line(ofd, prefix); 00903 fprintf(ofd, " "); 00904 00905 for (i = 0, a = 0, c = 0; i < len; i++) { 00906 int v = *(uint8_t *) (start + i); 00907 00908 fprintf(ofd, "%02x ", v); 00909 ascii[a++] = isprint(v) ? v : '.'; 00910 00911 if (c == limit-1) { 00912 fprintf(ofd, "%s\n", ascii); 00913 if (i < (len - 1)) { 00914 prefix_line(ofd, prefix); 00915 fprintf(ofd, " "); 00916 } 00917 a = c = 0; 00918 memset(ascii, 0, sizeof(ascii)); 00919 } else 00920 c++; 00921 } 00922 00923 if (c != 0) { 00924 for (i = 0; i < (limit - c); i++) 00925 fprintf(ofd, " "); 00926 fprintf(ofd, "%s\n", ascii); 00927 } 00928 } 00929 00930 static void print_hdr(FILE *ofd, struct nl_msg *msg) 00931 { 00932 struct nlmsghdr *nlh = nlmsg_hdr(msg); 00933 struct nl_cache_ops *ops; 00934 struct nl_msgtype *mt; 00935 char buf[128]; 00936 00937 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); 00938 00939 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); 00940 if (ops) { 00941 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); 00942 if (!mt) 00943 BUG(); 00944 00945 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); 00946 } else 00947 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); 00948 00949 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf); 00950 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, 00951 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); 00952 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); 00953 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); 00954 00955 } 00956 00957 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, 00958 int prefix) 00959 { 00960 int rem; 00961 struct nlattr *nla; 00962 00963 nla_for_each_attr(nla, attrs, attrlen, rem) { 00964 int padlen, alen = nla_len(nla); 00965 00966 prefix_line(ofd, prefix); 00967 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), 00968 nla->nla_type & NLA_F_NESTED ? " NESTED" : "", 00969 alen); 00970 00971 if (nla->nla_type & NLA_F_NESTED) 00972 dump_attrs(ofd, nla_data(nla), alen, prefix+1); 00973 else 00974 dump_hex(ofd, nla_data(nla), alen, prefix); 00975 00976 padlen = nla_padlen(alen); 00977 if (padlen > 0) { 00978 prefix_line(ofd, prefix); 00979 fprintf(ofd, " [PADDING] %d octets\n", 00980 padlen); 00981 dump_hex(ofd, nla_data(nla) + alen, 00982 padlen, prefix); 00983 } 00984 } 00985 00986 if (rem) { 00987 prefix_line(ofd, prefix); 00988 fprintf(ofd, " [LEFTOVER] %d octets\n", rem); 00989 } 00990 } 00991 00992 /** 00993 * Dump message in human readable format to file descriptor 00994 * @arg msg Message to print 00995 * @arg ofd File descriptor. 00996 */ 00997 void nl_msg_dump(struct nl_msg *msg, FILE *ofd) 00998 { 00999 struct nlmsghdr *hdr = nlmsg_hdr(msg); 01000 01001 fprintf(ofd, 01002 "-------------------------- BEGIN NETLINK MESSAGE " 01003 "---------------------------\n"); 01004 01005 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); 01006 print_hdr(ofd, msg); 01007 01008 if (hdr->nlmsg_type == NLMSG_ERROR && 01009 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { 01010 struct nl_msg *errmsg; 01011 struct nlmsgerr *err = nlmsg_data(hdr); 01012 01013 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); 01014 fprintf(ofd, " .error = %d \"%s\"\n", err->error, 01015 strerror(-err->error)); 01016 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); 01017 01018 errmsg = nlmsg_inherit(&err->msg); 01019 print_hdr(ofd, errmsg); 01020 nlmsg_free(errmsg); 01021 } else if (nlmsg_len(hdr) > 0) { 01022 struct nl_cache_ops *ops; 01023 int payloadlen = nlmsg_len(hdr); 01024 int attrlen = 0; 01025 01026 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 01027 hdr->nlmsg_type); 01028 if (ops) { 01029 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01030 payloadlen -= attrlen; 01031 } 01032 01033 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); 01034 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0); 01035 01036 if (attrlen) { 01037 struct nlattr *attrs; 01038 int attrlen; 01039 01040 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); 01041 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01042 dump_attrs(ofd, attrs, attrlen, 0); 01043 } 01044 } 01045 01046 fprintf(ofd, 01047 "--------------------------- END NETLINK MESSAGE " 01048 "---------------------------\n"); 01049 } 01050 01051 /** @} */ 01052 01053 /** @} */