1 /* 2 * libnetlink.c RTnetlink service routines. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 * 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <syslog.h> 17 #include <fcntl.h> 18 #include <net/if_arp.h> 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <string.h> 22 #include <errno.h> 23 #include <time.h> 24 #include <sys/uio.h> 25 26 #include "libnetlink.h" 27 28 #ifndef SOL_NETLINK 29 #define SOL_NETLINK 270 30 #endif 31 32 #ifndef MIN 33 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 34 #endif 35 36 int rcvbuf = 1024 * 1024; 37 38 void rtnl_close(struct rtnl_handle *rth) 39 { 40 if (rth->fd >= 0) { 41 close(rth->fd); 42 rth->fd = -1; 43 } 44 } 45 46 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, 47 int protocol) 48 { 49 socklen_t addr_len; 50 int sndbuf = 32768; 51 52 memset(rth, 0, sizeof(*rth)); 53 54 rth->proto = protocol; 55 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); 56 if (rth->fd < 0) { 57 perror("Cannot open netlink socket"); 58 return -1; 59 } 60 61 if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { 62 perror("SO_SNDBUF"); 63 return -1; 64 } 65 66 if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { 67 perror("SO_RCVBUF"); 68 return -1; 69 } 70 71 memset(&rth->local, 0, sizeof(rth->local)); 72 rth->local.nl_family = AF_NETLINK; 73 rth->local.nl_groups = subscriptions; 74 75 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { 76 perror("Cannot bind netlink socket"); 77 return -1; 78 } 79 addr_len = sizeof(rth->local); 80 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { 81 perror("Cannot getsockname"); 82 return -1; 83 } 84 if (addr_len != sizeof(rth->local)) { 85 fprintf(stderr, "Wrong address length %d\n", addr_len); 86 return -1; 87 } 88 if (rth->local.nl_family != AF_NETLINK) { 89 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); 90 return -1; 91 } 92 rth->seq = time(NULL); 93 return 0; 94 } 95 96 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) 97 { 98 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); 99 } 100 101 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 102 { 103 return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); 104 } 105 106 int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, 107 __u32 filt_mask) 108 { 109 struct { 110 struct nlmsghdr nlh; 111 struct ifinfomsg ifm; 112 /* attribute has to be NLMSG aligned */ 113 struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); 114 __u32 ext_filter_mask; 115 } req; 116 117 memset(&req, 0, sizeof(req)); 118 req.nlh.nlmsg_len = sizeof(req); 119 req.nlh.nlmsg_type = type; 120 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; 121 req.nlh.nlmsg_pid = 0; 122 req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 123 req.ifm.ifi_family = family; 124 125 req.ext_req.rta_type = IFLA_EXT_MASK; 126 req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); 127 req.ext_filter_mask = filt_mask; 128 129 return send(rth->fd, (void*)&req, sizeof(req), 0); 130 } 131 132 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) 133 { 134 return send(rth->fd, buf, len, 0); 135 } 136 137 int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) 138 { 139 struct nlmsghdr *h; 140 int status; 141 char resp[1024]; 142 143 status = send(rth->fd, buf, len, 0); 144 if (status < 0) 145 return status; 146 147 /* Check for immediate errors */ 148 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); 149 if (status < 0) { 150 if (errno == EAGAIN) 151 return 0; 152 return -1; 153 } 154 155 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); 156 h = NLMSG_NEXT(h, status)) { 157 if (h->nlmsg_type == NLMSG_ERROR) { 158 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 159 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 160 fprintf(stderr, "ERROR truncated\n"); 161 else 162 errno = -err->error; 163 return -1; 164 } 165 } 166 167 return 0; 168 } 169 170 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 171 { 172 struct nlmsghdr nlh; 173 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 174 struct iovec iov[2] = { 175 { .iov_base = &nlh, .iov_len = sizeof(nlh) }, 176 { .iov_base = req, .iov_len = len } 177 }; 178 struct msghdr msg = { 179 .msg_name = &nladdr, 180 .msg_namelen = sizeof(nladdr), 181 .msg_iov = iov, 182 .msg_iovlen = 2, 183 }; 184 185 nlh.nlmsg_len = NLMSG_LENGTH(len); 186 nlh.nlmsg_type = type; 187 nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; 188 nlh.nlmsg_pid = 0; 189 nlh.nlmsg_seq = rth->dump = ++rth->seq; 190 191 return sendmsg(rth->fd, &msg, 0); 192 } 193 194 int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) 195 { 196 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 197 struct iovec iov = { 198 .iov_base = (void*) n, 199 .iov_len = n->nlmsg_len 200 }; 201 struct msghdr msg = { 202 .msg_name = &nladdr, 203 .msg_namelen = sizeof(nladdr), 204 .msg_iov = &iov, 205 .msg_iovlen = 1, 206 }; 207 208 n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; 209 n->nlmsg_pid = 0; 210 n->nlmsg_seq = rth->dump = ++rth->seq; 211 212 return sendmsg(rth->fd, &msg, 0); 213 } 214 215 int rtnl_dump_filter_l(struct rtnl_handle *rth, 216 const struct rtnl_dump_filter_arg *arg) 217 { 218 struct sockaddr_nl nladdr; 219 struct iovec iov; 220 struct msghdr msg = { 221 .msg_name = &nladdr, 222 .msg_namelen = sizeof(nladdr), 223 .msg_iov = &iov, 224 .msg_iovlen = 1, 225 }; 226 char buf[16384]; 227 int dump_intr = 0; 228 229 iov.iov_base = buf; 230 while (1) { 231 int status; 232 const struct rtnl_dump_filter_arg *a; 233 int found_done = 0; 234 int msglen = 0; 235 236 iov.iov_len = sizeof(buf); 237 status = recvmsg(rth->fd, &msg, 0); 238 239 if (status < 0) { 240 if (errno == EINTR || errno == EAGAIN) 241 continue; 242 fprintf(stderr, "netlink receive error %s (%d)\n", 243 strerror(errno), errno); 244 return -1; 245 } 246 247 if (status == 0) { 248 fprintf(stderr, "EOF on netlink\n"); 249 return -1; 250 } 251 252 if (rth->dump_fp) 253 fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp); 254 255 for (a = arg; a->filter; a++) { 256 struct nlmsghdr *h = (struct nlmsghdr*)buf; 257 msglen = status; 258 259 while (NLMSG_OK(h, msglen)) { 260 int err = 0; 261 262 h->nlmsg_flags &= ~a->nc_flags; 263 264 if (nladdr.nl_pid != 0 || 265 h->nlmsg_pid != rth->local.nl_pid || 266 h->nlmsg_seq != rth->dump) 267 goto skip_it; 268 269 if (h->nlmsg_flags & NLM_F_DUMP_INTR) 270 dump_intr = 1; 271 272 if (h->nlmsg_type == NLMSG_DONE) { 273 found_done = 1; 274 break; /* process next filter */ 275 } 276 if (h->nlmsg_type == NLMSG_ERROR) { 277 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 278 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 279 fprintf(stderr, 280 "ERROR truncated\n"); 281 } else { 282 errno = -err->error; 283 if (rth->proto == NETLINK_SOCK_DIAG && 284 (errno == ENOENT || 285 errno == EOPNOTSUPP)) 286 return -1; 287 288 perror("RTNETLINK answers"); 289 } 290 return -1; 291 } 292 293 if (!rth->dump_fp) { 294 err = a->filter(&nladdr, h, a->arg1); 295 if (err < 0) 296 return err; 297 } 298 299 skip_it: 300 h = NLMSG_NEXT(h, msglen); 301 } 302 } 303 304 if (found_done) { 305 if (dump_intr) 306 fprintf(stderr, 307 "Dump was interrupted and may be inconsistent.\n"); 308 return 0; 309 } 310 311 if (msg.msg_flags & MSG_TRUNC) { 312 fprintf(stderr, "Message truncated\n"); 313 continue; 314 } 315 if (msglen) { 316 fprintf(stderr, "!!!Remnant of size %d\n", msglen); 317 exit(1); 318 } 319 } 320 } 321 322 int rtnl_dump_filter_nc(struct rtnl_handle *rth, 323 rtnl_filter_t filter, 324 void *arg1, __u16 nc_flags) 325 { 326 const struct rtnl_dump_filter_arg a[2] = { 327 { .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, }, 328 { .filter = NULL, .arg1 = NULL, .nc_flags = 0, }, 329 }; 330 331 return rtnl_dump_filter_l(rth, a); 332 } 333 334 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, 335 struct nlmsghdr *answer, size_t maxlen) 336 { 337 int status; 338 unsigned seq; 339 struct nlmsghdr *h; 340 struct sockaddr_nl nladdr; 341 struct iovec iov = { 342 .iov_base = (void*) n, 343 .iov_len = n->nlmsg_len 344 }; 345 struct msghdr msg = { 346 .msg_name = &nladdr, 347 .msg_namelen = sizeof(nladdr), 348 .msg_iov = &iov, 349 .msg_iovlen = 1, 350 }; 351 char buf[32768]; 352 353 memset(&nladdr, 0, sizeof(nladdr)); 354 nladdr.nl_family = AF_NETLINK; 355 356 n->nlmsg_seq = seq = ++rtnl->seq; 357 358 if (answer == NULL) 359 n->nlmsg_flags |= NLM_F_ACK; 360 361 status = sendmsg(rtnl->fd, &msg, 0); 362 if (status < 0) { 363 perror("Cannot talk to rtnetlink"); 364 return -1; 365 } 366 367 memset(buf,0,sizeof(buf)); 368 369 iov.iov_base = buf; 370 while (1) { 371 iov.iov_len = sizeof(buf); 372 status = recvmsg(rtnl->fd, &msg, 0); 373 374 if (status < 0) { 375 if (errno == EINTR || errno == EAGAIN) 376 continue; 377 fprintf(stderr, "netlink receive error %s (%d)\n", 378 strerror(errno), errno); 379 return -1; 380 } 381 if (status == 0) { 382 fprintf(stderr, "EOF on netlink\n"); 383 return -1; 384 } 385 if (msg.msg_namelen != sizeof(nladdr)) { 386 fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); 387 exit(1); 388 } 389 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { 390 int len = h->nlmsg_len; 391 int l = len - sizeof(*h); 392 393 if (l < 0 || len>status) { 394 if (msg.msg_flags & MSG_TRUNC) { 395 fprintf(stderr, "Truncated message\n"); 396 return -1; 397 } 398 fprintf(stderr, "!!!malformed message: len=%d\n", len); 399 exit(1); 400 } 401 402 if (nladdr.nl_pid != 0 || 403 h->nlmsg_pid != rtnl->local.nl_pid || 404 h->nlmsg_seq != seq) { 405 /* Don't forget to skip that message. */ 406 status -= NLMSG_ALIGN(len); 407 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 408 continue; 409 } 410 411 if (h->nlmsg_type == NLMSG_ERROR) { 412 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 413 if (l < sizeof(struct nlmsgerr)) { 414 fprintf(stderr, "ERROR truncated\n"); 415 } else if (!err->error) { 416 if (answer) 417 memcpy(answer, h, 418 MIN(maxlen, h->nlmsg_len)); 419 return 0; 420 } 421 422 if (rtnl->proto != NETLINK_SOCK_DIAG) 423 fprintf(stderr, 424 "RTNETLINK answers: %s\n", 425 strerror(-err->error)); 426 errno = -err->error; 427 return -1; 428 } 429 430 if (answer) { 431 memcpy(answer, h, 432 MIN(maxlen, h->nlmsg_len)); 433 return 0; 434 } 435 436 fprintf(stderr, "Unexpected reply!!!\n"); 437 438 status -= NLMSG_ALIGN(len); 439 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 440 } 441 442 if (msg.msg_flags & MSG_TRUNC) { 443 fprintf(stderr, "Message truncated\n"); 444 continue; 445 } 446 447 if (status) { 448 fprintf(stderr, "!!!Remnant of size %d\n", status); 449 exit(1); 450 } 451 } 452 } 453 454 int rtnl_listen_all_nsid(struct rtnl_handle *rth) 455 { 456 unsigned int on = 1; 457 458 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on, 459 sizeof(on)) < 0) { 460 perror("NETLINK_LISTEN_ALL_NSID"); 461 return -1; 462 } 463 rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID; 464 return 0; 465 } 466 467 int rtnl_listen(struct rtnl_handle *rtnl, 468 rtnl_listen_filter_t handler, 469 void *jarg) 470 { 471 int status; 472 struct nlmsghdr *h; 473 struct sockaddr_nl nladdr; 474 struct iovec iov; 475 struct msghdr msg = { 476 .msg_name = &nladdr, 477 .msg_namelen = sizeof(nladdr), 478 .msg_iov = &iov, 479 .msg_iovlen = 1, 480 }; 481 char buf[16384]; 482 char cmsgbuf[BUFSIZ]; 483 484 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) { 485 msg.msg_control = &cmsgbuf; 486 msg.msg_controllen = sizeof(cmsgbuf); 487 } 488 489 memset(&nladdr, 0, sizeof(nladdr)); 490 nladdr.nl_family = AF_NETLINK; 491 nladdr.nl_pid = 0; 492 nladdr.nl_groups = 0; 493 494 iov.iov_base = buf; 495 while (1) { 496 struct rtnl_ctrl_data ctrl; 497 struct cmsghdr *cmsg; 498 499 iov.iov_len = sizeof(buf); 500 status = recvmsg(rtnl->fd, &msg, 0); 501 502 if (status < 0) { 503 if (errno == EINTR || errno == EAGAIN) 504 continue; 505 fprintf(stderr, "netlink receive error %s (%d)\n", 506 strerror(errno), errno); 507 if (errno == ENOBUFS) 508 continue; 509 return -1; 510 } 511 if (status == 0) { 512 fprintf(stderr, "EOF on netlink\n"); 513 return -1; 514 } 515 if (msg.msg_namelen != sizeof(nladdr)) { 516 fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); 517 exit(1); 518 } 519 520 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) { 521 memset(&ctrl, 0, sizeof(ctrl)); 522 ctrl.nsid = -1; 523 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; 524 cmsg = CMSG_NXTHDR(&msg, cmsg)) 525 if (cmsg->cmsg_level == SOL_NETLINK && 526 cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID && 527 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { 528 int *data = (int *)CMSG_DATA(cmsg); 529 530 ctrl.nsid = *data; 531 } 532 } 533 534 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { 535 int err; 536 int len = h->nlmsg_len; 537 int l = len - sizeof(*h); 538 539 if (l<0 || len>status) { 540 if (msg.msg_flags & MSG_TRUNC) { 541 fprintf(stderr, "Truncated message\n"); 542 return -1; 543 } 544 fprintf(stderr, "!!!malformed message: len=%d\n", len); 545 exit(1); 546 } 547 548 err = handler(&nladdr, &ctrl, h, jarg); 549 if (err < 0) 550 return err; 551 552 status -= NLMSG_ALIGN(len); 553 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 554 } 555 if (msg.msg_flags & MSG_TRUNC) { 556 fprintf(stderr, "Message truncated\n"); 557 continue; 558 } 559 if (status) { 560 fprintf(stderr, "!!!Remnant of size %d\n", status); 561 exit(1); 562 } 563 } 564 } 565 566 int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, 567 void *jarg) 568 { 569 int status; 570 struct sockaddr_nl nladdr; 571 char buf[16384]; 572 struct nlmsghdr *h = (void*)buf; 573 574 memset(&nladdr, 0, sizeof(nladdr)); 575 nladdr.nl_family = AF_NETLINK; 576 nladdr.nl_pid = 0; 577 nladdr.nl_groups = 0; 578 579 while (1) { 580 int err, len; 581 int l; 582 583 status = fread(&buf, 1, sizeof(*h), rtnl); 584 585 if (status < 0) { 586 if (errno == EINTR) 587 continue; 588 perror("rtnl_from_file: fread"); 589 return -1; 590 } 591 if (status == 0) 592 return 0; 593 594 len = h->nlmsg_len; 595 l = len - sizeof(*h); 596 597 if (l<0 || len>sizeof(buf)) { 598 fprintf(stderr, "!!!malformed message: len=%d @%lu\n", 599 len, ftell(rtnl)); 600 return -1; 601 } 602 603 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); 604 605 if (status < 0) { 606 perror("rtnl_from_file: fread"); 607 return -1; 608 } 609 if (status < l) { 610 fprintf(stderr, "rtnl-from_file: truncated message\n"); 611 return -1; 612 } 613 614 err = handler(&nladdr, NULL, h, jarg); 615 if (err < 0) 616 return err; 617 } 618 } 619 620 int addattr(struct nlmsghdr *n, int maxlen, int type) 621 { 622 return addattr_l(n, maxlen, type, NULL, 0); 623 } 624 625 int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) 626 { 627 return addattr_l(n, maxlen, type, &data, sizeof(__u8)); 628 } 629 630 int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data) 631 { 632 return addattr_l(n, maxlen, type, &data, sizeof(__u16)); 633 } 634 635 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) 636 { 637 return addattr_l(n, maxlen, type, &data, sizeof(__u32)); 638 } 639 640 int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data) 641 { 642 return addattr_l(n, maxlen, type, &data, sizeof(__u64)); 643 } 644 645 int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) 646 { 647 return addattr_l(n, maxlen, type, str, strlen(str)+1); 648 } 649 650 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 651 int alen) 652 { 653 int len = RTA_LENGTH(alen); 654 struct rtattr *rta; 655 656 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { 657 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); 658 return -1; 659 } 660 rta = NLMSG_TAIL(n); 661 rta->rta_type = type; 662 rta->rta_len = len; 663 memcpy(RTA_DATA(rta), data, alen); 664 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 665 return 0; 666 } 667 668 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) 669 { 670 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { 671 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); 672 return -1; 673 } 674 675 memcpy(NLMSG_TAIL(n), data, len); 676 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); 677 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); 678 return 0; 679 } 680 681 struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) 682 { 683 struct rtattr *nest = NLMSG_TAIL(n); 684 685 addattr_l(n, maxlen, type, NULL, 0); 686 return nest; 687 } 688 689 int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) 690 { 691 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; 692 return n->nlmsg_len; 693 } 694 695 struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, 696 const void *data, int len) 697 { 698 struct rtattr *start = NLMSG_TAIL(n); 699 700 addattr_l(n, maxlen, type, data, len); 701 addattr_nest(n, maxlen, type); 702 return start; 703 } 704 705 int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) 706 { 707 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); 708 709 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; 710 addattr_nest_end(n, nest); 711 return n->nlmsg_len; 712 } 713 714 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) 715 { 716 int len = RTA_LENGTH(4); 717 struct rtattr *subrta; 718 719 if (RTA_ALIGN(rta->rta_len) + len > maxlen) { 720 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); 721 return -1; 722 } 723 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 724 subrta->rta_type = type; 725 subrta->rta_len = len; 726 memcpy(RTA_DATA(subrta), &data, 4); 727 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; 728 return 0; 729 } 730 731 int rta_addattr_l(struct rtattr *rta, int maxlen, int type, 732 const void *data, int alen) 733 { 734 struct rtattr *subrta; 735 int len = RTA_LENGTH(alen); 736 737 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { 738 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); 739 return -1; 740 } 741 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 742 subrta->rta_type = type; 743 subrta->rta_len = len; 744 memcpy(RTA_DATA(subrta), data, alen); 745 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); 746 return 0; 747 } 748 749 int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data) 750 { 751 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8)); 752 } 753 754 int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data) 755 { 756 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16)); 757 } 758 759 int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data) 760 { 761 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64)); 762 } 763 764 struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type) 765 { 766 struct rtattr *nest = RTA_TAIL(rta); 767 768 rta_addattr_l(rta, maxlen, type, NULL, 0); 769 770 return nest; 771 } 772 773 int rta_nest_end(struct rtattr *rta, struct rtattr *nest) 774 { 775 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest; 776 777 return rta->rta_len; 778 } 779 780 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 781 { 782 return parse_rtattr_flags(tb, max, rta, len, 0); 783 } 784 785 int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, 786 int len, unsigned short flags) 787 { 788 unsigned short type; 789 790 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 791 while (RTA_OK(rta, len)) { 792 type = rta->rta_type & ~flags; 793 if ((type <= max) && (!tb[type])) 794 tb[type] = rta; 795 rta = RTA_NEXT(rta,len); 796 } 797 if (len) 798 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 799 return 0; 800 } 801 802 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) 803 { 804 int i = 0; 805 806 memset(tb, 0, sizeof(struct rtattr *) * max); 807 while (RTA_OK(rta, len)) { 808 if (rta->rta_type <= max && i < max) 809 tb[i++] = rta; 810 rta = RTA_NEXT(rta,len); 811 } 812 if (len) 813 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 814 return i; 815 } 816 817 struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len) 818 { 819 while (RTA_OK(rta, len)) { 820 if (rta->rta_type == type) 821 return rta; 822 rta = RTA_NEXT(rta, len); 823 } 824 if (len) 825 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 826 return NULL; 827 } 828 829 int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, 830 int len) 831 { 832 if (RTA_PAYLOAD(rta) < len) 833 return -1; 834 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { 835 rta = RTA_DATA(rta) + RTA_ALIGN(len); 836 return parse_rtattr_nested(tb, max, rta); 837 } 838 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 839 return 0; 840 } 841