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 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 00551 00552 if ((tlen + nlmsg_len) > n->nm_size) 00553 return NULL; 00554 00555 buf += nlmsg_len; 00556 n->nm_nlh->nlmsg_len += tlen; 00557 00558 if (tlen > len) 00559 memset(buf + len, 0, tlen - len); 00560 00561 NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n", 00562 n, tlen, len, pad, n->nm_nlh->nlmsg_len); 00563 00564 return buf; 00565 } 00566 00567 /** 00568 * Append data to tail of a netlink message 00569 * @arg n netlink message 00570 * @arg data data to add 00571 * @arg len length of data 00572 * @arg pad Number of bytes to align data to. 00573 * 00574 * Extends the netlink message as needed and appends the data of given 00575 * length to the message. 00576 * 00577 * @return 0 on success or a negative error code 00578 */ 00579 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 00580 { 00581 void *tmp; 00582 00583 tmp = nlmsg_reserve(n, len, pad); 00584 if (tmp == NULL) 00585 return -NLE_NOMEM; 00586 00587 memcpy(tmp, data, len); 00588 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 00589 00590 return 0; 00591 } 00592 00593 /** 00594 * Expand maximum payload size of a netlink message 00595 * @arg n Netlink message. 00596 * @arg newlen New maximum payload size. 00597 * 00598 * Reallocates the payload section of a netlink message and increases 00599 * the maximum payload size of the message. 00600 * 00601 * @note Any pointers pointing to old payload block will be stale and 00602 * need to be refetched. Therfore, do not expand while constructing 00603 * nested attributes or while reserved data blocks are held. 00604 * 00605 * @return 0 on success or a negative error code. 00606 */ 00607 int nlmsg_expand(struct nl_msg *n, size_t newlen) 00608 { 00609 void *tmp; 00610 00611 if (newlen <= n->nm_size) 00612 return -NLE_INVAL; 00613 00614 tmp = realloc(n->nm_nlh, newlen); 00615 if (tmp == NULL) 00616 return -NLE_NOMEM; 00617 00618 n->nm_nlh = tmp; 00619 n->nm_size = newlen; 00620 00621 return 0; 00622 } 00623 00624 /** 00625 * Add a netlink message header to a netlink message 00626 * @arg n netlink message 00627 * @arg pid netlink process id or NL_AUTO_PID 00628 * @arg seq sequence number of message or NL_AUTO_SEQ 00629 * @arg type message type 00630 * @arg payload length of message payload 00631 * @arg flags message flags 00632 * 00633 * Adds or overwrites the netlink message header in an existing message 00634 * object. If \a payload is greater-than zero additional room will be 00635 * reserved, f.e. for family specific headers. It can be accesed via 00636 * nlmsg_data(). 00637 * 00638 * @return A pointer to the netlink message header or NULL. 00639 */ 00640 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 00641 int type, int payload, int flags) 00642 { 00643 struct nlmsghdr *nlh; 00644 00645 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 00646 BUG(); 00647 00648 nlh = (struct nlmsghdr *) n->nm_nlh; 00649 nlh->nlmsg_type = type; 00650 nlh->nlmsg_flags = flags; 00651 nlh->nlmsg_pid = pid; 00652 nlh->nlmsg_seq = seq; 00653 00654 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 00655 "seq=%d\n", n, type, flags, pid, seq); 00656 00657 if (payload > 0 && 00658 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 00659 return NULL; 00660 00661 return nlh; 00662 } 00663 00664 /** 00665 * Return actual netlink message 00666 * @arg n netlink message 00667 * 00668 * Returns the actual netlink message casted to the type of the netlink 00669 * message header. 00670 * 00671 * @return A pointer to the netlink message. 00672 */ 00673 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) 00674 { 00675 return n->nm_nlh; 00676 } 00677 00678 /** 00679 * Acquire a reference on a netlink message 00680 * @arg msg message to acquire reference from 00681 */ 00682 void nlmsg_get(struct nl_msg *msg) 00683 { 00684 msg->nm_refcnt++; 00685 NL_DBG(4, "New reference to message %p, total %d\n", 00686 msg, msg->nm_refcnt); 00687 } 00688 00689 /** 00690 * Release a reference from an netlink message 00691 * @arg msg message to release reference from 00692 * 00693 * Frees memory after the last reference has been released. 00694 */ 00695 void nlmsg_free(struct nl_msg *msg) 00696 { 00697 if (!msg) 00698 return; 00699 00700 msg->nm_refcnt--; 00701 NL_DBG(4, "Returned message reference %p, %d remaining\n", 00702 msg, msg->nm_refcnt); 00703 00704 if (msg->nm_refcnt < 0) 00705 BUG(); 00706 00707 if (msg->nm_refcnt <= 0) { 00708 free(msg->nm_nlh); 00709 free(msg); 00710 NL_DBG(2, "msg %p: Freed\n", msg); 00711 } 00712 } 00713 00714 /** @} */ 00715 00716 /** 00717 * @name Attributes 00718 * @{ 00719 */ 00720 00721 void nlmsg_set_proto(struct nl_msg *msg, int protocol) 00722 { 00723 msg->nm_protocol = protocol; 00724 } 00725 00726 int nlmsg_get_proto(struct nl_msg *msg) 00727 { 00728 return msg->nm_protocol; 00729 } 00730 00731 size_t nlmsg_get_max_size(struct nl_msg *msg) 00732 { 00733 return msg->nm_size; 00734 } 00735 00736 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) 00737 { 00738 memcpy(&msg->nm_src, addr, sizeof(*addr)); 00739 } 00740 00741 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) 00742 { 00743 return &msg->nm_src; 00744 } 00745 00746 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) 00747 { 00748 memcpy(&msg->nm_dst, addr, sizeof(*addr)); 00749 } 00750 00751 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) 00752 { 00753 return &msg->nm_dst; 00754 } 00755 00756 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) 00757 { 00758 memcpy(&msg->nm_creds, creds, sizeof(*creds)); 00759 msg->nm_flags |= NL_MSG_CRED_PRESENT; 00760 } 00761 00762 struct ucred *nlmsg_get_creds(struct nl_msg *msg) 00763 { 00764 if (msg->nm_flags & NL_MSG_CRED_PRESENT) 00765 return &msg->nm_creds; 00766 return NULL; 00767 } 00768 00769 /** @} */ 00770 00771 /** 00772 * @name Netlink Message Type Translations 00773 * @{ 00774 */ 00775 00776 static const struct trans_tbl nl_msgtypes[] = { 00777 __ADD(NLMSG_NOOP,NOOP) 00778 __ADD(NLMSG_ERROR,ERROR) 00779 __ADD(NLMSG_DONE,DONE) 00780 __ADD(NLMSG_OVERRUN,OVERRUN) 00781 }; 00782 00783 char *nl_nlmsgtype2str(int type, char *buf, size_t size) 00784 { 00785 return __type2str(type, buf, size, nl_msgtypes, 00786 ARRAY_SIZE(nl_msgtypes)); 00787 } 00788 00789 int nl_str2nlmsgtype(const char *name) 00790 { 00791 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); 00792 } 00793 00794 /** @} */ 00795 00796 /** 00797 * @name Netlink Message Flags Translations 00798 * @{ 00799 */ 00800 00801 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) 00802 { 00803 memset(buf, 0, len); 00804 00805 #define PRINT_FLAG(f) \ 00806 if (flags & NLM_F_##f) { \ 00807 flags &= ~NLM_F_##f; \ 00808 strncat(buf, #f, len - strlen(buf) - 1); \ 00809 if (flags) \ 00810 strncat(buf, ",", len - strlen(buf) - 1); \ 00811 } 00812 00813 PRINT_FLAG(REQUEST); 00814 PRINT_FLAG(MULTI); 00815 PRINT_FLAG(ACK); 00816 PRINT_FLAG(ECHO); 00817 PRINT_FLAG(ROOT); 00818 PRINT_FLAG(MATCH); 00819 PRINT_FLAG(ATOMIC); 00820 PRINT_FLAG(REPLACE); 00821 PRINT_FLAG(EXCL); 00822 PRINT_FLAG(CREATE); 00823 PRINT_FLAG(APPEND); 00824 00825 if (flags) { 00826 char s[32]; 00827 snprintf(s, sizeof(s), "0x%x", flags); 00828 strncat(buf, s, len - strlen(buf) - 1); 00829 } 00830 #undef PRINT_FLAG 00831 00832 return buf; 00833 } 00834 00835 /** @} */ 00836 00837 /** 00838 * @name Direct Parsing 00839 * @{ 00840 */ 00841 00842 /** @cond SKIP */ 00843 struct dp_xdata { 00844 void (*cb)(struct nl_object *, void *); 00845 void *arg; 00846 }; 00847 /** @endcond */ 00848 00849 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 00850 { 00851 struct dp_xdata *x = p->pp_arg; 00852 00853 x->cb(obj, x->arg); 00854 return 0; 00855 } 00856 00857 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 00858 void *arg) 00859 { 00860 struct nl_cache_ops *ops; 00861 struct nl_parser_param p = { 00862 .pp_cb = parse_cb 00863 }; 00864 struct dp_xdata x = { 00865 .cb = cb, 00866 .arg = arg, 00867 }; 00868 00869 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 00870 nlmsg_hdr(msg)->nlmsg_type); 00871 if (ops == NULL) 00872 return -NLE_MSGTYPE_NOSUPPORT; 00873 p.pp_arg = &x; 00874 00875 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 00876 } 00877 00878 /** @} */ 00879 00880 /** 00881 * @name Dumping 00882 * @{ 00883 */ 00884 00885 static void prefix_line(FILE *ofd, int prefix) 00886 { 00887 int i; 00888 00889 for (i = 0; i < prefix; i++) 00890 fprintf(ofd, " "); 00891 } 00892 00893 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) 00894 { 00895 int i, a, c, limit; 00896 char ascii[21] = {0}; 00897 00898 limit = 18 - (prefix * 2); 00899 prefix_line(ofd, prefix); 00900 fprintf(ofd, " "); 00901 00902 for (i = 0, a = 0, c = 0; i < len; i++) { 00903 int v = *(uint8_t *) (start + i); 00904 00905 fprintf(ofd, "%02x ", v); 00906 ascii[a++] = isprint(v) ? v : '.'; 00907 00908 if (c == limit-1) { 00909 fprintf(ofd, "%s\n", ascii); 00910 if (i < (len - 1)) { 00911 prefix_line(ofd, prefix); 00912 fprintf(ofd, " "); 00913 } 00914 a = c = 0; 00915 memset(ascii, 0, sizeof(ascii)); 00916 } else 00917 c++; 00918 } 00919 00920 if (c != 0) { 00921 for (i = 0; i < (limit - c); i++) 00922 fprintf(ofd, " "); 00923 fprintf(ofd, "%s\n", ascii); 00924 } 00925 } 00926 00927 static void print_hdr(FILE *ofd, struct nl_msg *msg) 00928 { 00929 struct nlmsghdr *nlh = nlmsg_hdr(msg); 00930 struct nl_cache_ops *ops; 00931 struct nl_msgtype *mt; 00932 char buf[128]; 00933 00934 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); 00935 00936 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); 00937 if (ops) { 00938 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); 00939 if (!mt) 00940 BUG(); 00941 00942 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); 00943 } else 00944 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); 00945 00946 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf); 00947 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, 00948 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); 00949 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); 00950 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); 00951 00952 } 00953 00954 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, 00955 int prefix) 00956 { 00957 int rem; 00958 struct nlattr *nla; 00959 00960 nla_for_each_attr(nla, attrs, attrlen, rem) { 00961 int padlen, alen = nla_len(nla); 00962 00963 prefix_line(ofd, prefix); 00964 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), 00965 nla->nla_type & NLA_F_NESTED ? " NESTED" : "", 00966 alen); 00967 00968 if (nla->nla_type & NLA_F_NESTED) 00969 dump_attrs(ofd, nla_data(nla), alen, prefix+1); 00970 else 00971 dump_hex(ofd, nla_data(nla), alen, prefix); 00972 00973 padlen = nla_padlen(alen); 00974 if (padlen > 0) { 00975 prefix_line(ofd, prefix); 00976 fprintf(ofd, " [PADDING] %d octets\n", 00977 padlen); 00978 dump_hex(ofd, nla_data(nla) + alen, 00979 padlen, prefix); 00980 } 00981 } 00982 00983 if (rem) { 00984 prefix_line(ofd, prefix); 00985 fprintf(ofd, " [LEFTOVER] %d octets\n", rem); 00986 } 00987 } 00988 00989 /** 00990 * Dump message in human readable format to file descriptor 00991 * @arg msg Message to print 00992 * @arg ofd File descriptor. 00993 */ 00994 void nl_msg_dump(struct nl_msg *msg, FILE *ofd) 00995 { 00996 struct nlmsghdr *hdr = nlmsg_hdr(msg); 00997 00998 fprintf(ofd, 00999 "-------------------------- BEGIN NETLINK MESSAGE " 01000 "---------------------------\n"); 01001 01002 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); 01003 print_hdr(ofd, msg); 01004 01005 if (hdr->nlmsg_type == NLMSG_ERROR && 01006 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { 01007 struct nl_msg *errmsg; 01008 struct nlmsgerr *err = nlmsg_data(hdr); 01009 01010 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); 01011 fprintf(ofd, " .error = %d \"%s\"\n", err->error, 01012 strerror(-err->error)); 01013 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); 01014 01015 errmsg = nlmsg_inherit(&err->msg); 01016 print_hdr(ofd, errmsg); 01017 nlmsg_free(errmsg); 01018 } else if (nlmsg_len(hdr) > 0) { 01019 struct nl_cache_ops *ops; 01020 int payloadlen = nlmsg_len(hdr); 01021 int attrlen = 0; 01022 01023 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 01024 hdr->nlmsg_type); 01025 if (ops) { 01026 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01027 payloadlen -= attrlen; 01028 } 01029 01030 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); 01031 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0); 01032 01033 if (attrlen) { 01034 struct nlattr *attrs; 01035 int attrlen; 01036 01037 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); 01038 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01039 dump_attrs(ofd, attrs, attrlen, 0); 01040 } 01041 } 01042 01043 fprintf(ofd, 01044 "--------------------------- END NETLINK MESSAGE " 01045 "---------------------------\n"); 01046 } 01047 01048 /** @} */ 01049 01050 /** @} */