1 /* 2 * lib/msg.c Netlink Messages Interface 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12 /** 13 * @ingroup core 14 * @defgroup msg Messages 15 * Netlink Message Construction/Parsing Interface 16 * 17 * The following information is partly extracted from RFC3549 18 * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt) 19 * 20 * @par Message Format 21 * Netlink messages consist of a byte stream with one or multiple 22 * Netlink headers and an associated payload. If the payload is too big 23 * to fit into a single message it, can be split over multiple Netlink 24 * messages, collectively called a multipart message. For multipart 25 * messages, the first and all following headers have the \c NLM_F_MULTI 26 * Netlink header flag set, except for the last header which has the 27 * Netlink header type \c NLMSG_DONE. 28 * 29 * @par 30 * The Netlink message header (\link nlmsghdr struct nlmsghdr\endlink) is shown below. 31 * @code 32 * 0 1 2 3 33 * 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 34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35 * | Length | 36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37 * | Type | Flags | 38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 39 * | Sequence Number | 40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 41 * | Process ID (PID) | 42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 * @endcode 44 * 45 * @par 46 * The netlink message header and payload must be aligned properly: 47 * @code 48 * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) ---> 49 * +----------------------------+- - -+- - - - - - - - - - -+- - -+ 50 * | Header | Pad | Payload | Pad | 51 * | struct nlmsghdr | | | | 52 * +----------------------------+- - -+- - - - - - - - - - -+- - -+ 53 * @endcode 54 * @par 55 * Message Format: 56 * @code 57 * <--- nlmsg_total_size(payload) ---> 58 * <-- nlmsg_msg_size(payload) -> 59 * +----------+- - -+-------------+- - -+-------- - - 60 * | nlmsghdr | Pad | Payload | Pad | nlmsghdr 61 * +----------+- - -+-------------+- - -+-------- - - 62 * nlmsg_data(nlh)---^ ^ 63 * nlmsg_next(nlh)-----------------------+ 64 * @endcode 65 * @par 66 * The payload may consist of arbitary data but may have strict 67 * alignment and formatting rules depening on the specific netlink 68 * families. 69 * @par 70 * @code 71 * <---------------------- nlmsg_len(nlh) ---------------------> 72 * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> 73 * +----------------------+- - -+--------------------------------+ 74 * | Family Header | Pad | Attributes | 75 * +----------------------+- - -+--------------------------------+ 76 * nlmsg_attrdata(nlh, hdrlen)---^ 77 * @endcode 78 * @par The ACK Netlink Message 79 * This message is actually used to denote both an ACK and a NACK. 80 * Typically, the direction is from FEC to CPC (in response to an ACK 81 * request message). However, the CPC should be able to send ACKs back 82 * to FEC when requested. 83 * @code 84 * 0 1 2 3 85 * 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 86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 87 * | Netlink message header | 88 * | type = NLMSG_ERROR | 89 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 90 * | Error code | 91 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 92 * | OLD Netlink message header | 93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 94 * @endcode 95 * 96 * @par Example 97 * @code 98 * // Various methods exist to create/allocate a new netlink 99 * // message. 100 * // 101 * // nlmsg_alloc() will allocate an empty netlink message with 102 * // a maximum payload size which defaults to the page size of 103 * // the system. This default size can be modified using the 104 * // function nlmsg_set_default_size(). 105 * struct nl_msg *msg = nlmsg_alloc(); 106 * 107 * // Very often, the message type and message flags are known 108 * // at allocation time while the other fields are auto generated: 109 * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS); 110 * 111 * // Alternatively an existing netlink message header can be used 112 * // to inherit the header values: 113 * struct nlmsghdr hdr = { 114 * .nlmsg_type = MY_TYPE, 115 * .nlmsg_flags = MY_FLAGS, 116 * }; 117 * struct nl_msg *msg = nlmsg_inherit(&hdr); 118 * 119 * // Last but not least, netlink messages received from netlink sockets 120 * // can be converted into nl_msg objects using nlmsg_convert(). This 121 * // will create a message with a maximum payload size which equals the 122 * // length of the existing netlink message, therefore no more data can 123 * // be appened without calling nlmsg_expand() first. 124 * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock); 125 * 126 * // Payload may be added to the message via nlmsg_append(). The fourth 127 * // parameter specifies the number of alignment bytes the data should 128 * // be padding with at the end. Common values are 0 to disable it or 129 * // NLMSG_ALIGNTO to ensure proper netlink message padding. 130 * nlmsg_append(msg, &mydata, sizeof(mydata), 0); 131 * 132 * // Sometimes it may be necessary to reserve room for data but defer 133 * // the actual copying to a later point, nlmsg_reserve() can be used 134 * // for this purpose: 135 * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO); 136 * 137 * // Attributes may be added using the attributes interface. 138 * 139 * // After successful use of the message, the memory must be freed 140 * // using nlmsg_free() 141 * nlmsg_free(msg); 142 * @endcode 143 * 144 * @par 4) Parsing messages 145 * @code 146 * int n; 147 * unsigned char *buf; 148 * struct nlmsghdr *hdr; 149 * 150 * n = nl_recv(handle, NULL, &buf); 151 * 152 * hdr = (struct nlmsghdr *) buf; 153 * while (nlmsg_ok(hdr, n)) { 154 * // Process message here... 155 * hdr = nlmsg_next(hdr, &n); 156 * } 157 * @endcode 158 * @{ 159 */ 160 161 #include <netlink-local.h> 162 #include <netlink/netlink.h> 163 #include <netlink/utils.h> 164 #include <netlink/cache.h> 165 #include <netlink/attr.h> 166 #include <netlink/msg.h> 167 #include <linux/socket.h> 168 169 static size_t default_msg_size = 4096; 170 171 /** 172 * @name Attribute Access 173 * @{ 174 */ 175 176 //** @} */ 177 178 /** 179 * @name Message Parsing 180 * @{ 181 */ 182 183 /** 184 * check if the netlink message fits into the remaining bytes 185 * @arg nlh netlink message header 186 * @arg remaining number of bytes remaining in message stream 187 */ 188 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) 189 { 190 size_t r = remaining; 191 192 return (r >= sizeof(struct nlmsghdr) && 193 nlh->nlmsg_len >= sizeof(struct nlmsghdr) && 194 nlh->nlmsg_len <= r); 195 } 196 197 /** 198 * next netlink message in message stream 199 * @arg nlh netlink message header 200 * @arg remaining number of bytes remaining in message stream 201 * 202 * @returns the next netlink message in the message stream and 203 * decrements remaining by the size of the current message. 204 */ 205 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) 206 { 207 int totlen = NLMSG_ALIGN(nlh->nlmsg_len); 208 209 *remaining -= totlen; 210 211 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); 212 } 213 214 /** 215 * parse attributes of a netlink message 216 * @arg nlh netlink message header 217 * @arg hdrlen length of family specific header 218 * @arg tb destination array with maxtype+1 elements 219 * @arg maxtype maximum attribute type to be expected 220 * @arg policy validation policy 221 * 222 * See nla_parse() 223 */ 224 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], 225 int maxtype, const struct nla_policy *policy) 226 { 227 if (!nlmsg_valid_hdr(nlh, hdrlen)) 228 return -NLE_MSG_TOOSHORT; 229 230 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), 231 nlmsg_attrlen(nlh, hdrlen), policy); 232 } 233 234 /** 235 * nlmsg_validate - validate a netlink message including attributes 236 * @arg nlh netlinket message header 237 * @arg hdrlen length of familiy specific header 238 * @arg maxtype maximum attribute type to be expected 239 * @arg policy validation policy 240 */ 241 int nlmsg_validate(const struct nlmsghdr *nlh, int hdrlen, int maxtype, 242 const struct nla_policy *policy) 243 { 244 if (!nlmsg_valid_hdr(nlh, hdrlen)) 245 return -NLE_MSG_TOOSHORT; 246 247 return nla_validate(nlmsg_attrdata(nlh, hdrlen), 248 nlmsg_attrlen(nlh, hdrlen), maxtype, policy); 249 } 250 251 /** @} */ 252 253 /** 254 * @name Message Building/Access 255 * @{ 256 */ 257 258 static struct nl_msg *__nlmsg_alloc(size_t len) 259 { 260 struct nl_msg *nm; 261 262 nm = calloc(1, sizeof(*nm)); 263 if (!nm) 264 goto errout; 265 266 nm->nm_refcnt = 1; 267 268 nm->nm_nlh = malloc(len); 269 if (!nm->nm_nlh) 270 goto errout; 271 272 memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr)); 273 274 nm->nm_protocol = -1; 275 nm->nm_size = len; 276 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); 277 278 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); 279 280 return nm; 281 errout: 282 free(nm); 283 return NULL; 284 } 285 286 /** 287 * Allocate a new netlink message with the default maximum payload size. 288 * 289 * Allocates a new netlink message without any further payload. The 290 * maximum payload size defaults to PAGESIZE or as otherwise specified 291 * with nlmsg_set_default_size(). 292 * 293 * @return Newly allocated netlink message or NULL. 294 */ 295 struct nl_msg *nlmsg_alloc(void) 296 { 297 return __nlmsg_alloc(default_msg_size); 298 } 299 300 /** 301 * Allocate a new netlink message with maximum payload size specified. 302 */ 303 struct nl_msg *nlmsg_alloc_size(size_t max) 304 { 305 return __nlmsg_alloc(max); 306 } 307 308 /** 309 * Allocate a new netlink message and inherit netlink message header 310 * @arg hdr Netlink message header template 311 * 312 * Allocates a new netlink message and inherits the original message 313 * header. If \a hdr is not NULL it will be used as a template for 314 * the netlink message header, otherwise the header is left blank. 315 * 316 * @return Newly allocated netlink message or NULL 317 */ 318 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) 319 { 320 struct nl_msg *nm; 321 322 nm = nlmsg_alloc(); 323 if (nm && hdr) { 324 struct nlmsghdr *new = nm->nm_nlh; 325 326 new->nlmsg_type = hdr->nlmsg_type; 327 new->nlmsg_flags = hdr->nlmsg_flags; 328 new->nlmsg_seq = hdr->nlmsg_seq; 329 new->nlmsg_pid = hdr->nlmsg_pid; 330 } 331 332 return nm; 333 } 334 335 /** 336 * Allocate a new netlink message 337 * @arg nlmsgtype Netlink message type 338 * @arg flags Message flags. 339 * 340 * @return Newly allocated netlink message or NULL. 341 */ 342 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) 343 { 344 struct nl_msg *msg; 345 struct nlmsghdr nlh = { 346 .nlmsg_type = nlmsgtype, 347 .nlmsg_flags = flags, 348 }; 349 350 msg = nlmsg_inherit(&nlh); 351 if (msg) 352 NL_DBG(2, "msg %p: Allocated new simple message\n", msg); 353 354 return msg; 355 } 356 357 /** 358 * Set the default maximum message payload size for allocated messages 359 * @arg max Size of payload in bytes. 360 */ 361 void nlmsg_set_default_size(size_t max) 362 { 363 if (max < (size_t) nlmsg_total_size(0)) 364 max = nlmsg_total_size(0); 365 366 default_msg_size = max; 367 } 368 369 /** 370 * Convert a netlink message received from a netlink socket to a nl_msg 371 * @arg hdr Netlink message received from netlink socket. 372 * 373 * Allocates a new netlink message and copies all of the data pointed to 374 * by \a hdr into the new message object. 375 * 376 * @return Newly allocated netlink message or NULL. 377 */ 378 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) 379 { 380 struct nl_msg *nm; 381 382 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); 383 if (!nm) 384 goto errout; 385 386 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); 387 388 return nm; 389 errout: 390 nlmsg_free(nm); 391 return NULL; 392 } 393 394 /** 395 * Reserve room for additional data in a netlink message 396 * @arg n netlink message 397 * @arg len length of additional data to reserve room for 398 * @arg pad number of bytes to align data to 399 * 400 * Reserves room for additional data at the tail of the an 401 * existing netlink message. Eventual padding required will 402 * be zeroed out. 403 * 404 * @return Pointer to start of additional data tailroom or NULL. 405 */ 406 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) 407 { 408 void *buf = n->nm_nlh; 409 size_t nlmsg_len = n->nm_nlh->nlmsg_len; 410 size_t tlen; 411 412 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 413 414 if ((tlen + nlmsg_len) > n->nm_size) 415 return NULL; 416 417 buf += nlmsg_len; 418 n->nm_nlh->nlmsg_len += tlen; 419 420 if (tlen > len) 421 memset(buf + len, 0, tlen - len); 422 423 NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n", 424 n, len, pad, n->nm_nlh->nlmsg_len); 425 426 return buf; 427 } 428 429 /** 430 * Append data to tail of a netlink message 431 * @arg n netlink message 432 * @arg data data to add 433 * @arg len length of data 434 * @arg pad Number of bytes to align data to. 435 * 436 * Extends the netlink message as needed and appends the data of given 437 * length to the message. 438 * 439 * @return 0 on success or a negative error code 440 */ 441 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 442 { 443 void *tmp; 444 445 tmp = nlmsg_reserve(n, len, pad); 446 if (tmp == NULL) 447 return -NLE_NOMEM; 448 449 memcpy(tmp, data, len); 450 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 451 452 return 0; 453 } 454 455 /** 456 * Add a netlink message header to a netlink message 457 * @arg n netlink message 458 * @arg pid netlink process id or NL_AUTO_PID 459 * @arg seq sequence number of message or NL_AUTO_SEQ 460 * @arg type message type 461 * @arg payload length of message payload 462 * @arg flags message flags 463 * 464 * Adds or overwrites the netlink message header in an existing message 465 * object. If \a payload is greater-than zero additional room will be 466 * reserved, f.e. for family specific headers. It can be accesed via 467 * nlmsg_data(). 468 * 469 * @return A pointer to the netlink message header or NULL. 470 */ 471 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 472 int type, int payload, int flags) 473 { 474 struct nlmsghdr *nlh; 475 476 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 477 BUG(); 478 479 nlh = (struct nlmsghdr *) n->nm_nlh; 480 nlh->nlmsg_type = type; 481 nlh->nlmsg_flags = flags; 482 nlh->nlmsg_pid = pid; 483 nlh->nlmsg_seq = seq; 484 485 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 486 "seq=%d\n", n, type, flags, pid, seq); 487 488 if (payload > 0 && 489 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 490 return NULL; 491 492 return nlh; 493 } 494 495 /** 496 * Release a reference from an netlink message 497 * @arg msg message to release reference from 498 * 499 * Frees memory after the last reference has been released. 500 */ 501 void nlmsg_free(struct nl_msg *msg) 502 { 503 if (!msg) 504 return; 505 506 msg->nm_refcnt--; 507 NL_DBG(4, "Returned message reference %p, %d remaining\n", 508 msg, msg->nm_refcnt); 509 510 if (msg->nm_refcnt < 0) 511 BUG(); 512 513 if (msg->nm_refcnt <= 0) { 514 free(msg->nm_nlh); 515 free(msg); 516 NL_DBG(2, "msg %p: Freed\n", msg); 517 } 518 } 519 520 /** @} */ 521 522 /** 523 * @name Direct Parsing 524 * @{ 525 */ 526 527 /** @cond SKIP */ 528 struct dp_xdata { 529 void (*cb)(struct nl_object *, void *); 530 void *arg; 531 }; 532 /** @endcond */ 533 534 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 535 { 536 struct dp_xdata *x = p->pp_arg; 537 538 x->cb(obj, x->arg); 539 return 0; 540 } 541 542 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 543 void *arg) 544 { 545 struct nl_cache_ops *ops; 546 struct nl_parser_param p = { 547 .pp_cb = parse_cb 548 }; 549 struct dp_xdata x = { 550 .cb = cb, 551 .arg = arg, 552 }; 553 554 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), 555 nlmsg_hdr(msg)->nlmsg_type); 556 if (ops == NULL) 557 return -NLE_MSGTYPE_NOSUPPORT; 558 p.pp_arg = &x; 559 560 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 561 } 562 563 /** @} */ 564
This page was automatically generated by LXR 0.3.1. • OpenWrt