libnl 1.1
|
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-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup nl 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 >= 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 nl_errno(EINVAL); 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 nl_errno(EINVAL); 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_nlh = calloc(1, len); 00376 if (!nm->nm_nlh) 00377 goto errout; 00378 00379 nm->nm_protocol = -1; 00380 nm->nm_size = len; 00381 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); 00382 00383 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); 00384 00385 return nm; 00386 errout: 00387 free(nm); 00388 nl_errno(ENOMEM); 00389 return NULL; 00390 } 00391 00392 /** 00393 * Allocate a new netlink message with the default maximum payload size. 00394 * 00395 * Allocates a new netlink message without any further payload. The 00396 * maximum payload size defaults to PAGESIZE or as otherwise specified 00397 * with nlmsg_set_default_size(). 00398 * 00399 * @return Newly allocated netlink message or NULL. 00400 */ 00401 struct nl_msg *nlmsg_alloc(void) 00402 { 00403 return __nlmsg_alloc(default_msg_size); 00404 } 00405 00406 /** 00407 * Allocate a new netlink message with maximum payload size specified. 00408 */ 00409 struct nl_msg *nlmsg_alloc_size(size_t max) 00410 { 00411 return __nlmsg_alloc(max); 00412 } 00413 00414 /** 00415 * Allocate a new netlink message and inherit netlink message header 00416 * @arg hdr Netlink message header template 00417 * 00418 * Allocates a new netlink message and inherits the original message 00419 * header. If \a hdr is not NULL it will be used as a template for 00420 * the netlink message header, otherwise the header is left blank. 00421 * 00422 * @return Newly allocated netlink message or NULL 00423 */ 00424 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) 00425 { 00426 struct nl_msg *nm; 00427 00428 nm = nlmsg_alloc(); 00429 if (nm && hdr) { 00430 struct nlmsghdr *new = nm->nm_nlh; 00431 00432 new->nlmsg_type = hdr->nlmsg_type; 00433 new->nlmsg_flags = hdr->nlmsg_flags; 00434 new->nlmsg_seq = hdr->nlmsg_seq; 00435 new->nlmsg_pid = hdr->nlmsg_pid; 00436 } 00437 00438 return nm; 00439 } 00440 00441 /** 00442 * Allocate a new netlink message 00443 * @arg nlmsgtype Netlink message type 00444 * @arg flags Message flags. 00445 * 00446 * @return Newly allocated netlink message or NULL. 00447 */ 00448 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) 00449 { 00450 struct nl_msg *msg; 00451 struct nlmsghdr nlh = { 00452 .nlmsg_type = nlmsgtype, 00453 .nlmsg_flags = flags, 00454 }; 00455 00456 msg = nlmsg_inherit(&nlh); 00457 if (msg) 00458 NL_DBG(2, "msg %p: Allocated new simple message\n", msg); 00459 00460 return msg; 00461 } 00462 00463 /** 00464 * Set the default maximum message payload size for allocated messages 00465 * @arg max Size of payload in bytes. 00466 */ 00467 void nlmsg_set_default_size(size_t max) 00468 { 00469 if (max < nlmsg_total_size(0)) 00470 max = nlmsg_total_size(0); 00471 00472 default_msg_size = max; 00473 } 00474 00475 /** 00476 * Convert a netlink message received from a netlink socket to a nl_msg 00477 * @arg hdr Netlink message received from netlink socket. 00478 * 00479 * Allocates a new netlink message and copies all of the data pointed to 00480 * by \a hdr into the new message object. 00481 * 00482 * @return Newly allocated netlink message or NULL. 00483 */ 00484 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) 00485 { 00486 struct nl_msg *nm; 00487 00488 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); 00489 if (!nm) 00490 goto errout; 00491 00492 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); 00493 00494 return nm; 00495 errout: 00496 nlmsg_free(nm); 00497 return NULL; 00498 } 00499 00500 /** 00501 * Reserve room for additional data in a netlink message 00502 * @arg n netlink message 00503 * @arg len length of additional data to reserve room for 00504 * @arg pad number of bytes to align data to 00505 * 00506 * Reserves room for additional data at the tail of the an 00507 * existing netlink message. Eventual padding required will 00508 * be zeroed out. 00509 * 00510 * @return Pointer to start of additional data tailroom or NULL. 00511 */ 00512 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) 00513 { 00514 void *buf = n->nm_nlh; 00515 size_t nlmsg_len = n->nm_nlh->nlmsg_len; 00516 size_t tlen; 00517 00518 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 00519 00520 if ((tlen + nlmsg_len) > n->nm_size) { 00521 nl_errno(ENOBUFS); 00522 return NULL; 00523 } 00524 00525 buf += nlmsg_len; 00526 n->nm_nlh->nlmsg_len += tlen; 00527 00528 if (tlen > len) 00529 memset(buf + len, 0, tlen - len); 00530 00531 NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n", 00532 n, len, pad, n->nm_nlh->nlmsg_len); 00533 00534 return buf; 00535 } 00536 00537 /** 00538 * Append data to tail of a netlink message 00539 * @arg n netlink message 00540 * @arg data data to add 00541 * @arg len length of data 00542 * @arg pad Number of bytes to align data to. 00543 * 00544 * Extends the netlink message as needed and appends the data of given 00545 * length to the message. 00546 * 00547 * @return 0 on success or a negative error code 00548 */ 00549 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 00550 { 00551 void *tmp; 00552 00553 tmp = nlmsg_reserve(n, len, pad); 00554 if (tmp == NULL) 00555 return nl_errno(ENOMEM); 00556 00557 memcpy(tmp, data, len); 00558 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 00559 00560 return 0; 00561 } 00562 00563 /** 00564 * Expand maximum payload size of a netlink message 00565 * @arg n Netlink message. 00566 * @arg newlen New maximum payload size. 00567 * 00568 * Reallocates the payload section of a netlink message and increases 00569 * the maximum payload size of the message. 00570 * 00571 * @note Any pointers pointing to old payload block will be stale and 00572 * need to be refetched. Therfore, do not expand while constructing 00573 * nested attributes or while reserved data blocks are held. 00574 * 00575 * @return 0 on success or a negative error code. 00576 */ 00577 int nlmsg_expand(struct nl_msg *n, size_t newlen) 00578 { 00579 void *tmp; 00580 00581 if (newlen <= n->nm_size) 00582 return nl_errno(EINVAL); 00583 00584 tmp = realloc(n->nm_nlh, newlen); 00585 if (tmp == NULL) 00586 return nl_errno(ENOMEM); 00587 00588 n->nm_nlh = tmp; 00589 n->nm_size = newlen; 00590 00591 return 0; 00592 } 00593 00594 /** 00595 * Add a netlink message header to a netlink message 00596 * @arg n netlink message 00597 * @arg pid netlink process id or NL_AUTO_PID 00598 * @arg seq sequence number of message or NL_AUTO_SEQ 00599 * @arg type message type 00600 * @arg payload length of message payload 00601 * @arg flags message flags 00602 * 00603 * Adds or overwrites the netlink message header in an existing message 00604 * object. If \a payload is greater-than zero additional room will be 00605 * reserved, f.e. for family specific headers. It can be accesed via 00606 * nlmsg_data(). 00607 * 00608 * @return A pointer to the netlink message header or NULL. 00609 */ 00610 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 00611 int type, int payload, int flags) 00612 { 00613 struct nlmsghdr *nlh; 00614 00615 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 00616 BUG(); 00617 00618 nlh = (struct nlmsghdr *) n->nm_nlh; 00619 nlh->nlmsg_type = type; 00620 nlh->nlmsg_flags = flags; 00621 nlh->nlmsg_pid = pid; 00622 nlh->nlmsg_seq = seq; 00623 00624 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 00625 "seq=%d\n", n, type, flags, pid, seq); 00626 00627 if (payload > 0 && 00628 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 00629 return NULL; 00630 00631 return nlh; 00632 } 00633 00634 /** 00635 * Return actual netlink message 00636 * @arg n netlink message 00637 * 00638 * Returns the actual netlink message casted to the type of the netlink 00639 * message header. 00640 * 00641 * @return A pointer to the netlink message. 00642 */ 00643 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) 00644 { 00645 return n->nm_nlh; 00646 } 00647 00648 /** 00649 * Free a netlink message 00650 * @arg n netlink message 00651 * 00652 * Destroys a netlink message and frees up all used memory. 00653 * 00654 * @pre The message must be unused. 00655 */ 00656 void nlmsg_free(struct nl_msg *n) 00657 { 00658 if (!n) 00659 return; 00660 00661 free(n->nm_nlh); 00662 free(n); 00663 NL_DBG(2, "msg %p: Freed\n", n); 00664 } 00665 00666 /** @} */ 00667 00668 /** 00669 * @name Attributes 00670 * @{ 00671 */ 00672 00673 void nlmsg_set_proto(struct nl_msg *msg, int protocol) 00674 { 00675 msg->nm_protocol = protocol; 00676 } 00677 00678 int nlmsg_get_proto(struct nl_msg *msg) 00679 { 00680 return msg->nm_protocol; 00681 } 00682 00683 size_t nlmsg_get_max_size(struct nl_msg *msg) 00684 { 00685 return msg->nm_size; 00686 } 00687 00688 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) 00689 { 00690 memcpy(&msg->nm_src, addr, sizeof(*addr)); 00691 } 00692 00693 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) 00694 { 00695 return &msg->nm_src; 00696 } 00697 00698 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) 00699 { 00700 memcpy(&msg->nm_dst, addr, sizeof(*addr)); 00701 } 00702 00703 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) 00704 { 00705 return &msg->nm_dst; 00706 } 00707 00708 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) 00709 { 00710 memcpy(&msg->nm_creds, creds, sizeof(*creds)); 00711 msg->nm_flags |= NL_MSG_CRED_PRESENT; 00712 } 00713 00714 struct ucred *nlmsg_get_creds(struct nl_msg *msg) 00715 { 00716 if (msg->nm_flags & NL_MSG_CRED_PRESENT) 00717 return &msg->nm_creds; 00718 return NULL; 00719 } 00720 00721 /** @} */ 00722 00723 /** 00724 * @name Netlink Message Type Translations 00725 * @{ 00726 */ 00727 00728 static struct trans_tbl nl_msgtypes[] = { 00729 __ADD(NLMSG_NOOP,NOOP) 00730 __ADD(NLMSG_ERROR,ERROR) 00731 __ADD(NLMSG_DONE,DONE) 00732 __ADD(NLMSG_OVERRUN,OVERRUN) 00733 }; 00734 00735 char *nl_nlmsgtype2str(int type, char *buf, size_t size) 00736 { 00737 return __type2str(type, buf, size, nl_msgtypes, 00738 ARRAY_SIZE(nl_msgtypes)); 00739 } 00740 00741 int nl_str2nlmsgtype(const char *name) 00742 { 00743 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); 00744 } 00745 00746 /** @} */ 00747 00748 /** 00749 * @name Netlink Message Flags Translations 00750 * @{ 00751 */ 00752 00753 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) 00754 { 00755 memset(buf, 0, len); 00756 00757 #define PRINT_FLAG(f) \ 00758 if (flags & NLM_F_##f) { \ 00759 flags &= ~NLM_F_##f; \ 00760 strncat(buf, #f, len - strlen(buf) - 1); \ 00761 if (flags) \ 00762 strncat(buf, ",", len - strlen(buf) - 1); \ 00763 } 00764 00765 PRINT_FLAG(REQUEST); 00766 PRINT_FLAG(MULTI); 00767 PRINT_FLAG(ACK); 00768 PRINT_FLAG(ECHO); 00769 PRINT_FLAG(ROOT); 00770 PRINT_FLAG(MATCH); 00771 PRINT_FLAG(ATOMIC); 00772 PRINT_FLAG(REPLACE); 00773 PRINT_FLAG(EXCL); 00774 PRINT_FLAG(CREATE); 00775 PRINT_FLAG(APPEND); 00776 00777 if (flags) { 00778 char s[32]; 00779 snprintf(s, sizeof(s), "0x%x", flags); 00780 strncat(buf, s, len - strlen(buf) - 1); 00781 } 00782 #undef PRINT_FLAG 00783 00784 return buf; 00785 } 00786 00787 /** @} */ 00788 00789 /** 00790 * @name Direct Parsing 00791 * @{ 00792 */ 00793 00794 /** @cond SKIP */ 00795 struct dp_xdata { 00796 void (*cb)(struct nl_object *, void *); 00797 void *arg; 00798 }; 00799 /** @endcond */ 00800 00801 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 00802 { 00803 struct dp_xdata *x = p->pp_arg; 00804 00805 x->cb(obj, x->arg); 00806 return 0; 00807 } 00808 00809 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 00810 void *arg) 00811 { 00812 struct nl_cache_ops *ops; 00813 struct nl_parser_param p = { 00814 .pp_cb = parse_cb 00815 }; 00816 struct dp_xdata x = { 00817 .cb = cb, 00818 .arg = arg, 00819 }; 00820 00821 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 00822 nlmsg_hdr(msg)->nlmsg_type); 00823 if (ops == NULL) 00824 return nl_error(ENOENT, "Unknown message type %d", 00825 nlmsg_hdr(msg)->nlmsg_type); 00826 p.pp_arg = &x; 00827 00828 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 00829 } 00830 00831 /** @} */ 00832 00833 /** 00834 * @name Dumping 00835 * @{ 00836 */ 00837 00838 static void prefix_line(FILE *ofd, int prefix) 00839 { 00840 int i; 00841 00842 for (i = 0; i < prefix; i++) 00843 fprintf(ofd, " "); 00844 } 00845 00846 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) 00847 { 00848 int i, a, c, limit; 00849 char ascii[21] = {0}; 00850 00851 limit = 18 - (prefix * 2); 00852 prefix_line(ofd, prefix); 00853 fprintf(ofd, " "); 00854 00855 for (i = 0, a = 0, c = 0; i < len; i++) { 00856 int v = *(uint8_t *) (start + i); 00857 00858 fprintf(ofd, "%02x ", v); 00859 ascii[a++] = isprint(v) ? v : '.'; 00860 00861 if (c == limit-1) { 00862 fprintf(ofd, "%s\n", ascii); 00863 if (i < (len - 1)) { 00864 prefix_line(ofd, prefix); 00865 fprintf(ofd, " "); 00866 } 00867 a = c = 0; 00868 memset(ascii, 0, sizeof(ascii)); 00869 } else 00870 c++; 00871 } 00872 00873 if (c != 0) { 00874 for (i = 0; i < (limit - c); i++) 00875 fprintf(ofd, " "); 00876 fprintf(ofd, "%s\n", ascii); 00877 } 00878 } 00879 00880 static void print_hdr(FILE *ofd, struct nl_msg *msg) 00881 { 00882 struct nlmsghdr *nlh = nlmsg_hdr(msg); 00883 struct nl_cache_ops *ops; 00884 struct nl_msgtype *mt; 00885 char buf[128]; 00886 00887 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); 00888 00889 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); 00890 if (ops) { 00891 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); 00892 if (!mt) 00893 BUG(); 00894 00895 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); 00896 } else 00897 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); 00898 00899 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf); 00900 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, 00901 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); 00902 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); 00903 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); 00904 00905 } 00906 00907 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, 00908 int prefix) 00909 { 00910 int rem; 00911 struct nlattr *nla; 00912 00913 nla_for_each_attr(nla, attrs, attrlen, rem) { 00914 int padlen, alen = nla_len(nla); 00915 00916 prefix_line(ofd, prefix); 00917 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), 00918 nla->nla_type & NLA_F_NESTED ? " NESTED" : "", 00919 alen); 00920 00921 if (nla->nla_type & NLA_F_NESTED) 00922 dump_attrs(ofd, nla_data(nla), alen, prefix+1); 00923 else 00924 dump_hex(ofd, nla_data(nla), alen, prefix); 00925 00926 padlen = nla_padlen(alen); 00927 if (padlen > 0) { 00928 prefix_line(ofd, prefix); 00929 fprintf(ofd, " [PADDING] %d octets\n", 00930 padlen); 00931 dump_hex(ofd, nla_data(nla) + alen, 00932 padlen, prefix); 00933 } 00934 } 00935 00936 if (rem) { 00937 prefix_line(ofd, prefix); 00938 fprintf(ofd, " [LEFTOVER] %d octets\n", rem); 00939 } 00940 } 00941 00942 /** 00943 * Dump message in human readable format to file descriptor 00944 * @arg msg Message to print 00945 * @arg ofd File descriptor. 00946 */ 00947 void nl_msg_dump(struct nl_msg *msg, FILE *ofd) 00948 { 00949 struct nlmsghdr *hdr = nlmsg_hdr(msg); 00950 00951 fprintf(ofd, 00952 "-------------------------- BEGIN NETLINK MESSAGE " 00953 "---------------------------\n"); 00954 00955 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); 00956 print_hdr(ofd, msg); 00957 00958 if (hdr->nlmsg_type == NLMSG_ERROR && 00959 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { 00960 struct nl_msg *errmsg; 00961 struct nlmsgerr *err = nlmsg_data(hdr); 00962 00963 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); 00964 fprintf(ofd, " .error = %d \"%s\"\n", err->error, 00965 strerror(-err->error)); 00966 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); 00967 00968 errmsg = nlmsg_inherit(&err->msg); 00969 print_hdr(ofd, errmsg); 00970 nlmsg_free(errmsg); 00971 } else if (nlmsg_len(hdr) > 0) { 00972 struct nl_cache_ops *ops; 00973 int payloadlen = nlmsg_len(hdr); 00974 int attrlen = 0; 00975 00976 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 00977 hdr->nlmsg_type); 00978 if (ops) { 00979 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 00980 payloadlen -= attrlen; 00981 } 00982 00983 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); 00984 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0); 00985 00986 if (attrlen) { 00987 struct nlattr *attrs; 00988 int attrlen; 00989 00990 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); 00991 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 00992 dump_attrs(ofd, attrs, attrlen, 0); 00993 } 00994 } 00995 00996 fprintf(ofd, 00997 "--------------------------- END NETLINK MESSAGE " 00998 "---------------------------\n"); 00999 } 01000 01001 /** @} */ 01002 01003 /** @} */