1 /* 2 * lib/idiag/idiagnl_msg_obj.c Inet Diag Message Object 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) 2013 Sassano Systems LLC <joe (at) sassanosystems.com> 10 */ 11 12 #include <netlink-private/netlink.h> 13 #include <netlink/idiag/msg.h> 14 #include <netlink/idiag/meminfo.h> 15 #include <netlink/idiag/vegasinfo.h> 16 #include <linux/inet_diag.h> 17 18 /** 19 * @ingroup idiag 20 * @defgroup idiagnl_msg Inet Diag Messages 21 * 22 * @details 23 * @idiagnl_doc{idiagnl_msg, Inet Diag Message Documentation} 24 * @{ 25 */ 26 struct idiagnl_msg *idiagnl_msg_alloc(void) 27 { 28 return (struct idiagnl_msg *) nl_object_alloc(&idiagnl_msg_obj_ops); 29 } 30 31 void idiagnl_msg_get(struct idiagnl_msg *msg) 32 { 33 nl_object_get((struct nl_object *) msg); 34 } 35 36 void idiagnl_msg_put(struct idiagnl_msg *msg) 37 { 38 nl_object_put((struct nl_object *) msg); 39 } 40 41 static struct nl_cache_ops idiagnl_msg_ops; 42 43 static int idiagnl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 44 struct nlmsghdr *nlh, struct nl_parser_param *pp) 45 { 46 struct idiagnl_msg *msg = NULL; 47 int err = 0; 48 49 if ((err = idiagnl_msg_parse(nlh, &msg)) < 0) 50 return err; 51 52 err = pp->pp_cb((struct nl_object *) msg, pp); 53 idiagnl_msg_put(msg); 54 55 return err; 56 } 57 58 static int idiagnl_request_update(struct nl_cache *cache, struct nl_sock *sk) 59 { 60 int family = cache->c_iarg1; 61 int states = cache->c_iarg2; 62 63 return idiagnl_send_simple(sk, 0, family, states, IDIAG_ATTR_ALL); 64 } 65 66 static struct nl_cache_ops idiagnl_msg_ops = { 67 .co_name = "idiag/idiag", 68 .co_hdrsize = sizeof(struct inet_diag_msg), 69 .co_msgtypes = { 70 { IDIAG_TCPDIAG_GETSOCK, NL_ACT_NEW, "new" }, 71 { IDIAG_DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" }, 72 END_OF_MSGTYPES_LIST, 73 }, 74 .co_protocol = NETLINK_INET_DIAG, 75 .co_request_update = idiagnl_request_update, 76 .co_msg_parser = idiagnl_msg_parser, 77 .co_obj_ops = &idiagnl_msg_obj_ops, 78 }; 79 80 static void __init idiagnl_init(void) 81 { 82 nl_cache_mngt_register(&idiagnl_msg_ops); 83 } 84 85 static void __exit idiagnl_exit(void) 86 { 87 nl_cache_mngt_unregister(&idiagnl_msg_ops); 88 } 89 90 /** 91 * @name Cache Management 92 * @{ 93 */ 94 95 /** 96 * Build an inetdiag cache to hold socket state information. 97 * @arg sk Netlink socket 98 * @arg family The address family to query 99 * @arg states Socket states to query 100 * @arg result Result pointer 101 * 102 * @note The caller is responsible for destroying and free the cache after using 103 * it. 104 * @return 0 on success of a negative error code. 105 */ 106 int idiagnl_msg_alloc_cache(struct nl_sock *sk, int family, int states, 107 struct nl_cache **result) 108 { 109 struct nl_cache *cache = NULL; 110 int err; 111 112 if (!(cache = nl_cache_alloc(&idiagnl_msg_ops))) 113 return -NLE_NOMEM; 114 115 cache->c_iarg1 = family; 116 cache->c_iarg2 = states; 117 118 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 119 free(cache); 120 return err; 121 } 122 123 *result = cache; 124 return 0; 125 } 126 127 /** @} */ 128 129 /** 130 * @name Attributes 131 * @{ 132 */ 133 134 uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg) 135 { 136 return msg->idiag_family; 137 } 138 139 void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family) 140 { 141 msg->idiag_family = family; 142 } 143 144 uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg) 145 { 146 return msg->idiag_state; 147 } 148 149 void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state) 150 { 151 msg->idiag_state = state; 152 } 153 154 uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg) 155 { 156 return msg->idiag_timer; 157 } 158 159 void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer) 160 { 161 msg->idiag_timer = timer; 162 } 163 164 uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg) 165 { 166 return msg->idiag_retrans; 167 } 168 169 void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans) 170 { 171 msg->idiag_retrans = retrans; 172 } 173 174 uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg) 175 { 176 return msg->idiag_sport; 177 } 178 179 void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port) 180 { 181 msg->idiag_sport = port; 182 } 183 184 uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg) 185 { 186 return msg->idiag_dport; 187 } 188 189 void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port) 190 { 191 msg->idiag_dport = port; 192 } 193 194 struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg) 195 { 196 return msg->idiag_src; 197 } 198 199 int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr) 200 { 201 if (msg->idiag_src) 202 nl_addr_put(msg->idiag_src); 203 204 nl_addr_get(addr); 205 msg->idiag_src = addr; 206 207 return 0; 208 } 209 210 struct nl_addr *idiagnl_msg_get_dst(const struct idiagnl_msg *msg) 211 { 212 return msg->idiag_dst; 213 } 214 215 int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr) 216 { 217 if (msg->idiag_dst) 218 nl_addr_put(msg->idiag_dst); 219 220 nl_addr_get(addr); 221 msg->idiag_dst = addr; 222 223 return 0; 224 } 225 226 uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg) 227 { 228 return msg->idiag_ifindex; 229 } 230 231 void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex) 232 { 233 msg->idiag_ifindex = ifindex; 234 } 235 236 uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg) 237 { 238 return msg->idiag_expires; 239 } 240 241 void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires) 242 { 243 msg->idiag_expires = expires; 244 } 245 246 uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg) 247 { 248 return msg->idiag_rqueue; 249 } 250 251 void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue) 252 { 253 msg->idiag_rqueue = rqueue; 254 } 255 256 uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg) 257 { 258 return msg->idiag_wqueue; 259 } 260 261 void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue) 262 { 263 msg->idiag_wqueue = wqueue; 264 } 265 266 uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg) 267 { 268 return msg->idiag_uid; 269 } 270 271 void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid) 272 { 273 msg->idiag_uid = uid; 274 } 275 276 uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg) 277 { 278 return msg->idiag_inode; 279 } 280 281 void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode) 282 { 283 msg->idiag_inode = inode; 284 } 285 286 uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg) 287 { 288 return msg->idiag_tos; 289 } 290 291 void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos) 292 { 293 msg->idiag_tos = tos; 294 } 295 296 uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg) 297 { 298 return msg->idiag_tclass; 299 } 300 301 void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass) 302 { 303 msg->idiag_tclass = tclass; 304 } 305 306 uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg) 307 { 308 return msg->idiag_shutdown; 309 } 310 311 void idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown) 312 { 313 msg->idiag_shutdown = shutdown; 314 } 315 316 char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg) 317 { 318 return msg->idiag_cong; 319 } 320 321 void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong) 322 { 323 msg->idiag_cong = strdup(cong); 324 } 325 326 struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg) 327 { 328 return msg->idiag_meminfo; 329 } 330 331 void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo 332 *minfo) 333 { 334 if (msg->idiag_meminfo) 335 idiagnl_meminfo_put(msg->idiag_meminfo); 336 337 idiagnl_meminfo_get(minfo); 338 msg->idiag_meminfo = minfo; 339 } 340 341 struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg) 342 { 343 return msg->idiag_vegasinfo; 344 } 345 346 void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo 347 *vinfo) 348 { 349 if (msg->idiag_vegasinfo) 350 idiagnl_vegasinfo_put(msg->idiag_vegasinfo); 351 352 idiagnl_vegasinfo_get(vinfo); 353 msg->idiag_vegasinfo = vinfo; 354 } 355 356 struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg) 357 { 358 return msg->idiag_tcpinfo; 359 } 360 361 void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo) 362 { 363 memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info)); 364 } 365 366 /** @} */ 367 368 static void idiag_msg_dump_line(struct nl_object *a, struct nl_dump_params *p) 369 { 370 struct idiagnl_msg *msg = (struct idiagnl_msg *) a; 371 char buf[64] = { 0 }; 372 373 nl_dump_line(p, "family: %s ", nl_af2str(msg->idiag_family, buf, sizeof(buf))); 374 nl_dump(p, "src: %s:%d ", nl_addr2str(msg->idiag_src, buf, sizeof(buf)), 375 ntohs(msg->idiag_sport)); 376 nl_dump(p, "dst: %s:%d ", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)), 377 ntohs(msg->idiag_dport)); 378 nl_dump(p, "iif: %d ", msg->idiag_ifindex); 379 nl_dump(p, "\n"); 380 } 381 382 static void idiag_msg_dump_details(struct nl_object *a, struct nl_dump_params *p) 383 { 384 struct idiagnl_msg *msg = (struct idiagnl_msg *) a; 385 char buf[64], buf2[64]; 386 387 nl_dump(p, "\nfamily: %s\n", nl_af2str(msg->idiag_family, buf, sizeof(buf))); 388 nl_dump(p, "state: %s\n", 389 idiagnl_state2str(msg->idiag_state, buf, sizeof(buf))); 390 nl_dump(p, "timer (%s, %s, retransmits: %d)\n", 391 idiagnl_timer2str(msg->idiag_timer, buf, sizeof(buf)), 392 nl_msec2str(msg->idiag_expires, buf2, sizeof(buf2)), 393 msg->idiag_retrans); 394 395 nl_dump(p, "source: %s:%d\n", nl_addr2str(msg->idiag_src, buf, sizeof(buf)), 396 ntohs(msg->idiag_sport)); 397 nl_dump(p, "destination: %s:%d\n", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)), 398 ntohs(msg->idiag_dport)); 399 400 nl_dump(p, "ifindex: %d\n", msg->idiag_ifindex); 401 nl_dump(p, "rqueue: %-6d wqueue: %-6d\n", msg->idiag_rqueue, msg->idiag_wqueue); 402 nl_dump(p, "uid %d\n", msg->idiag_uid); 403 nl_dump(p, "inode %d\n", msg->idiag_inode); 404 if (msg->idiag_shutdown) { 405 nl_dump(p, "socket shutdown: %s\n", 406 idiagnl_shutdown2str(msg->idiag_shutdown, 407 buf, sizeof(buf))); 408 } 409 410 nl_dump(p, "tos: 0x%x\n", msg->idiag_tos); 411 nl_dump(p, "traffic class: %d\n", msg->idiag_tclass); 412 nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong); 413 } 414 415 static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 416 { 417 struct idiagnl_msg *msg = (struct idiagnl_msg *) obj; 418 char buf[64]; 419 420 idiag_msg_dump_details(obj, p); 421 422 nl_dump(p, "tcp info: [\n"); 423 nl_dump(p, "\tsocket state: %s\n", 424 idiagnl_state2str(msg->idiag_tcpinfo.tcpi_state, 425 buf, sizeof(buf))); 426 nl_dump(p, "\ttcp state: %s\n", 427 idiagnl_tcpstate2str(msg->idiag_tcpinfo.tcpi_ca_state, 428 buf, sizeof(buf))); 429 nl_dump(p, "\tretransmits: %d\n", 430 msg->idiag_tcpinfo.tcpi_retransmits); 431 nl_dump(p, "\tprobes: %d\n", 432 msg->idiag_tcpinfo.tcpi_probes); 433 nl_dump(p, "\tbackoff: %d\n", 434 msg->idiag_tcpinfo.tcpi_backoff); 435 nl_dump(p, "\toptions: %s\n", 436 idiagnl_tcpopts2str(msg->idiag_tcpinfo.tcpi_options, 437 buf, sizeof(buf))); 438 nl_dump(p, "\tsnd_wscale: %d\n", msg->idiag_tcpinfo.tcpi_snd_wscale); 439 nl_dump(p, "\trcv_wscale: %d\n", msg->idiag_tcpinfo.tcpi_rcv_wscale); 440 nl_dump(p, "\trto: %d\n", msg->idiag_tcpinfo.tcpi_rto); 441 nl_dump(p, "\tato: %d\n", msg->idiag_tcpinfo.tcpi_ato); 442 nl_dump(p, "\tsnd_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_snd_mss, 443 buf, sizeof(buf))); 444 nl_dump(p, "\trcv_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_mss, 445 buf, sizeof(buf))); 446 nl_dump(p, "\tunacked: %d\n", msg->idiag_tcpinfo.tcpi_unacked); 447 nl_dump(p, "\tsacked: %d\n", msg->idiag_tcpinfo.tcpi_sacked); 448 449 nl_dump(p, "\tlost: %d\n", msg->idiag_tcpinfo.tcpi_lost); 450 nl_dump(p, "\tretransmit segments: %d\n", 451 msg->idiag_tcpinfo.tcpi_retrans); 452 nl_dump(p, "\tfackets: %d\n", 453 msg->idiag_tcpinfo.tcpi_fackets); 454 nl_dump(p, "\tlast data sent: %s\n", 455 nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_sent, buf, 456 sizeof(buf))); 457 nl_dump(p, "\tlast ack sent: %s\n", 458 nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_sent, buf, sizeof(buf))); 459 nl_dump(p, "\tlast data recv: %s\n", 460 nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_recv, buf, 461 sizeof(buf))); 462 nl_dump(p, "\tlast ack recv: %s\n", 463 nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_recv, buf, 464 sizeof(buf))); 465 nl_dump(p, "\tpath mtu: %s\n", 466 nl_size2str(msg->idiag_tcpinfo.tcpi_pmtu, buf, 467 sizeof(buf))); 468 nl_dump(p, "\trcv ss threshold: %d\n", 469 msg->idiag_tcpinfo.tcpi_rcv_ssthresh); 470 nl_dump(p, "\tsmoothed round trip time: %d\n", 471 msg->idiag_tcpinfo.tcpi_rtt); 472 nl_dump(p, "\tround trip time variation: %d\n", 473 msg->idiag_tcpinfo.tcpi_rttvar); 474 nl_dump(p, "\tsnd ss threshold: %s\n", 475 nl_size2str(msg->idiag_tcpinfo.tcpi_snd_ssthresh, buf, 476 sizeof(buf))); 477 nl_dump(p, "\tsend congestion window: %d\n", 478 msg->idiag_tcpinfo.tcpi_snd_cwnd); 479 nl_dump(p, "\tadvertised mss: %s\n", 480 nl_size2str(msg->idiag_tcpinfo.tcpi_advmss, buf, 481 sizeof(buf))); 482 nl_dump(p, "\treordering: %d\n", 483 msg->idiag_tcpinfo.tcpi_reordering); 484 nl_dump(p, "\trcv rround trip time: %d\n", 485 msg->idiag_tcpinfo.tcpi_rcv_rtt); 486 nl_dump(p, "\treceive queue space: %s\n", 487 nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_space, buf, 488 sizeof(buf))); 489 nl_dump(p, "\ttotal retransmits: %d\n", 490 msg->idiag_tcpinfo.tcpi_total_retrans); 491 nl_dump(p, "]\n"); 492 493 if (msg->idiag_meminfo) { 494 nl_dump(p, "meminfo: [\n"); 495 nl_dump(p, "\trmem: %s\n", 496 nl_size2str(msg->idiag_meminfo->idiag_rmem, 497 buf, 498 sizeof(buf))); 499 nl_dump(p, "\twmem: %s\n", 500 nl_size2str(msg->idiag_meminfo->idiag_wmem, 501 buf, 502 sizeof(buf))); 503 nl_dump(p, "\tfmem: %s\n", 504 nl_size2str(msg->idiag_meminfo->idiag_fmem, 505 buf, 506 sizeof(buf))); 507 nl_dump(p, "\ttmem: %s\n", 508 nl_size2str(msg->idiag_meminfo->idiag_tmem, 509 buf, 510 sizeof(buf))); 511 nl_dump(p, "]\n"); 512 } 513 514 if (msg->idiag_vegasinfo) { 515 nl_dump(p, "vegasinfo: [\n"); 516 nl_dump(p, "\tvegas enabled: %d\n", 517 msg->idiag_vegasinfo->tcpv_enabled); 518 if (msg->idiag_vegasinfo->tcpv_enabled) { 519 nl_dump(p, "\trtt cnt: %d", 520 msg->idiag_vegasinfo->tcpv_rttcnt); 521 nl_dump(p, "\trtt (propagation delay): %d", 522 msg->idiag_vegasinfo->tcpv_rtt); 523 nl_dump(p, "\tmin rtt: %d", 524 msg->idiag_vegasinfo->tcpv_minrtt); 525 } 526 nl_dump(p, "]\n"); 527 } 528 529 nl_dump(p, "skmeminfo: [\n"); 530 nl_dump(p, "\trmem alloc: %d\n", 531 msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RMEM_ALLOC]); 532 nl_dump(p, "\trcv buf: %s\n", 533 nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RCVBUF], 534 buf, sizeof(buf))); 535 nl_dump(p, "\twmem alloc: %d\n", 536 msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_ALLOC]); 537 nl_dump(p, "\tsnd buf: %s\n", 538 nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_SNDBUF], 539 buf, sizeof(buf))); 540 nl_dump(p, "\tfwd alloc: %d\n", 541 msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_FWD_ALLOC]); 542 nl_dump(p, "\twmem queued: %s\n", 543 nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_QUEUED], 544 buf, sizeof(buf))); 545 nl_dump(p, "\topt mem: %d\n", 546 msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_OPTMEM]); 547 nl_dump(p, "\tbacklog: %d\n", 548 msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_BACKLOG]); 549 nl_dump(p, "]\n\n"); 550 } 551 552 static void idiagnl_msg_free(struct nl_object *a) 553 { 554 struct idiagnl_msg *msg = (struct idiagnl_msg *) a; 555 if (a == NULL) 556 return; 557 558 free(msg->idiag_cong); 559 nl_addr_put(msg->idiag_src); 560 nl_addr_put(msg->idiag_dst); 561 idiagnl_meminfo_put(msg->idiag_meminfo); 562 idiagnl_vegasinfo_put(msg->idiag_vegasinfo); 563 } 564 565 static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src) 566 { 567 struct idiagnl_msg *dst = (struct idiagnl_msg *) _dst; 568 struct idiagnl_msg *src = (struct idiagnl_msg *) _src; 569 570 if (src->idiag_src) 571 if (!(dst->idiag_src = nl_addr_clone(src->idiag_src))) 572 return -NLE_NOMEM; 573 574 if (src->idiag_dst) 575 if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst))) 576 return -NLE_NOMEM; 577 578 return 0; 579 } 580 581 static struct nla_policy ext_policy[IDIAG_ATTR_MAX] = { 582 [IDIAG_ATTR_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) }, 583 [IDIAG_ATTR_INFO] = { .minlen = sizeof(struct tcp_info) }, 584 [IDIAG_ATTR_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) }, 585 [IDIAG_ATTR_CONG] = { .type = NLA_STRING }, 586 [IDIAG_ATTR_TOS] = { .type = NLA_U8 }, 587 [IDIAG_ATTR_TCLASS] = { .type = NLA_U8 }, 588 [IDIAG_ATTR_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * IDIAG_SK_MEMINFO_VARS) }, 589 [IDIAG_ATTR_SHUTDOWN] = { .type = NLA_U8 }, 590 }; 591 592 int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) 593 { 594 struct idiagnl_msg *msg = NULL; 595 struct inet_diag_msg *raw_msg = NULL; 596 struct nl_addr *src = NULL, *dst = NULL; 597 struct nlattr *tb[IDIAG_ATTR_MAX]; 598 int err = 0; 599 600 msg = idiagnl_msg_alloc(); 601 if (!msg) 602 goto errout_nomem; 603 604 err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX, 605 ext_policy); 606 if (err < 0) 607 goto errout; 608 609 raw_msg = nlmsg_data(nlh); 610 msg->idiag_family = raw_msg->idiag_family; 611 msg->idiag_state = raw_msg->idiag_state; 612 msg->idiag_timer = raw_msg->idiag_timer; 613 msg->idiag_retrans = raw_msg->idiag_retrans; 614 msg->idiag_expires = raw_msg->idiag_expires; 615 msg->idiag_rqueue = raw_msg->idiag_rqueue; 616 msg->idiag_wqueue = raw_msg->idiag_wqueue; 617 msg->idiag_uid = raw_msg->idiag_uid; 618 msg->idiag_inode = raw_msg->idiag_inode; 619 msg->idiag_sport = raw_msg->id.idiag_sport; 620 msg->idiag_dport = raw_msg->id.idiag_dport; 621 msg->idiag_ifindex = raw_msg->id.idiag_if; 622 623 dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst, 624 sizeof(raw_msg->id.idiag_dst)); 625 if (!dst) 626 goto errout_nomem; 627 628 err = idiagnl_msg_set_dst(msg, dst); 629 if (err < 0) 630 goto errout; 631 632 nl_addr_put(dst); 633 634 src = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_src, 635 sizeof(raw_msg->id.idiag_src)); 636 if (!src) 637 goto errout_nomem; 638 639 err = idiagnl_msg_set_src(msg, src); 640 if (err < 0) 641 goto errout; 642 643 nl_addr_put(src); 644 645 if (tb[IDIAG_ATTR_TOS]) 646 msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]); 647 648 if (tb[IDIAG_ATTR_TCLASS]) 649 msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]); 650 651 if (tb[IDIAG_ATTR_SHUTDOWN]) 652 msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]); 653 654 if (tb[IDIAG_ATTR_CONG]) 655 msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]); 656 657 if (tb[IDIAG_ATTR_INFO]) 658 nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO], 659 sizeof(msg->idiag_tcpinfo)); 660 661 if (tb[IDIAG_ATTR_MEMINFO]) { 662 struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc(); 663 struct inet_diag_meminfo *raw_minfo = NULL; 664 665 if (!minfo) 666 goto errout_nomem; 667 668 raw_minfo = (struct inet_diag_meminfo *) 669 nla_data(tb[IDIAG_ATTR_MEMINFO]); 670 671 idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem); 672 idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem); 673 idiagnl_meminfo_set_fmem(minfo, raw_minfo->idiag_fmem); 674 idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem); 675 676 msg->idiag_meminfo = minfo; 677 } 678 679 if (tb[IDIAG_ATTR_VEGASINFO]) { 680 struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc(); 681 struct tcpvegas_info *raw_vinfo = NULL; 682 683 if (!vinfo) 684 goto errout_nomem; 685 686 raw_vinfo = (struct tcpvegas_info *) 687 nla_data(tb[IDIAG_ATTR_VEGASINFO]); 688 689 idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled); 690 idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt); 691 idiagnl_vegasinfo_set_rtt(vinfo, raw_vinfo->tcpv_rtt); 692 idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt); 693 694 msg->idiag_vegasinfo = vinfo; 695 } 696 697 if (tb[IDIAG_ATTR_SKMEMINFO]) 698 nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO], 699 sizeof(msg->idiag_skmeminfo)); 700 701 *result = msg; 702 return 0; 703 704 errout: 705 idiagnl_msg_put(msg); 706 return err; 707 708 errout_nomem: 709 err = -NLE_NOMEM; 710 goto errout; 711 } 712 713 /** @cond SKIP */ 714 struct nl_object_ops idiagnl_msg_obj_ops = { 715 .oo_name = "idiag/idiag_msg", 716 .oo_size = sizeof(struct idiagnl_msg), 717 .oo_free_data = idiagnl_msg_free, 718 .oo_clone = idiagnl_msg_clone, 719 .oo_dump = { 720 [NL_DUMP_LINE] = idiag_msg_dump_line, 721 [NL_DUMP_DETAILS] = idiag_msg_dump_details, 722 [NL_DUMP_STATS] = idiag_msg_dump_stats, 723 }, 724 .oo_attrs2str = idiagnl_attrs2str, 725 .oo_id_attrs = (IDIAG_ATTR_INFO) 726 }; 727 /** @endcond */ 728 729 /** @} */ 730