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-2012 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup core 14 * @defgroup msg Message Construction & Parsing 15 * Netlink Message Construction/Parsing Interface 16 * 17 * Related sections in the development guide: 18 * - @core_doc{_message_parsing_amp_construction,Message Parsing & Construction} 19 * 20 * @{ 21 * 22 * Header 23 * ------ 24 * ~~~~{.c} 25 * #include <netlink/msg.h> 26 * ~~~~ 27 */ 28 29 #include <netlink-private/netlink.h> 30 #include <netlink/netlink.h> 31 #include <netlink/utils.h> 32 #include <netlink/cache.h> 33 #include <netlink/attr.h> 34 #include <linux/socket.h> 35 36 static size_t default_msg_size; 37 38 static void __init init_msg_size(void) 39 { 40 default_msg_size = getpagesize(); 41 } 42 43 /** 44 * @name Size Calculations 45 * @{ 46 */ 47 48 /** 49 * Calculates size of netlink message based on payload length. 50 * @arg payload Length of payload 51 * 52 * @return size of netlink message without padding. 53 */ 54 int nlmsg_size(int payload) 55 { 56 return NLMSG_HDRLEN + payload; 57 } 58 59 static int nlmsg_msg_size(int payload) 60 { 61 return nlmsg_size(payload); 62 } 63 64 /** 65 * Calculates size of netlink message including padding based on payload length 66 * @arg payload Length of payload 67 * 68 * This function is idential to nlmsg_size() + nlmsg_padlen(). 69 * 70 * @return Size of netlink message including padding. 71 */ 72 int nlmsg_total_size(int payload) 73 { 74 return NLMSG_ALIGN(nlmsg_msg_size(payload)); 75 } 76 77 /** 78 * Size of padding that needs to be added at end of message 79 * @arg payload Length of payload 80 * 81 * Calculates the number of bytes of padding which is required to be added to 82 * the end of the message to ensure that the next netlink message header begins 83 * properly aligned to NLMSG_ALIGNTO. 84 * 85 * @return Number of bytes of padding needed. 86 */ 87 int nlmsg_padlen(int payload) 88 { 89 return nlmsg_total_size(payload) - nlmsg_msg_size(payload); 90 } 91 92 /** @} */ 93 94 /** 95 * @name Access to Message Payload 96 * @{ 97 */ 98 99 /** 100 * Return pointer to message payload 101 * @arg nlh Netlink message header 102 * 103 * @return Pointer to start of message payload. 104 */ 105 void *nlmsg_data(const struct nlmsghdr *nlh) 106 { 107 return (unsigned char *) nlh + NLMSG_HDRLEN; 108 } 109 110 void *nlmsg_tail(const struct nlmsghdr *nlh) 111 { 112 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); 113 } 114 115 /** 116 * Return length of message payload 117 * @arg nlh Netlink message header 118 * 119 * @return Length of message payload in bytes. 120 */ 121 int nlmsg_datalen(const struct nlmsghdr *nlh) 122 { 123 return nlh->nlmsg_len - NLMSG_HDRLEN; 124 } 125 126 static int nlmsg_len(const struct nlmsghdr *nlh) 127 { 128 return nlmsg_datalen(nlh); 129 } 130 131 /** @} */ 132 133 /** 134 * @name Attribute Access 135 * @{ 136 */ 137 138 /** 139 * head of attributes data 140 * @arg nlh netlink message header 141 * @arg hdrlen length of family specific header 142 */ 143 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen) 144 { 145 unsigned char *data = nlmsg_data(nlh); 146 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); 147 } 148 149 /** 150 * length of attributes data 151 * @arg nlh netlink message header 152 * @arg hdrlen length of family specific header 153 */ 154 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) 155 { 156 return max_t(int, nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen), 0); 157 } 158 159 /** @} */ 160 161 /** 162 * @name Message Parsing 163 * @{ 164 */ 165 166 int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) 167 { 168 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) 169 return 0; 170 171 return 1; 172 } 173 174 /** 175 * check if the netlink message fits into the remaining bytes 176 * @arg nlh netlink message header 177 * @arg remaining number of bytes remaining in message stream 178 */ 179 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) 180 { 181 return (remaining >= (int)sizeof(struct nlmsghdr) && 182 nlh->nlmsg_len >= sizeof(struct nlmsghdr) && 183 nlh->nlmsg_len <= remaining); 184 } 185 186 /** 187 * next netlink message in message stream 188 * @arg nlh netlink message header 189 * @arg remaining number of bytes remaining in message stream 190 * 191 * @returns the next netlink message in the message stream and 192 * decrements remaining by the size of the current message. 193 */ 194 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) 195 { 196 int totlen = NLMSG_ALIGN(nlh->nlmsg_len); 197 198 *remaining -= totlen; 199 200 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); 201 } 202 203 /** 204 * parse attributes of a netlink message 205 * @arg nlh netlink message header 206 * @arg hdrlen length of family specific header 207 * @arg tb destination array with maxtype+1 elements 208 * @arg maxtype maximum attribute type to be expected 209 * @arg policy validation policy 210 * 211 * See nla_parse() 212 */ 213 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], 214 int maxtype, struct nla_policy *policy) 215 { 216 if (!nlmsg_valid_hdr(nlh, hdrlen)) 217 return -NLE_MSG_TOOSHORT; 218 219 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), 220 nlmsg_attrlen(nlh, hdrlen), policy); 221 } 222 223 /** 224 * nlmsg_find_attr - find a specific attribute in a netlink message 225 * @arg nlh netlink message header 226 * @arg hdrlen length of familiy specific header 227 * @arg attrtype type of attribute to look for 228 * 229 * Returns the first attribute which matches the specified type. 230 */ 231 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) 232 { 233 return nla_find(nlmsg_attrdata(nlh, hdrlen), 234 nlmsg_attrlen(nlh, hdrlen), attrtype); 235 } 236 237 /** 238 * nlmsg_validate - validate a netlink message including attributes 239 * @arg nlh netlinket message header 240 * @arg hdrlen length of familiy specific header 241 * @arg maxtype maximum attribute type to be expected 242 * @arg policy validation policy 243 */ 244 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, 245 struct nla_policy *policy) 246 { 247 if (!nlmsg_valid_hdr(nlh, hdrlen)) 248 return -NLE_MSG_TOOSHORT; 249 250 return nla_validate(nlmsg_attrdata(nlh, hdrlen), 251 nlmsg_attrlen(nlh, hdrlen), maxtype, policy); 252 } 253 254 /** @} */ 255 256 /** 257 * @name Message Building/Access 258 * @{ 259 */ 260 261 static struct nl_msg *__nlmsg_alloc(size_t len) 262 { 263 struct nl_msg *nm; 264 265 if (len < sizeof(struct nlmsghdr)) 266 len = sizeof(struct nlmsghdr); 267 268 nm = calloc(1, sizeof(*nm)); 269 if (!nm) 270 goto errout; 271 272 nm->nm_refcnt = 1; 273 274 nm->nm_nlh = calloc(1, len); 275 if (!nm->nm_nlh) 276 goto errout; 277 278 nm->nm_protocol = -1; 279 nm->nm_size = len; 280 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); 281 282 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); 283 284 return nm; 285 errout: 286 free(nm); 287 return NULL; 288 } 289 290 /** 291 * Allocate a new netlink message with the default maximum payload size. 292 * 293 * Allocates a new netlink message without any further payload. The 294 * maximum payload size defaults to PAGESIZE or as otherwise specified 295 * with nlmsg_set_default_size(). 296 * 297 * @return Newly allocated netlink message or NULL. 298 */ 299 struct nl_msg *nlmsg_alloc(void) 300 { 301 return __nlmsg_alloc(default_msg_size); 302 } 303 304 /** 305 * Allocate a new netlink message with maximum payload size specified. 306 */ 307 struct nl_msg *nlmsg_alloc_size(size_t max) 308 { 309 return __nlmsg_alloc(max); 310 } 311 312 /** 313 * Allocate a new netlink message and inherit netlink message header 314 * @arg hdr Netlink message header template 315 * 316 * Allocates a new netlink message and inherits the original message 317 * header. If \a hdr is not NULL it will be used as a template for 318 * the netlink message header, otherwise the header is left blank. 319 * 320 * @return Newly allocated netlink message or NULL 321 */ 322 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) 323 { 324 struct nl_msg *nm; 325 326 nm = nlmsg_alloc(); 327 if (nm && hdr) { 328 struct nlmsghdr *new = nm->nm_nlh; 329 330 new->nlmsg_type = hdr->nlmsg_type; 331 new->nlmsg_flags = hdr->nlmsg_flags; 332 new->nlmsg_seq = hdr->nlmsg_seq; 333 new->nlmsg_pid = hdr->nlmsg_pid; 334 } 335 336 return nm; 337 } 338 339 /** 340 * Allocate a new netlink message 341 * @arg nlmsgtype Netlink message type 342 * @arg flags Message flags. 343 * 344 * @return Newly allocated netlink message or NULL. 345 */ 346 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) 347 { 348 struct nl_msg *msg; 349 struct nlmsghdr nlh = { 350 .nlmsg_type = nlmsgtype, 351 .nlmsg_flags = flags, 352 }; 353 354 msg = nlmsg_inherit(&nlh); 355 if (msg) 356 NL_DBG(2, "msg %p: Allocated new simple message\n", msg); 357 358 return msg; 359 } 360 361 /** 362 * Set the default maximum message payload size for allocated messages 363 * @arg max Size of payload in bytes. 364 */ 365 void nlmsg_set_default_size(size_t max) 366 { 367 if (max < nlmsg_total_size(0)) 368 max = nlmsg_total_size(0); 369 370 default_msg_size = max; 371 } 372 373 /** 374 * Convert a netlink message received from a netlink socket to a nl_msg 375 * @arg hdr Netlink message received from netlink socket. 376 * 377 * Allocates a new netlink message and copies all of the data pointed to 378 * by \a hdr into the new message object. 379 * 380 * @return Newly allocated netlink message or NULL. 381 */ 382 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) 383 { 384 struct nl_msg *nm; 385 386 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); 387 if (!nm) 388 return NULL; 389 390 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); 391 392 return nm; 393 } 394 395 /** 396 * Reserve room for additional data in a netlink message 397 * @arg n netlink message 398 * @arg len length of additional data to reserve room for 399 * @arg pad number of bytes to align data to 400 * 401 * Reserves room for additional data at the tail of the an 402 * existing netlink message. Eventual padding required will 403 * be zeroed out. 404 * 405 * @return Pointer to start of additional data tailroom or NULL. 406 */ 407 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) 408 { 409 void *buf = n->nm_nlh; 410 size_t nlmsg_len = n->nm_nlh->nlmsg_len; 411 size_t tlen; 412 413 if (len > n->nm_size) 414 return NULL; 415 416 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; 417 418 if ((tlen + nlmsg_len) > n->nm_size) 419 return NULL; 420 421 buf += nlmsg_len; 422 n->nm_nlh->nlmsg_len += tlen; 423 424 if (tlen > len) 425 memset(buf + len, 0, tlen - len); 426 427 NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n", 428 n, tlen, len, pad, n->nm_nlh->nlmsg_len); 429 430 return buf; 431 } 432 433 /** 434 * Append data to tail of a netlink message 435 * @arg n netlink message 436 * @arg data data to add 437 * @arg len length of data 438 * @arg pad Number of bytes to align data to. 439 * 440 * Extends the netlink message as needed and appends the data of given 441 * length to the message. 442 * 443 * @return 0 on success or a negative error code 444 */ 445 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) 446 { 447 void *tmp; 448 449 tmp = nlmsg_reserve(n, len, pad); 450 if (tmp == NULL) 451 return -NLE_NOMEM; 452 453 memcpy(tmp, data, len); 454 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); 455 456 return 0; 457 } 458 459 /** 460 * Expand maximum payload size of a netlink message 461 * @arg n Netlink message. 462 * @arg newlen New maximum payload size. 463 * 464 * Reallocates the payload section of a netlink message and increases 465 * the maximum payload size of the message. 466 * 467 * @note Any pointers pointing to old payload block will be stale and 468 * need to be refetched. Therfore, do not expand while constructing 469 * nested attributes or while reserved data blocks are held. 470 * 471 * @return 0 on success or a negative error code. 472 */ 473 int nlmsg_expand(struct nl_msg *n, size_t newlen) 474 { 475 void *tmp; 476 477 if (newlen <= n->nm_size) 478 return -NLE_INVAL; 479 480 tmp = realloc(n->nm_nlh, newlen); 481 if (tmp == NULL) 482 return -NLE_NOMEM; 483 484 n->nm_nlh = tmp; 485 n->nm_size = newlen; 486 487 return 0; 488 } 489 490 /** 491 * Add a netlink message header to a netlink message 492 * @arg n netlink message 493 * @arg pid netlink process id or NL_AUTO_PID 494 * @arg seq sequence number of message or NL_AUTO_SEQ 495 * @arg type message type 496 * @arg payload length of message payload 497 * @arg flags message flags 498 * 499 * Adds or overwrites the netlink message header in an existing message 500 * object. If \a payload is greater-than zero additional room will be 501 * reserved, f.e. for family specific headers. It can be accesed via 502 * nlmsg_data(). 503 * 504 * @return A pointer to the netlink message header or NULL. 505 */ 506 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, 507 int type, int payload, int flags) 508 { 509 struct nlmsghdr *nlh; 510 511 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) 512 BUG(); 513 514 nlh = (struct nlmsghdr *) n->nm_nlh; 515 nlh->nlmsg_type = type; 516 nlh->nlmsg_flags = flags; 517 nlh->nlmsg_pid = pid; 518 nlh->nlmsg_seq = seq; 519 520 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " 521 "seq=%d\n", n, type, flags, pid, seq); 522 523 if (payload > 0 && 524 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) 525 return NULL; 526 527 return nlh; 528 } 529 530 /** 531 * Return actual netlink message 532 * @arg n netlink message 533 * 534 * Returns the actual netlink message casted to the type of the netlink 535 * message header. 536 * 537 * @return A pointer to the netlink message. 538 */ 539 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) 540 { 541 return n->nm_nlh; 542 } 543 544 /** 545 * Acquire a reference on a netlink message 546 * @arg msg message to acquire reference from 547 */ 548 void nlmsg_get(struct nl_msg *msg) 549 { 550 msg->nm_refcnt++; 551 NL_DBG(4, "New reference to message %p, total %d\n", 552 msg, msg->nm_refcnt); 553 } 554 555 /** 556 * Release a reference from an netlink message 557 * @arg msg message to release reference from 558 * 559 * Frees memory after the last reference has been released. 560 */ 561 void nlmsg_free(struct nl_msg *msg) 562 { 563 if (!msg) 564 return; 565 566 msg->nm_refcnt--; 567 NL_DBG(4, "Returned message reference %p, %d remaining\n", 568 msg, msg->nm_refcnt); 569 570 if (msg->nm_refcnt < 0) 571 BUG(); 572 573 if (msg->nm_refcnt <= 0) { 574 free(msg->nm_nlh); 575 NL_DBG(2, "msg %p: Freed\n", msg); 576 free(msg); 577 } 578 } 579 580 /** @} */ 581 582 /** 583 * @name Attributes 584 * @{ 585 */ 586 587 void nlmsg_set_proto(struct nl_msg *msg, int protocol) 588 { 589 msg->nm_protocol = protocol; 590 } 591 592 int nlmsg_get_proto(struct nl_msg *msg) 593 { 594 return msg->nm_protocol; 595 } 596 597 size_t nlmsg_get_max_size(struct nl_msg *msg) 598 { 599 return msg->nm_size; 600 } 601 602 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) 603 { 604 memcpy(&msg->nm_src, addr, sizeof(*addr)); 605 } 606 607 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) 608 { 609 return &msg->nm_src; 610 } 611 612 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) 613 { 614 memcpy(&msg->nm_dst, addr, sizeof(*addr)); 615 } 616 617 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) 618 { 619 return &msg->nm_dst; 620 } 621 622 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) 623 { 624 memcpy(&msg->nm_creds, creds, sizeof(*creds)); 625 msg->nm_flags |= NL_MSG_CRED_PRESENT; 626 } 627 628 struct ucred *nlmsg_get_creds(struct nl_msg *msg) 629 { 630 if (msg->nm_flags & NL_MSG_CRED_PRESENT) 631 return &msg->nm_creds; 632 return NULL; 633 } 634 635 /** @} */ 636 637 /** 638 * @name Netlink Message Type Translations 639 * @{ 640 */ 641 642 static const struct trans_tbl nl_msgtypes[] = { 643 __ADD(NLMSG_NOOP,NOOP) 644 __ADD(NLMSG_ERROR,ERROR) 645 __ADD(NLMSG_DONE,DONE) 646 __ADD(NLMSG_OVERRUN,OVERRUN) 647 }; 648 649 char *nl_nlmsgtype2str(int type, char *buf, size_t size) 650 { 651 return __type2str(type, buf, size, nl_msgtypes, 652 ARRAY_SIZE(nl_msgtypes)); 653 } 654 655 int nl_str2nlmsgtype(const char *name) 656 { 657 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); 658 } 659 660 /** @} */ 661 662 /** 663 * @name Netlink Message Flags Translations 664 * @{ 665 */ 666 667 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) 668 { 669 memset(buf, 0, len); 670 671 #define PRINT_FLAG(f) \ 672 if (flags & NLM_F_##f) { \ 673 flags &= ~NLM_F_##f; \ 674 strncat(buf, #f, len - strlen(buf) - 1); \ 675 if (flags) \ 676 strncat(buf, ",", len - strlen(buf) - 1); \ 677 } 678 679 PRINT_FLAG(REQUEST); 680 PRINT_FLAG(MULTI); 681 PRINT_FLAG(ACK); 682 PRINT_FLAG(ECHO); 683 PRINT_FLAG(ROOT); 684 PRINT_FLAG(MATCH); 685 PRINT_FLAG(ATOMIC); 686 PRINT_FLAG(REPLACE); 687 PRINT_FLAG(EXCL); 688 PRINT_FLAG(CREATE); 689 PRINT_FLAG(APPEND); 690 691 if (flags) { 692 char s[32]; 693 snprintf(s, sizeof(s), "0x%x", flags); 694 strncat(buf, s, len - strlen(buf) - 1); 695 } 696 #undef PRINT_FLAG 697 698 return buf; 699 } 700 701 /** @} */ 702 703 /** 704 * @name Direct Parsing 705 * @{ 706 */ 707 708 /** @cond SKIP */ 709 struct dp_xdata { 710 void (*cb)(struct nl_object *, void *); 711 void *arg; 712 }; 713 /** @endcond */ 714 715 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) 716 { 717 struct dp_xdata *x = p->pp_arg; 718 719 x->cb(obj, x->arg); 720 return 0; 721 } 722 723 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), 724 void *arg) 725 { 726 struct nl_cache_ops *ops; 727 struct nl_parser_param p = { 728 .pp_cb = parse_cb 729 }; 730 struct dp_xdata x = { 731 .cb = cb, 732 .arg = arg, 733 }; 734 int err; 735 736 ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg), 737 nlmsg_hdr(msg)->nlmsg_type); 738 if (ops == NULL) 739 return -NLE_MSGTYPE_NOSUPPORT; 740 p.pp_arg = &x; 741 742 err = nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); 743 nl_cache_ops_put(ops); 744 745 return err; 746 } 747 748 /** @} */ 749 750 /** 751 * @name Dumping 752 * @{ 753 */ 754 755 static void prefix_line(FILE *ofd, int prefix) 756 { 757 int i; 758 759 for (i = 0; i < prefix; i++) 760 fprintf(ofd, " "); 761 } 762 763 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) 764 { 765 int i, a, c, limit; 766 char ascii[21] = {0}; 767 768 limit = 16 - (prefix * 2); 769 prefix_line(ofd, prefix); 770 fprintf(ofd, " "); 771 772 for (i = 0, a = 0, c = 0; i < len; i++) { 773 int v = *(uint8_t *) (start + i); 774 775 fprintf(ofd, "%02x ", v); 776 ascii[a++] = isprint(v) ? v : '.'; 777 778 if (++c >= limit) { 779 fprintf(ofd, "%s\n", ascii); 780 if (i < (len - 1)) { 781 prefix_line(ofd, prefix); 782 fprintf(ofd, " "); 783 } 784 a = c = 0; 785 memset(ascii, 0, sizeof(ascii)); 786 } 787 } 788 789 if (c != 0) { 790 for (i = 0; i < (limit - c); i++) 791 fprintf(ofd, " "); 792 fprintf(ofd, "%s\n", ascii); 793 } 794 } 795 796 static void print_hdr(FILE *ofd, struct nl_msg *msg) 797 { 798 struct nlmsghdr *nlh = nlmsg_hdr(msg); 799 struct nl_cache_ops *ops; 800 struct nl_msgtype *mt; 801 char buf[128]; 802 803 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); 804 805 ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg), nlh->nlmsg_type); 806 if (ops) { 807 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); 808 if (!mt) 809 BUG(); 810 811 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); 812 nl_cache_ops_put(ops); 813 } else 814 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); 815 816 fprintf(ofd, " .type = %d <%s>\n", nlh->nlmsg_type, buf); 817 fprintf(ofd, " .flags = %d <%s>\n", nlh->nlmsg_flags, 818 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); 819 fprintf(ofd, " .seq = %d\n", nlh->nlmsg_seq); 820 fprintf(ofd, " .port = %d\n", nlh->nlmsg_pid); 821 822 } 823 824 static void print_genl_hdr(FILE *ofd, void *start) 825 { 826 struct genlmsghdr *ghdr = start; 827 828 fprintf(ofd, " [GENERIC NETLINK HEADER] %zu octets\n", GENL_HDRLEN); 829 fprintf(ofd, " .cmd = %u\n", ghdr->cmd); 830 fprintf(ofd, " .version = %u\n", ghdr->version); 831 fprintf(ofd, " .unused = %#x\n", ghdr->reserved); 832 } 833 834 static void *print_genl_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr, 835 struct nl_cache_ops *ops, int *payloadlen) 836 { 837 void *data = nlmsg_data(hdr); 838 839 if (*payloadlen < GENL_HDRLEN) 840 return data; 841 842 print_genl_hdr(ofd, data); 843 844 *payloadlen -= GENL_HDRLEN; 845 data += GENL_HDRLEN; 846 847 if (ops) { 848 int hdrsize = ops->co_hdrsize - GENL_HDRLEN; 849 850 if (hdrsize > 0) { 851 if (*payloadlen < hdrsize) 852 return data; 853 854 fprintf(ofd, " [HEADER] %d octets\n", hdrsize); 855 dump_hex(ofd, data, hdrsize, 0); 856 857 *payloadlen -= hdrsize; 858 data += hdrsize; 859 } 860 } 861 862 return data; 863 } 864 865 static void dump_attr(FILE *ofd, struct nlattr *attr, int prefix) 866 { 867 int len = nla_len(attr); 868 869 dump_hex(ofd, nla_data(attr), len, prefix); 870 } 871 872 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, 873 int prefix) 874 { 875 int rem; 876 struct nlattr *nla; 877 878 nla_for_each_attr(nla, attrs, attrlen, rem) { 879 int padlen, alen = nla_len(nla); 880 881 prefix_line(ofd, prefix); 882 883 if (nla->nla_type == 0) 884 fprintf(ofd, " [ATTR PADDING] %d octets\n", alen); 885 else 886 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), 887 nla_is_nested(nla) ? " NESTED" : "", 888 alen); 889 890 if (nla_is_nested(nla)) 891 dump_attrs(ofd, nla_data(nla), alen, prefix+1); 892 else 893 dump_attr(ofd, nla, prefix); 894 895 padlen = nla_padlen(alen); 896 if (padlen > 0) { 897 prefix_line(ofd, prefix); 898 fprintf(ofd, " [PADDING] %d octets\n", 899 padlen); 900 dump_hex(ofd, nla_data(nla) + alen, 901 padlen, prefix); 902 } 903 } 904 905 if (rem) { 906 prefix_line(ofd, prefix); 907 fprintf(ofd, " [LEFTOVER] %d octets\n", rem); 908 } 909 } 910 911 static void dump_error_msg(struct nl_msg *msg, FILE *ofd) 912 { 913 struct nlmsghdr *hdr = nlmsg_hdr(msg); 914 struct nlmsgerr *err = nlmsg_data(hdr); 915 916 fprintf(ofd, " [ERRORMSG] %zu octets\n", sizeof(*err)); 917 918 if (nlmsg_len(hdr) >= sizeof(*err)) { 919 char buf[256]; 920 struct nl_msg *errmsg; 921 922 fprintf(ofd, " .error = %d \"%s\"\n", err->error, 923 strerror_r(-err->error, buf, sizeof(buf))); 924 fprintf(ofd, " [ORIGINAL MESSAGE] %zu octets\n", sizeof(*hdr)); 925 926 errmsg = nlmsg_inherit(&err->msg); 927 print_hdr(ofd, errmsg); 928 nlmsg_free(errmsg); 929 } 930 } 931 932 static void print_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr) 933 { 934 struct nl_cache_ops *ops; 935 int payloadlen = nlmsg_len(hdr); 936 int attrlen = 0; 937 void *data; 938 939 data = nlmsg_data(hdr); 940 ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg), 941 hdr->nlmsg_type); 942 if (ops) { 943 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 944 payloadlen -= attrlen; 945 } 946 947 if (msg->nm_protocol == NETLINK_GENERIC) 948 data = print_genl_msg(msg, ofd, hdr, ops, &payloadlen); 949 950 if (payloadlen) { 951 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); 952 dump_hex(ofd, data, payloadlen, 0); 953 } 954 955 if (attrlen) { 956 struct nlattr *attrs; 957 int attrlen; 958 959 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); 960 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); 961 dump_attrs(ofd, attrs, attrlen, 0); 962 } 963 964 if (ops) 965 nl_cache_ops_put(ops); 966 } 967 968 /** 969 * Dump message in human readable format to file descriptor 970 * @arg msg Message to print 971 * @arg ofd File descriptor. 972 */ 973 void nl_msg_dump(struct nl_msg *msg, FILE *ofd) 974 { 975 struct nlmsghdr *hdr = nlmsg_hdr(msg); 976 977 fprintf(ofd, 978 "-------------------------- BEGIN NETLINK MESSAGE ---------------------------\n"); 979 980 fprintf(ofd, " [NETLINK HEADER] %zu octets\n", sizeof(struct nlmsghdr)); 981 print_hdr(ofd, msg); 982 983 if (hdr->nlmsg_type == NLMSG_ERROR) 984 dump_error_msg(msg, ofd); 985 else if (nlmsg_len(hdr) > 0) 986 print_msg(msg, ofd, hdr); 987 988 fprintf(ofd, 989 "--------------------------- END NETLINK MESSAGE ---------------------------\n"); 990 } 991 992 /** @} */ 993 994 /** @} */ 995