libnl 3.0
|
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 (\link nlmsghdr struct nlmsghdr\endlink) 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 * See \ref core_msg_fmt_align for more information on alignment. 00185 * 00186 * @return size of netlink message without padding. 00187 */ 00188 int nlmsg_size(int payload) 00189 { 00190 return NLMSG_HDRLEN + payload; 00191 } 00192 00193 int nlmsg_msg_size(int payload) 00194 { 00195 return nlmsg_size(payload); 00196 } 00197 00198 /** 00199 * Calculates size of netlink message including padding based on payload length 00200 * @arg payload Length of payload 00201 * 00202 * This function is idential to nlmsg_size() + nlmsg_padlen(). 00203 * 00204 * See \ref core_msg_fmt_align for more information on alignment. 00205 * 00206 * @return Size of netlink message including padding. 00207 */ 00208 int nlmsg_total_size(int payload) 00209 { 00210 return NLMSG_ALIGN(nlmsg_msg_size(payload)); 00211 } 00212 00213 /** 00214 * Size of padding that needs to be added at end of message 00215 * @arg payload Length of payload 00216 * 00217 * Calculates the number of bytes of padding which is required to be added to 00218 * the end of the message to ensure that the next netlink message header begins 00219 * properly aligned to NLMSG_ALIGNTO. 00220 * 00221 * See \ref core_msg_fmt_align for more information on alignment. 00222 * 00223 * @return Number of bytes of padding needed. 00224 */ 00225 int nlmsg_padlen(int payload) 00226 { 00227 return nlmsg_total_size(payload) - nlmsg_msg_size(payload); 00228 } 00229 00230 /** @} */ 00231 00232 /** 00233 * @name Access to Message Payload 00234 * @{ 00235 */ 00236 00237 /** 00238 * Return pointer to message payload 00239 * @arg nlh Netlink message header 00240 * 00241 * @return Pointer to start of message payload. 00242 */ 00243 void *nlmsg_data(const struct nlmsghdr *nlh) 00244 { 00245 return (unsigned char *) nlh + NLMSG_HDRLEN; 00246 } 00247 00248 void *nlmsg_tail(const struct nlmsghdr *nlh) 00249 { 00250 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); 00251 } 00252 00253 /** 00254 * Return length of message payload 00255 * @arg nlh Netlink message header 00256 * 00257 * @return Length of message payload in bytes. 00258 */ 00259 int nlmsg_datalen(const struct nlmsghdr *nlh) 00260 { 00261 return nlh->nlmsg_len - NLMSG_HDRLEN; 00262 } 00263 00264 int nlmsg_len(const struct nlmsghdr *nlh) 00265 { 00266 return nlmsg_datalen(nlh); 00267 } 00268 00269 /** @} */ 00270 00271 /** 00272 * @name Attribute Access 00273 * @{ 00274 */ 00275 00276 /** 00277 * head of attributes data 00278 * @arg nlh netlink message header 00279 * @arg hdrlen length of family specific header 00280 */ 00281 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen) 00282 { 00283 unsigned char *data = nlmsg_data(nlh); 00284 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); 00285 } 00286 00287 /** 00288 * length of attributes data 00289 * @arg nlh netlink message header 00290 * @arg hdrlen length of family specific header 00291 */ 00292 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) 00293 { 00294 return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); 00295 } 00296 00297 /** @} */ 00298 00299 /** 00300 * @name Message Parsing 00301 * @{ 00302 */ 00303 00304 int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) 00305 { 00306 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) 00307 return 0; 00308 00309 return 1; 00310 } 00311 00312 /** 00313 * check if the netlink message fits into the remaining bytes 00314 * @arg nlh netlink message header 00315 * @arg remaining number of bytes remaining in message stream 00316 */ 00317 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) 00318 { 00319 return (remaining >= (int)sizeof(struct nlmsghdr) && 00320 nlh->nlmsg_len >= sizeof(struct nlmsghdr) && 00321 nlh->nlmsg_len <= remaining); 00322 } 00323 00324 /** 00325 * next netlink message in message stream 00326 * @arg nlh netlink message header 00327 * @arg remaining number of bytes remaining in message stream 00328 * 00329 * @returns the next netlink message in the message stream and 00330 * decrements remaining by the size of the current message. 00331 */ 00332 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) 00333 { 00334 int totlen = NLMSG_ALIGN(nlh->nlmsg_len); 00335 00336 *remaining -= totlen; 00337 00338 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); 00339 } 00340 00341 /** 00342 * parse attributes of a netlink message 00343 * @arg nlh netlink message header 00344 * @arg hdrlen length of family specific header 00345 * @arg tb destination array with maxtype+1 elements 00346 * @arg maxtype maximum attribute type to be expected 00347 * @arg policy validation policy 00348 * 00349 * See nla_parse() 00350 */ 00351 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], 00352 int maxtype, struct nla_policy *policy) 00353 { 00354 if (!nlmsg_valid_hdr(nlh, hdrlen)) 00355 return -NLE_MSG_TOOSHORT; 00356 00357 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), 00358 nlmsg_attrlen(nlh, hdrlen), policy); 00359 } 00360 00361 /** 00362 * nlmsg_find_attr - find a specific attribute in a netlink message 00363 * @arg nlh netlink message header 00364 * @arg hdrlen length of familiy specific header 00365 * @arg attrtype type of attribute to look for 00366 * 00367 * Returns the first attribute which matches the specified type. 00368 */ 00369 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) 00370 { 00371 return nla_find(nlmsg_attrdata(nlh, hdrlen), 00372 nlmsg_attrlen(nlh, hdrlen), attrtype); 00373 } 00374 00375 /** 00376 * nlmsg_validate - validate a netlink message including attributes 00377 * @arg nlh netlinket message header 00378 * @arg hdrlen length of familiy specific header 00379 * @arg maxtype maximum attribute type to be expected 00380 * @arg policy validation policy 00381 */ 00382 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, 00383 struct nla_policy *policy) 00384 { 00385 if (!nlmsg_valid_hdr(nlh, hdrlen)) 00386 return -NLE_MSG_TOOSHORT; 00387 00388 return nla_validate(nlmsg_attrdata(nlh, hdrlen), 00389 nlmsg_attrlen(nlh, hdrlen), maxtype, policy); 00390 } 00391 00392 /** @} */ 00393 00394 /** 00395 * @name Message Building/Access 00396 * @{ 00397 */ 00398 00399 static struct nl_msg *__nlmsg_alloc(size_t len) 00400 { 00401 struct nl_msg *nm; 00402 00403 if (len < sizeof(struct nlmsghdr)) 00404 len = sizeof(struct nlmsghdr); 00405 00406 nm = calloc(1, sizeof(*nm)); 00407 if (!nm) 00408 goto errout; 00409 00410 nm->nm_refcnt = 1; 00411 00412 nm->nm_nlh = calloc(1, len); 00413 if (!nm->nm_nlh) 00414 goto errout; 00415 00416 memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr)); 00417 00418 nm->nm_protocol = -1; 00419 nm->nm_size = len; 00420 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); 00421 00422 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); 00423 00424 return nm; 00425 errout: 00426 free(nm); 00427 return NULL; 00428 } 00429 00430 /** 00431 * Allocate a new netlink message with the default maximum payload size. 00432 * 00433 * Allocates a new netlink message without any further payload. The 00434 * maximum payload size defaults to PAGESIZE or as otherwise specified 00435 * with nlmsg_set_default_size(). 00436 * 00437 * @return Newly allocated netlink message or NULL. 00438 */ 00439 struct nl_msg *nlmsg_alloc(void) 00440 { 00441 return __nlmsg_alloc(default_msg_size); 00442 } 00443 00444 /** 00445 * Allocate a new netlink message with maximum payload size specified. 00446 */ 00447 struct nl_msg *nlmsg_alloc_size(size_t max) 00448 { 00449 return __nlmsg_alloc(max); 00450 } 00451 00452 /** 00453 * Allocate a new netlink message and inherit netlink message header 00454 * @arg hdr Netlink message header template 00455 * 00456 * Allocates a new netlink message and inherits the original message 00457 * header. If \a hdr is not NULL it will be used as a template for 00458 * the netlink message header, otherwise the header is left blank. 00459 * 00460 * @return Newly allocated netlink message or NULL 00461 */ 00462 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) 00463 { 00464 struct nl_msg *nm; 00465 00466 nm = nlmsg_alloc(); 00467 if (nm && hdr) { 00468 struct nlmsghdr *new = nm->nm_nlh; 00469 00470 new->nlmsg_type = hdr->nlmsg_type; 00471 new->nlmsg_flags = hdr->nlmsg_flags; 00472 new->nlmsg_seq = hdr->nlmsg_seq; 00473 new->nlmsg_pid = hdr->nlmsg_pid; 00474 } 00475 00476 return nm; 00477 } 00478 00479 /** 00480 * Allocate a new netlink message 00481 * @arg nlmsgtype Netlink message type 00482 * @arg flags Message flags. 00483 * 00484 * @return Newly allocated netlink message or NULL. 00485 */ 00486 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) 00487 { 00488 struct nl_msg *msg; 00489 struct nlmsghdr nlh = { 00490 .nlmsg_type = nlmsgtype, 00491 .nlmsg_flags = flags, 00492 }; 00493 00494 msg = nlmsg_inherit(&nlh); 00495 if (msg) 00496 NL_DBG(2, "msg %p: Allocated new simple message\n", msg); 00497 00498 return msg; 00499 } 00500 00501 /** 00502 * Set the default maximum message payload size for allocated messages 00503 * @arg max Size of payload in bytes. 00504 */ 00505 void nlmsg_set_default_size(size_t max) 00506 { 00507 if (max < nlmsg_total_size(0)) 00508 max = nlmsg_total_size(0); 00509 00510 default_msg_size = max; 00511 } 00512 00513 /** 00514 * Convert a netlink message received from a netlink socket to a nl_msg 00515 * @arg hdr Netlink message received from netlink socket. 00516 * 00517 * Allocates a new netlink message and copies all of the data pointed to 00518 * by \a hdr into the new message object. 00519 * 00520 * @return Newly allocated netlink message or NULL. 00521 */ 00522 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) 00523 { 00524 struct nl_msg *nm; 00525 00526 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); 00527 if (!nm) 00528 goto errout; 00529 00530 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); 00531 00532 return nm; 00533 errout: 00534 nlmsg_free(nm); 00535 return NULL; 00536 } 00537 00538 /** 00539 * Reserve room for additional data in a netlink message 00540 * @arg n netlink message 00541 * @arg len length of additional data to reserve room for 00542 * @arg pad number of bytes to align data to 00543 * 00544 * Reserves room for additional data at the tail of the an 00545 * existing netlink message. Eventual padding required will 00546 * be zeroed out. 00547 * 00548 * @return Pointer to start of additional data tailroom or NULL. 00549 */ 00550 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) 00551 { 00552 void *buf = n->nm_nlh; 00553 size_t nlmsg_len = n->nm_nlh->nlmsg_len; 00554 size_t tlen; 00555 00556 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 00557 00558 if ((tlen + nlmsg_len) > n->nm_size) 00559 return NULL; 00560 00561 buf += nlmsg_len; 00562 n->nm_nlh->nlmsg_len += tlen; 00563 00564 if (tlen > len) 00565 memset(buf + len, 0, tlen - len); 00566 00567 NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n", 00568 n, tlen, len, pad, n->nm_nlh->nlmsg_len); 00569 00570 return buf; 00571 } 00572 00573 /** 00574 * Append data to tail of a netlink message 00575 * @arg n netlink message 00576 * @arg data data to add 00577 * @arg len length of data 00578 * @arg pad Number of bytes to align data to. 00579 * 00580 * Extends the netlink message as needed and appends the data of given 00581 * length to the message. 00582 * 00583 * @return 0 on success or a negative error code 00584 */ 00585 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 00586 { 00587 void *tmp; 00588 00589 tmp = nlmsg_reserve(n, len, pad); 00590 if (tmp == NULL) 00591 return -NLE_NOMEM; 00592 00593 memcpy(tmp, data, len); 00594 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 00595 00596 return 0; 00597 } 00598 00599 /** 00600 * Expand maximum payload size of a netlink message 00601 * @arg n Netlink message. 00602 * @arg newlen New maximum payload size. 00603 * 00604 * Reallocates the payload section of a netlink message and increases 00605 * the maximum payload size of the message. 00606 * 00607 * @note Any pointers pointing to old payload block will be stale and 00608 * need to be refetched. Therfore, do not expand while constructing 00609 * nested attributes or while reserved data blocks are held. 00610 * 00611 * @return 0 on success or a negative error code. 00612 */ 00613 int nlmsg_expand(struct nl_msg *n, size_t newlen) 00614 { 00615 void *tmp; 00616 00617 if (newlen <= n->nm_size) 00618 return -NLE_INVAL; 00619 00620 tmp = realloc(n->nm_nlh, newlen); 00621 if (tmp == NULL) 00622 return -NLE_NOMEM; 00623 00624 n->nm_nlh = tmp; 00625 n->nm_size = newlen; 00626 00627 return 0; 00628 } 00629 00630 /** 00631 * Add a netlink message header to a netlink message 00632 * @arg n netlink message 00633 * @arg pid netlink process id or NL_AUTO_PID 00634 * @arg seq sequence number of message or NL_AUTO_SEQ 00635 * @arg type message type 00636 * @arg payload length of message payload 00637 * @arg flags message flags 00638 * 00639 * Adds or overwrites the netlink message header in an existing message 00640 * object. If \a payload is greater-than zero additional room will be 00641 * reserved, f.e. for family specific headers. It can be accesed via 00642 * nlmsg_data(). 00643 * 00644 * @return A pointer to the netlink message header or NULL. 00645 */ 00646 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 00647 int type, int payload, int flags) 00648 { 00649 struct nlmsghdr *nlh; 00650 00651 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 00652 BUG(); 00653 00654 nlh = (struct nlmsghdr *) n->nm_nlh; 00655 nlh->nlmsg_type = type; 00656 nlh->nlmsg_flags = flags; 00657 nlh->nlmsg_pid = pid; 00658 nlh->nlmsg_seq = seq; 00659 00660 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 00661 "seq=%d\n", n, type, flags, pid, seq); 00662 00663 if (payload > 0 && 00664 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 00665 return NULL; 00666 00667 return nlh; 00668 } 00669 00670 /** 00671 * Return actual netlink message 00672 * @arg n netlink message 00673 * 00674 * Returns the actual netlink message casted to the type of the netlink 00675 * message header. 00676 * 00677 * @return A pointer to the netlink message. 00678 */ 00679 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) 00680 { 00681 return n->nm_nlh; 00682 } 00683 00684 /** 00685 * Acquire a reference on a netlink message 00686 * @arg msg message to acquire reference from 00687 */ 00688 void nlmsg_get(struct nl_msg *msg) 00689 { 00690 msg->nm_refcnt++; 00691 NL_DBG(4, "New reference to message %p, total %d\n", 00692 msg, msg->nm_refcnt); 00693 } 00694 00695 /** 00696 * Release a reference from an netlink message 00697 * @arg msg message to release reference from 00698 * 00699 * Frees memory after the last reference has been released. 00700 */ 00701 void nlmsg_free(struct nl_msg *msg) 00702 { 00703 if (!msg) 00704 return; 00705 00706 msg->nm_refcnt--; 00707 NL_DBG(4, "Returned message reference %p, %d remaining\n", 00708 msg, msg->nm_refcnt); 00709 00710 if (msg->nm_refcnt < 0) 00711 BUG(); 00712 00713 if (msg->nm_refcnt <= 0) { 00714 free(msg->nm_nlh); 00715 free(msg); 00716 NL_DBG(2, "msg %p: Freed\n", msg); 00717 } 00718 } 00719 00720 /** @} */ 00721 00722 /** 00723 * @name Attributes 00724 * @{ 00725 */ 00726 00727 void nlmsg_set_proto(struct nl_msg *msg, int protocol) 00728 { 00729 msg->nm_protocol = protocol; 00730 } 00731 00732 int nlmsg_get_proto(struct nl_msg *msg) 00733 { 00734 return msg->nm_protocol; 00735 } 00736 00737 size_t nlmsg_get_max_size(struct nl_msg *msg) 00738 { 00739 return msg->nm_size; 00740 } 00741 00742 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) 00743 { 00744 memcpy(&msg->nm_src, addr, sizeof(*addr)); 00745 } 00746 00747 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) 00748 { 00749 return &msg->nm_src; 00750 } 00751 00752 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) 00753 { 00754 memcpy(&msg->nm_dst, addr, sizeof(*addr)); 00755 } 00756 00757 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) 00758 { 00759 return &msg->nm_dst; 00760 } 00761 00762 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) 00763 { 00764 memcpy(&msg->nm_creds, creds, sizeof(*creds)); 00765 msg->nm_flags |= NL_MSG_CRED_PRESENT; 00766 } 00767 00768 struct ucred *nlmsg_get_creds(struct nl_msg *msg) 00769 { 00770 if (msg->nm_flags & NL_MSG_CRED_PRESENT) 00771 return &msg->nm_creds; 00772 return NULL; 00773 } 00774 00775 /** @} */ 00776 00777 /** 00778 * @name Netlink Message Type Translations 00779 * @{ 00780 */ 00781 00782 static const struct trans_tbl nl_msgtypes[] = { 00783 __ADD(NLMSG_NOOP,NOOP) 00784 __ADD(NLMSG_ERROR,ERROR) 00785 __ADD(NLMSG_DONE,DONE) 00786 __ADD(NLMSG_OVERRUN,OVERRUN) 00787 }; 00788 00789 char *nl_nlmsgtype2str(int type, char *buf, size_t size) 00790 { 00791 return __type2str(type, buf, size, nl_msgtypes, 00792 ARRAY_SIZE(nl_msgtypes)); 00793 } 00794 00795 int nl_str2nlmsgtype(const char *name) 00796 { 00797 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); 00798 } 00799 00800 /** @} */ 00801 00802 /** 00803 * @name Netlink Message Flags Translations 00804 * @{ 00805 */ 00806 00807 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) 00808 { 00809 memset(buf, 0, len); 00810 00811 #define PRINT_FLAG(f) \ 00812 if (flags & NLM_F_##f) { \ 00813 flags &= ~NLM_F_##f; \ 00814 strncat(buf, #f, len - strlen(buf) - 1); \ 00815 if (flags) \ 00816 strncat(buf, ",", len - strlen(buf) - 1); \ 00817 } 00818 00819 PRINT_FLAG(REQUEST); 00820 PRINT_FLAG(MULTI); 00821 PRINT_FLAG(ACK); 00822 PRINT_FLAG(ECHO); 00823 PRINT_FLAG(ROOT); 00824 PRINT_FLAG(MATCH); 00825 PRINT_FLAG(ATOMIC); 00826 PRINT_FLAG(REPLACE); 00827 PRINT_FLAG(EXCL); 00828 PRINT_FLAG(CREATE); 00829 PRINT_FLAG(APPEND); 00830 00831 if (flags) { 00832 char s[32]; 00833 snprintf(s, sizeof(s), "0x%x", flags); 00834 strncat(buf, s, len - strlen(buf) - 1); 00835 } 00836 #undef PRINT_FLAG 00837 00838 return buf; 00839 } 00840 00841 /** @} */ 00842 00843 /** 00844 * @name Direct Parsing 00845 * @{ 00846 */ 00847 00848 /** @cond SKIP */ 00849 struct dp_xdata { 00850 void (*cb)(struct nl_object *, void *); 00851 void *arg; 00852 }; 00853 /** @endcond */ 00854 00855 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 00856 { 00857 struct dp_xdata *x = p->pp_arg; 00858 00859 x->cb(obj, x->arg); 00860 return 0; 00861 } 00862 00863 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 00864 void *arg) 00865 { 00866 struct nl_cache_ops *ops; 00867 struct nl_parser_param p = { 00868 .pp_cb = parse_cb 00869 }; 00870 struct dp_xdata x = { 00871 .cb = cb, 00872 .arg = arg, 00873 }; 00874 00875 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 00876 nlmsg_hdr(msg)->nlmsg_type); 00877 if (ops == NULL) 00878 return -NLE_MSGTYPE_NOSUPPORT; 00879 p.pp_arg = &x; 00880 00881 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 00882 } 00883 00884 /** @} */ 00885 00886 /** 00887 * @name Dumping 00888 * @{ 00889 */ 00890 00891 static void prefix_line(FILE *ofd, int prefix) 00892 { 00893 int i; 00894 00895 for (i = 0; i < prefix; i++) 00896 fprintf(ofd, " "); 00897 } 00898 00899 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) 00900 { 00901 int i, a, c, limit; 00902 char ascii[21] = {0}; 00903 00904 limit = 18 - (prefix * 2); 00905 prefix_line(ofd, prefix); 00906 fprintf(ofd, " "); 00907 00908 for (i = 0, a = 0, c = 0; i < len; i++) { 00909 int v = *(uint8_t *) (start + i); 00910 00911 fprintf(ofd, "%02x ", v); 00912 ascii[a++] = isprint(v) ? v : '.'; 00913 00914 if (c == limit-1) { 00915 fprintf(ofd, "%s\n", ascii); 00916 if (i < (len - 1)) { 00917 prefix_line(ofd, prefix); 00918 fprintf(ofd, " "); 00919 } 00920 a = c = 0; 00921 memset(ascii, 0, sizeof(ascii)); 00922 } else 00923 c++; 00924 } 00925 00926 if (c != 0) { 00927 for (i = 0; i < (limit - c); i++) 00928 fprintf(ofd, " "); 00929 fprintf(ofd, "%s\n", ascii); 00930 } 00931 } 00932 00933 static void print_hdr(FILE *ofd, struct nl_msg *msg) 00934 { 00935 struct nlmsghdr *nlh = nlmsg_hdr(msg); 00936 struct nl_cache_ops *ops; 00937 struct nl_msgtype *mt; 00938 char buf[128]; 00939 00940 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); 00941 00942 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); 00943 if (ops) { 00944 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); 00945 if (!mt) 00946 BUG(); 00947 00948 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); 00949 } else 00950 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); 00951 00952 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf); 00953 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, 00954 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); 00955 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); 00956 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); 00957 00958 } 00959 00960 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, 00961 int prefix) 00962 { 00963 int rem; 00964 struct nlattr *nla; 00965 00966 nla_for_each_attr(nla, attrs, attrlen, rem) { 00967 int padlen, alen = nla_len(nla); 00968 00969 prefix_line(ofd, prefix); 00970 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), 00971 nla->nla_type & NLA_F_NESTED ? " NESTED" : "", 00972 alen); 00973 00974 if (nla->nla_type & NLA_F_NESTED) 00975 dump_attrs(ofd, nla_data(nla), alen, prefix+1); 00976 else 00977 dump_hex(ofd, nla_data(nla), alen, prefix); 00978 00979 padlen = nla_padlen(alen); 00980 if (padlen > 0) { 00981 prefix_line(ofd, prefix); 00982 fprintf(ofd, " [PADDING] %d octets\n", 00983 padlen); 00984 dump_hex(ofd, nla_data(nla) + alen, 00985 padlen, prefix); 00986 } 00987 } 00988 00989 if (rem) { 00990 prefix_line(ofd, prefix); 00991 fprintf(ofd, " [LEFTOVER] %d octets\n", rem); 00992 } 00993 } 00994 00995 /** 00996 * Dump message in human readable format to file descriptor 00997 * @arg msg Message to print 00998 * @arg ofd File descriptor. 00999 */ 01000 void nl_msg_dump(struct nl_msg *msg, FILE *ofd) 01001 { 01002 struct nlmsghdr *hdr = nlmsg_hdr(msg); 01003 01004 fprintf(ofd, 01005 "-------------------------- BEGIN NETLINK MESSAGE " 01006 "---------------------------\n"); 01007 01008 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); 01009 print_hdr(ofd, msg); 01010 01011 if (hdr->nlmsg_type == NLMSG_ERROR && 01012 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { 01013 struct nl_msg *errmsg; 01014 struct nlmsgerr *err = nlmsg_data(hdr); 01015 01016 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); 01017 fprintf(ofd, " .error = %d \"%s\"\n", err->error, 01018 strerror(-err->error)); 01019 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); 01020 01021 errmsg = nlmsg_inherit(&err->msg); 01022 print_hdr(ofd, errmsg); 01023 nlmsg_free(errmsg); 01024 } else if (nlmsg_len(hdr) > 0) { 01025 struct nl_cache_ops *ops; 01026 int payloadlen = nlmsg_len(hdr); 01027 int attrlen = 0; 01028 01029 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 01030 hdr->nlmsg_type); 01031 if (ops) { 01032 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01033 payloadlen -= attrlen; 01034 } 01035 01036 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); 01037 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0); 01038 01039 if (attrlen) { 01040 struct nlattr *attrs; 01041 int attrlen; 01042 01043 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); 01044 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 01045 dump_attrs(ofd, attrs, attrlen, 0); 01046 } 01047 } 01048 01049 fprintf(ofd, 01050 "--------------------------- END NETLINK MESSAGE " 01051 "---------------------------\n"); 01052 } 01053 01054 /** @} */ 01055 01056 /** @} */