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