1 /* 2 * Copyright (c) 2016 Fabien Siron <fabien.siron (at) epita.fr> 3 * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org> 4 * Copyright (c) 2016-2017 The strace developers. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "defs.h" 31 #include "netlink.h" 32 #include "nlattr.h" 33 #include <linux/audit.h> 34 #include <linux/rtnetlink.h> 35 #include <linux/xfrm.h> 36 #include "xlat/netlink_ack_flags.h" 37 #include "xlat/netlink_delete_flags.h" 38 #include "xlat/netlink_flags.h" 39 #include "xlat/netlink_get_flags.h" 40 #include "xlat/netlink_new_flags.h" 41 #include "xlat/netlink_protocols.h" 42 #include "xlat/netlink_types.h" 43 #include "xlat/nf_acct_msg_types.h" 44 #include "xlat/nf_cthelper_msg_types.h" 45 #include "xlat/nf_ctnetlink_exp_msg_types.h" 46 #include "xlat/nf_ctnetlink_msg_types.h" 47 #include "xlat/nf_cttimeout_msg_types.h" 48 #include "xlat/nf_ipset_msg_types.h" 49 #include "xlat/nf_nft_compat_msg_types.h" 50 #include "xlat/nf_nftables_msg_types.h" 51 #include "xlat/nf_osf_msg_types.h" 52 #include "xlat/nf_queue_msg_types.h" 53 #include "xlat/nf_ulog_msg_types.h" 54 #include "xlat/nl_audit_types.h" 55 #include "xlat/nl_crypto_types.h" 56 #include "xlat/nl_netfilter_msg_types.h" 57 #include "xlat/nl_netfilter_subsys_ids.h" 58 #include "xlat/nl_selinux_types.h" 59 #include "xlat/nl_sock_diag_types.h" 60 #include "xlat/nl_xfrm_types.h" 61 #include "xlat/nlmsgerr_attrs.h" 62 63 /* 64 * Fetch a struct nlmsghdr from the given address. 65 */ 66 static bool 67 fetch_nlmsghdr(struct tcb *const tcp, struct nlmsghdr *const nlmsghdr, 68 const kernel_ulong_t addr, const kernel_ulong_t len) 69 { 70 if (len < sizeof(struct nlmsghdr)) { 71 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 72 return false; 73 } 74 75 if (umove_or_printaddr(tcp, addr, nlmsghdr)) 76 return false; 77 78 return true; 79 } 80 81 static int 82 get_fd_nl_family(struct tcb *const tcp, const int fd) 83 { 84 const unsigned long inode = getfdinode(tcp, fd); 85 if (!inode) 86 return -1; 87 88 const char *const details = get_sockaddr_by_inode(tcp, fd, inode); 89 if (!details) 90 return -1; 91 92 const char *const nl_details = STR_STRIP_PREFIX(details, "NETLINK:["); 93 if (nl_details == details) 94 return -1; 95 96 const struct xlat *xlats = netlink_protocols; 97 for (; xlats->str; ++xlats) { 98 const char *name = STR_STRIP_PREFIX(xlats->str, "NETLINK_"); 99 if (!strncmp(nl_details, name, strlen(name))) 100 return xlats->val; 101 } 102 103 if (*nl_details >= '0' && *nl_details <= '9') 104 return atoi(nl_details); 105 106 return -1; 107 } 108 109 static void 110 decode_nlmsg_type_default(struct tcb *tcp, const struct xlat *const xlat, 111 const uint16_t type, 112 const char *const dflt) 113 { 114 printxval(xlat, type, dflt); 115 } 116 117 static void 118 decode_nlmsg_type_generic(struct tcb *tcp, const struct xlat *const xlat, 119 const uint16_t type, 120 const char *const dflt) 121 { 122 printxval(genl_families_xlat(tcp), type, dflt); 123 } 124 125 static const struct { 126 const struct xlat *const xlat; 127 const char *const dflt; 128 } nf_nlmsg_types[] = { 129 [NFNL_SUBSYS_CTNETLINK] = { 130 nf_ctnetlink_msg_types, 131 "IPCTNL_MSG_CT_???" 132 }, 133 [NFNL_SUBSYS_CTNETLINK_EXP] = { 134 nf_ctnetlink_exp_msg_types, 135 "IPCTNL_MSG_EXP_???" 136 }, 137 [NFNL_SUBSYS_QUEUE] = { nf_queue_msg_types, "NFQNL_MSG_???" }, 138 [NFNL_SUBSYS_ULOG] = { nf_ulog_msg_types, "NFULNL_MSG_???" }, 139 [NFNL_SUBSYS_OSF] = { nf_osf_msg_types, "OSF_MSG_???" }, 140 [NFNL_SUBSYS_IPSET] = { nf_ipset_msg_types, "IPSET_CMD_???" }, 141 [NFNL_SUBSYS_ACCT] = { nf_acct_msg_types, "NFNL_MSG_ACCT_???" }, 142 [NFNL_SUBSYS_CTNETLINK_TIMEOUT] = { 143 nf_cttimeout_msg_types, 144 "IPCTNL_MSG_TIMEOUT_???" 145 }, 146 [NFNL_SUBSYS_CTHELPER] = { 147 nf_cthelper_msg_types, 148 "NFNL_MSG_CTHELPER_???" 149 }, 150 [NFNL_SUBSYS_NFTABLES] = { nf_nftables_msg_types, "NFT_MSG_???" }, 151 [NFNL_SUBSYS_NFT_COMPAT] = { 152 nf_nft_compat_msg_types, 153 "NFNL_MSG_COMPAT_???" 154 } 155 }; 156 157 static void 158 decode_nlmsg_type_netfilter(struct tcb *tcp, const struct xlat *const xlat, 159 const uint16_t type, 160 const char *const dflt) 161 { 162 /* Reserved control nfnetlink messages first. */ 163 const char *const text = xlookup(nl_netfilter_msg_types, type); 164 if (text) { 165 tprints(text); 166 return; 167 } 168 169 /* 170 * Other netfilter message types are split 171 * in two pieces: 8 bits subsystem and 8 bits type. 172 */ 173 const uint8_t subsys_id = (uint8_t) (type >> 8); 174 const uint8_t msg_type = (uint8_t) type; 175 176 printxval(xlat, subsys_id, dflt); 177 178 tprints("<<8|"); 179 if (subsys_id < ARRAY_SIZE(nf_nlmsg_types)) 180 printxval(nf_nlmsg_types[subsys_id].xlat, 181 msg_type, nf_nlmsg_types[subsys_id].dflt); 182 else 183 tprintf("%#x", msg_type); 184 } 185 186 typedef void (*nlmsg_types_decoder_t)(struct tcb *, const struct xlat *, 187 uint16_t type, 188 const char *dflt); 189 190 static const struct { 191 const nlmsg_types_decoder_t decoder; 192 const struct xlat *const xlat; 193 const char *const dflt; 194 } nlmsg_types[] = { 195 [NETLINK_AUDIT] = { NULL, nl_audit_types, "AUDIT_???" }, 196 [NETLINK_CRYPTO] = { NULL, nl_crypto_types, "CRYPTO_MSG_???" }, 197 [NETLINK_GENERIC] = { 198 decode_nlmsg_type_generic, 199 NULL, 200 "GENERIC_FAMILY_???" 201 }, 202 [NETLINK_NETFILTER] = { 203 decode_nlmsg_type_netfilter, 204 nl_netfilter_subsys_ids, 205 "NFNL_SUBSYS_???" 206 }, 207 [NETLINK_ROUTE] = { NULL, nl_route_types, "RTM_???" }, 208 [NETLINK_SELINUX] = { NULL, nl_selinux_types, "SELNL_MSG_???" }, 209 [NETLINK_SOCK_DIAG] = { NULL, nl_sock_diag_types, "SOCK_DIAG_???" }, 210 [NETLINK_XFRM] = { NULL, nl_xfrm_types, "XFRM_MSG_???" } 211 }; 212 213 /* 214 * As all valid netlink families are positive integers, use unsigned int 215 * for family here to filter out -1. 216 */ 217 static void 218 decode_nlmsg_type(struct tcb *tcp, const uint16_t type, 219 const unsigned int family) 220 { 221 nlmsg_types_decoder_t decoder = decode_nlmsg_type_default; 222 const struct xlat *xlat = netlink_types; 223 const char *dflt = "NLMSG_???"; 224 225 /* 226 * type < NLMSG_MIN_TYPE are reserved control messages 227 * that need no family-specific decoding. 228 */ 229 if (type >= NLMSG_MIN_TYPE && family < ARRAY_SIZE(nlmsg_types)) { 230 if (nlmsg_types[family].decoder) 231 decoder = nlmsg_types[family].decoder; 232 if (nlmsg_types[family].xlat) 233 xlat = nlmsg_types[family].xlat; 234 if (nlmsg_types[family].dflt) 235 dflt = nlmsg_types[family].dflt; 236 } 237 238 decoder(tcp, xlat, type, dflt); 239 } 240 241 static const struct xlat * 242 decode_nlmsg_flags_crypto(const uint16_t type) 243 { 244 switch (type) { 245 case CRYPTO_MSG_NEWALG: 246 return netlink_new_flags; 247 case CRYPTO_MSG_DELALG: 248 case CRYPTO_MSG_DELRNG: 249 return netlink_delete_flags; 250 case CRYPTO_MSG_GETALG: 251 return netlink_get_flags; 252 } 253 254 return NULL; 255 } 256 257 static const struct xlat * 258 decode_nlmsg_flags_netfilter(const uint16_t type) 259 { 260 const uint8_t subsys_id = (uint8_t) (type >> 8); 261 const uint8_t msg_type = (uint8_t) type; 262 263 switch (subsys_id) { 264 case NFNL_SUBSYS_CTNETLINK: 265 switch (msg_type) { 266 case IPCTNL_MSG_CT_NEW: 267 return netlink_new_flags; 268 case IPCTNL_MSG_CT_GET: 269 case IPCTNL_MSG_CT_GET_CTRZERO: 270 case IPCTNL_MSG_CT_GET_STATS_CPU: 271 case IPCTNL_MSG_CT_GET_STATS: 272 case IPCTNL_MSG_CT_GET_DYING: 273 case IPCTNL_MSG_CT_GET_UNCONFIRMED: 274 return netlink_get_flags; 275 case IPCTNL_MSG_CT_DELETE: 276 return netlink_delete_flags; 277 } 278 break; 279 case NFNL_SUBSYS_CTNETLINK_EXP: 280 switch (msg_type) { 281 case IPCTNL_MSG_EXP_NEW: 282 return netlink_new_flags; 283 case IPCTNL_MSG_EXP_GET: 284 case IPCTNL_MSG_EXP_GET_STATS_CPU: 285 return netlink_get_flags; 286 case IPCTNL_MSG_EXP_DELETE: 287 return netlink_delete_flags; 288 } 289 break; 290 case NFNL_SUBSYS_ACCT: 291 switch (msg_type) { 292 case NFNL_MSG_ACCT_NEW: 293 return netlink_new_flags; 294 case NFNL_MSG_ACCT_GET: 295 case NFNL_MSG_ACCT_GET_CTRZERO: 296 return netlink_get_flags; 297 case NFNL_MSG_ACCT_DEL: 298 return netlink_delete_flags; 299 } 300 break; 301 case NFNL_SUBSYS_CTNETLINK_TIMEOUT: 302 switch (msg_type) { 303 case IPCTNL_MSG_TIMEOUT_NEW: 304 return netlink_new_flags; 305 case IPCTNL_MSG_TIMEOUT_GET: 306 return netlink_get_flags; 307 case IPCTNL_MSG_TIMEOUT_DELETE: 308 return netlink_delete_flags; 309 } 310 break; 311 case NFNL_SUBSYS_CTHELPER: 312 switch (msg_type) { 313 case NFNL_MSG_CTHELPER_NEW: 314 return netlink_new_flags; 315 case NFNL_MSG_CTHELPER_GET: 316 return netlink_get_flags; 317 case NFNL_MSG_CTHELPER_DEL: 318 return netlink_delete_flags; 319 } 320 break; 321 case NFNL_SUBSYS_NFTABLES: 322 switch (msg_type) { 323 case NFT_MSG_NEWTABLE: 324 case NFT_MSG_NEWCHAIN: 325 case NFT_MSG_NEWRULE: 326 case NFT_MSG_NEWSET: 327 case NFT_MSG_NEWSETELEM: 328 case NFT_MSG_NEWGEN: 329 case NFT_MSG_NEWOBJ: 330 return netlink_new_flags; 331 case NFT_MSG_GETTABLE: 332 case NFT_MSG_GETCHAIN: 333 case NFT_MSG_GETRULE: 334 case NFT_MSG_GETSET: 335 case NFT_MSG_GETSETELEM: 336 case NFT_MSG_GETGEN: 337 case NFT_MSG_GETOBJ: 338 case NFT_MSG_GETOBJ_RESET: 339 return netlink_get_flags; 340 case NFT_MSG_DELTABLE: 341 case NFT_MSG_DELCHAIN: 342 case NFT_MSG_DELRULE: 343 case NFT_MSG_DELSET: 344 case NFT_MSG_DELSETELEM: 345 case NFT_MSG_DELOBJ: 346 return netlink_delete_flags; 347 } 348 break; 349 case NFNL_SUBSYS_NFT_COMPAT: 350 switch (msg_type) { 351 case NFNL_MSG_COMPAT_GET: 352 return netlink_get_flags; 353 } 354 break; 355 } 356 357 return NULL; 358 } 359 360 static const struct xlat * 361 decode_nlmsg_flags_route(const uint16_t type) 362 { 363 /* RTM_DELACTION uses NLM_F_ROOT flags */ 364 if (type == RTM_DELACTION) 365 return netlink_get_flags; 366 switch (type & 3) { 367 case 0: 368 return netlink_new_flags; 369 case 1: 370 return netlink_delete_flags; 371 case 2: 372 return netlink_get_flags; 373 } 374 375 return NULL; 376 } 377 378 static const struct xlat * 379 decode_nlmsg_flags_sock_diag(const uint16_t type) 380 { 381 return netlink_get_flags; 382 } 383 384 static const struct xlat * 385 decode_nlmsg_flags_xfrm(const uint16_t type) 386 { 387 switch (type) { 388 case XFRM_MSG_NEWSA: 389 case XFRM_MSG_NEWPOLICY: 390 case XFRM_MSG_NEWAE: 391 case XFRM_MSG_NEWSADINFO: 392 case XFRM_MSG_NEWSPDINFO: 393 return netlink_new_flags; 394 case XFRM_MSG_DELSA: 395 case XFRM_MSG_DELPOLICY: 396 return netlink_delete_flags; 397 case XFRM_MSG_GETSA: 398 case XFRM_MSG_GETPOLICY: 399 case XFRM_MSG_GETAE: 400 case XFRM_MSG_GETSADINFO: 401 case XFRM_MSG_GETSPDINFO: 402 return netlink_get_flags; 403 } 404 405 return NULL; 406 } 407 408 typedef const struct xlat *(*nlmsg_flags_decoder_t)(const uint16_t type); 409 410 static const nlmsg_flags_decoder_t nlmsg_flags[] = { 411 [NETLINK_CRYPTO] = decode_nlmsg_flags_crypto, 412 [NETLINK_NETFILTER] = decode_nlmsg_flags_netfilter, 413 [NETLINK_ROUTE] = decode_nlmsg_flags_route, 414 [NETLINK_SOCK_DIAG] = decode_nlmsg_flags_sock_diag, 415 [NETLINK_XFRM] = decode_nlmsg_flags_xfrm 416 }; 417 418 /* 419 * As all valid netlink families are positive integers, use unsigned int 420 * for family here to filter out -1. 421 */ 422 static void 423 decode_nlmsg_flags(const uint16_t flags, const uint16_t type, 424 const unsigned int family) 425 { 426 const struct xlat *table = NULL; 427 428 if (type < NLMSG_MIN_TYPE) { 429 if (type == NLMSG_ERROR) 430 table = netlink_ack_flags; 431 } else if (family < ARRAY_SIZE(nlmsg_flags) && nlmsg_flags[family]) 432 table = nlmsg_flags[family](type); 433 434 printflags_ex(flags, "NLM_F_???", netlink_flags, table, NULL); 435 } 436 437 static void 438 print_nlmsghdr(struct tcb *tcp, 439 const int fd, 440 const int family, 441 const struct nlmsghdr *const nlmsghdr) 442 { 443 /* print the whole structure regardless of its nlmsg_len */ 444 445 tprintf("{len=%u, type=", nlmsghdr->nlmsg_len); 446 447 decode_nlmsg_type(tcp, nlmsghdr->nlmsg_type, family); 448 449 tprints(", flags="); 450 decode_nlmsg_flags(nlmsghdr->nlmsg_flags, 451 nlmsghdr->nlmsg_type, family); 452 453 tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq, 454 nlmsghdr->nlmsg_pid); 455 } 456 457 static bool 458 print_cookie(struct tcb *const tcp, void *const elem_buf, 459 const size_t elem_size, void *const opaque_data) 460 { 461 tprintf("%" PRIu8, *(uint8_t *) elem_buf); 462 463 return true; 464 } 465 466 static bool 467 decode_nlmsgerr_attr_cookie(struct tcb *const tcp, 468 const kernel_ulong_t addr, 469 const unsigned int len, 470 const void *const opaque_data) 471 { 472 uint8_t cookie; 473 const size_t nmemb = len / sizeof(cookie); 474 475 print_array(tcp, addr, nmemb, &cookie, sizeof(cookie), 476 umoven_or_printaddr, print_cookie, 0); 477 478 return true; 479 } 480 481 static const nla_decoder_t nlmsgerr_nla_decoders[] = { 482 [NLMSGERR_ATTR_MSG] = decode_nla_str, 483 [NLMSGERR_ATTR_OFFS] = decode_nla_u32, 484 [NLMSGERR_ATTR_COOKIE] = decode_nlmsgerr_attr_cookie 485 }; 486 487 static void 488 decode_nlmsghdr_with_payload(struct tcb *const tcp, 489 const int fd, 490 const int family, 491 const struct nlmsghdr *const nlmsghdr, 492 const kernel_ulong_t addr, 493 const kernel_ulong_t len); 494 495 static void 496 decode_nlmsgerr(struct tcb *const tcp, 497 const int fd, 498 const int family, 499 kernel_ulong_t addr, 500 unsigned int len, 501 const bool capped) 502 { 503 struct nlmsgerr err; 504 505 if (len < sizeof(err.error)) { 506 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 507 return; 508 } 509 510 if (umove_or_printaddr(tcp, addr, &err.error)) 511 return; 512 513 tprints("{error="); 514 if (err.error < 0 && (unsigned) -err.error < nerrnos) { 515 tprintf("-%s", errnoent[-err.error]); 516 } else { 517 tprintf("%d", err.error); 518 } 519 520 addr += offsetof(struct nlmsgerr, msg); 521 len -= offsetof(struct nlmsgerr, msg); 522 523 if (len) { 524 tprints(", msg="); 525 if (fetch_nlmsghdr(tcp, &err.msg, addr, len)) { 526 unsigned int payload = 527 capped ? sizeof(err.msg) : err.msg.nlmsg_len; 528 if (payload > len) 529 payload = len; 530 531 decode_nlmsghdr_with_payload(tcp, fd, family, 532 &err.msg, addr, payload); 533 if (len > payload) { 534 tprints(", "); 535 decode_nlattr(tcp, addr + payload, 536 len - payload, nlmsgerr_attrs, 537 "NLMSGERR_ATTR_???", 538 nlmsgerr_nla_decoders, 539 ARRAY_SIZE(nlmsgerr_nla_decoders), 540 NULL); 541 } 542 } 543 } 544 545 tprints("}"); 546 } 547 548 static const netlink_decoder_t netlink_decoders[] = { 549 #ifdef HAVE_LINUX_CRYPTOUSER_H 550 [NETLINK_CRYPTO] = decode_netlink_crypto, 551 #endif 552 [NETLINK_ROUTE] = decode_netlink_route, 553 [NETLINK_SELINUX] = decode_netlink_selinux, 554 [NETLINK_SOCK_DIAG] = decode_netlink_sock_diag 555 }; 556 557 static void 558 decode_payload(struct tcb *const tcp, 559 const int fd, 560 const int family, 561 const struct nlmsghdr *const nlmsghdr, 562 const kernel_ulong_t addr, 563 const unsigned int len) 564 { 565 if (nlmsghdr->nlmsg_type == NLMSG_ERROR) { 566 decode_nlmsgerr(tcp, fd, family, addr, len, 567 nlmsghdr->nlmsg_flags & NLM_F_CAPPED); 568 return; 569 } 570 571 /* 572 * While most of NLMSG_DONE messages indeed have payloads 573 * containing just a single integer, there are few exceptions, 574 * so pass payloads of NLMSG_DONE messages to family-specific 575 * netlink payload decoders. 576 * 577 * Other types of reserved control messages need no family-specific 578 * netlink payload decoding. 579 */ 580 if ((nlmsghdr->nlmsg_type >= NLMSG_MIN_TYPE 581 || nlmsghdr->nlmsg_type == NLMSG_DONE) 582 && (unsigned int) family < ARRAY_SIZE(netlink_decoders) 583 && netlink_decoders[family] 584 && netlink_decoders[family](tcp, nlmsghdr, addr, len)) { 585 return; 586 } 587 588 if (nlmsghdr->nlmsg_type == NLMSG_DONE && len == sizeof(int)) { 589 int num; 590 591 if (!umove_or_printaddr(tcp, addr, &num)) 592 tprintf("%d", num); 593 return; 594 } 595 596 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 597 } 598 599 static void 600 decode_nlmsghdr_with_payload(struct tcb *const tcp, 601 const int fd, 602 const int family, 603 const struct nlmsghdr *const nlmsghdr, 604 const kernel_ulong_t addr, 605 const kernel_ulong_t len) 606 { 607 const unsigned int nlmsg_len = 608 nlmsghdr->nlmsg_len > len ? len : nlmsghdr->nlmsg_len; 609 610 if (nlmsg_len > NLMSG_HDRLEN) 611 tprints("{"); 612 613 print_nlmsghdr(tcp, fd, family, nlmsghdr); 614 615 if (nlmsg_len > NLMSG_HDRLEN) { 616 tprints(", "); 617 decode_payload(tcp, fd, family, nlmsghdr, addr + NLMSG_HDRLEN, 618 nlmsg_len - NLMSG_HDRLEN); 619 tprints("}"); 620 } 621 } 622 623 void 624 decode_netlink(struct tcb *const tcp, 625 const int fd, 626 kernel_ulong_t addr, 627 kernel_ulong_t len) 628 { 629 const int family = get_fd_nl_family(tcp, fd); 630 631 if (family == NETLINK_KOBJECT_UEVENT) { 632 printstrn(tcp, addr, len); 633 return; 634 } 635 636 struct nlmsghdr nlmsghdr; 637 bool print_array = false; 638 unsigned int elt; 639 640 for (elt = 0; fetch_nlmsghdr(tcp, &nlmsghdr, addr, len); elt++) { 641 if (abbrev(tcp) && elt == max_strlen) { 642 tprints("..."); 643 break; 644 } 645 646 unsigned int nlmsg_len = NLMSG_ALIGN(nlmsghdr.nlmsg_len); 647 kernel_ulong_t next_addr = 0; 648 kernel_ulong_t next_len = 0; 649 650 if (nlmsghdr.nlmsg_len >= NLMSG_HDRLEN) { 651 next_len = (len >= nlmsg_len) ? len - nlmsg_len : 0; 652 653 if (next_len && addr + nlmsg_len > addr) 654 next_addr = addr + nlmsg_len; 655 } 656 657 if (!print_array && next_addr) { 658 tprints("["); 659 print_array = true; 660 } 661 662 decode_nlmsghdr_with_payload(tcp, fd, family, 663 &nlmsghdr, addr, len); 664 665 if (!next_addr) 666 break; 667 668 tprints(", "); 669 addr = next_addr; 670 len = next_len; 671 } 672 673 if (print_array) { 674 tprints("]"); 675 } 676 } 677