1/* vi: set sw=4 ts=4: */ 2/* 3 * ipaddress.c "ip address". 4 * 5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 6 * 7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 8 * 9 * Changes: 10 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated 11 */ 12 13//#include <sys/socket.h> 14//#include <sys/ioctl.h> 15#include <fnmatch.h> 16#include <net/if.h> 17#include <net/if_arp.h> 18 19#include "ip_common.h" /* #include "libbb.h" is inside */ 20#include "rt_names.h" 21#include "utils.h" 22 23 24typedef struct filter_t { 25 int ifindex; 26 int family; 27 int oneline; 28 int showqueue; 29 inet_prefix pfx; 30 int scope, scopemask; 31 int flags, flagmask; 32 int up; 33 char *label; 34 int flushed; 35 char *flushb; 36 int flushp; 37 int flushe; 38 struct rtnl_handle *rth; 39} filter_t; 40 41#define filter (*(filter_t*)&bb_common_bufsiz1) 42 43 44static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) 45{ 46 fprintf(fp, "<"); 47 flags &= ~IFF_RUNNING; 48#define _PF(f) if (flags&IFF_##f) { \ 49 flags &= ~IFF_##f; \ 50 fprintf(fp, #f "%s", flags ? "," : ""); } 51 _PF(LOOPBACK); 52 _PF(BROADCAST); 53 _PF(POINTOPOINT); 54 _PF(MULTICAST); 55 _PF(NOARP); 56 _PF(UP); 57#undef _PF 58 if (flags) 59 fprintf(fp, "%x", flags); 60 if (mdown) 61 fprintf(fp, ",M-DOWN"); 62 fprintf(fp, "> "); 63} 64 65static void print_queuelen(char *name) 66{ 67 struct ifreq ifr; 68 int s; 69 70 s = socket(AF_INET, SOCK_STREAM, 0); 71 if (s < 0) 72 return; 73 74 memset(&ifr, 0, sizeof(ifr)); 75 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 76 if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) { 77 close(s); 78 return; 79 } 80 close(s); 81 82 if (ifr.ifr_qlen) 83 printf("qlen %d", ifr.ifr_qlen); 84} 85 86static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, 87 const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) 88{ 89 FILE *fp = (FILE*)arg; 90 struct ifinfomsg *ifi = NLMSG_DATA(n); 91 struct rtattr * tb[IFLA_MAX+1]; 92 int len = n->nlmsg_len; 93 unsigned m_flag = 0; 94 95 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) 96 return 0; 97 98 len -= NLMSG_LENGTH(sizeof(*ifi)); 99 if (len < 0) 100 return -1; 101 102 if (filter.ifindex && ifi->ifi_index != filter.ifindex) 103 return 0; 104 if (filter.up && !(ifi->ifi_flags&IFF_UP)) 105 return 0; 106 107 memset(tb, 0, sizeof(tb)); 108 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); 109 if (tb[IFLA_IFNAME] == NULL) { 110 bb_error_msg("nil ifname"); 111 return -1; 112 } 113 if (filter.label 114 && (!filter.family || filter.family == AF_PACKET) 115 && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0) 116 ) { 117 return 0; 118 } 119 120 if (n->nlmsg_type == RTM_DELLINK) 121 fprintf(fp, "Deleted "); 122 123 fprintf(fp, "%d: %s", ifi->ifi_index, 124 tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>"); 125 126 if (tb[IFLA_LINK]) { 127 SPRINT_BUF(b1); 128 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); 129 if (iflink == 0) 130 fprintf(fp, "@NONE: "); 131 else { 132 fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1)); 133 m_flag = ll_index_to_flags(iflink); 134 m_flag = !(m_flag & IFF_UP); 135 } 136 } else { 137 fprintf(fp, ": "); 138 } 139 print_link_flags(fp, ifi->ifi_flags, m_flag); 140 141 if (tb[IFLA_MTU]) 142 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU])); 143 if (tb[IFLA_QDISC]) 144 fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC])); 145#ifdef IFLA_MASTER 146 if (tb[IFLA_MASTER]) { 147 SPRINT_BUF(b1); 148 fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); 149 } 150#endif 151 if (filter.showqueue) 152 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); 153 154 if (!filter.family || filter.family == AF_PACKET) { 155 SPRINT_BUF(b1); 156 fprintf(fp, "%c link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); 157 158 if (tb[IFLA_ADDRESS]) { 159 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), 160 RTA_PAYLOAD(tb[IFLA_ADDRESS]), 161 ifi->ifi_type, 162 b1, sizeof(b1))); 163 } 164 if (tb[IFLA_BROADCAST]) { 165 if (ifi->ifi_flags&IFF_POINTOPOINT) 166 fprintf(fp, " peer "); 167 else 168 fprintf(fp, " brd "); 169 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), 170 RTA_PAYLOAD(tb[IFLA_BROADCAST]), 171 ifi->ifi_type, 172 b1, sizeof(b1))); 173 } 174 } 175 fputc('\n', fp); 176 fflush(fp); 177 return 0; 178} 179 180static int flush_update(void) 181{ 182 if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { 183 bb_perror_msg("failed to send flush request"); 184 return -1; 185 } 186 filter.flushp = 0; 187 return 0; 188} 189 190static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, 191 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) 192{ 193 FILE *fp = (FILE*)arg; 194 struct ifaddrmsg *ifa = NLMSG_DATA(n); 195 int len = n->nlmsg_len; 196 struct rtattr * rta_tb[IFA_MAX+1]; 197 char abuf[256]; 198 SPRINT_BUF(b1); 199 200 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) 201 return 0; 202 len -= NLMSG_LENGTH(sizeof(*ifa)); 203 if (len < 0) { 204 bb_error_msg("wrong nlmsg len %d", len); 205 return -1; 206 } 207 208 if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) 209 return 0; 210 211 memset(rta_tb, 0, sizeof(rta_tb)); 212 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); 213 214 if (!rta_tb[IFA_LOCAL]) 215 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; 216 if (!rta_tb[IFA_ADDRESS]) 217 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; 218 219 if (filter.ifindex && filter.ifindex != ifa->ifa_index) 220 return 0; 221 if ((filter.scope^ifa->ifa_scope)&filter.scopemask) 222 return 0; 223 if ((filter.flags^ifa->ifa_flags)&filter.flagmask) 224 return 0; 225 if (filter.label) { 226 const char *label; 227 if (rta_tb[IFA_LABEL]) 228 label = RTA_DATA(rta_tb[IFA_LABEL]); 229 else 230 label = ll_idx_n2a(ifa->ifa_index, b1); 231 if (fnmatch(filter.label, label, 0) != 0) 232 return 0; 233 } 234 if (filter.pfx.family) { 235 if (rta_tb[IFA_LOCAL]) { 236 inet_prefix dst; 237 memset(&dst, 0, sizeof(dst)); 238 dst.family = ifa->ifa_family; 239 memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); 240 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) 241 return 0; 242 } 243 } 244 245 if (filter.flushb) { 246 struct nlmsghdr *fn; 247 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { 248 if (flush_update()) 249 return -1; 250 } 251 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); 252 memcpy(fn, n, n->nlmsg_len); 253 fn->nlmsg_type = RTM_DELADDR; 254 fn->nlmsg_flags = NLM_F_REQUEST; 255 fn->nlmsg_seq = ++filter.rth->seq; 256 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; 257 filter.flushed++; 258 return 0; 259 } 260 261 if (n->nlmsg_type == RTM_DELADDR) 262 fprintf(fp, "Deleted "); 263 264 if (filter.oneline) 265 fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); 266 if (ifa->ifa_family == AF_INET) 267 fprintf(fp, " inet "); 268 else if (ifa->ifa_family == AF_INET6) 269 fprintf(fp, " inet6 "); 270 else 271 fprintf(fp, " family %d ", ifa->ifa_family); 272 273 if (rta_tb[IFA_LOCAL]) { 274 fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family, 275 RTA_PAYLOAD(rta_tb[IFA_LOCAL]), 276 RTA_DATA(rta_tb[IFA_LOCAL]), 277 abuf, sizeof(abuf))); 278 279 if (rta_tb[IFA_ADDRESS] == NULL || 280 memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) { 281 fprintf(fp, "/%d ", ifa->ifa_prefixlen); 282 } else { 283 fprintf(fp, " peer %s/%d ", 284 rt_addr_n2a(ifa->ifa_family, 285 RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), 286 RTA_DATA(rta_tb[IFA_ADDRESS]), 287 abuf, sizeof(abuf)), 288 ifa->ifa_prefixlen); 289 } 290 } 291 292 if (rta_tb[IFA_BROADCAST]) { 293 fprintf(fp, "brd %s ", 294 rt_addr_n2a(ifa->ifa_family, 295 RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), 296 RTA_DATA(rta_tb[IFA_BROADCAST]), 297 abuf, sizeof(abuf))); 298 } 299 if (rta_tb[IFA_ANYCAST]) { 300 fprintf(fp, "any %s ", 301 rt_addr_n2a(ifa->ifa_family, 302 RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), 303 RTA_DATA(rta_tb[IFA_ANYCAST]), 304 abuf, sizeof(abuf))); 305 } 306 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); 307 if (ifa->ifa_flags&IFA_F_SECONDARY) { 308 ifa->ifa_flags &= ~IFA_F_SECONDARY; 309 fprintf(fp, "secondary "); 310 } 311 if (ifa->ifa_flags&IFA_F_TENTATIVE) { 312 ifa->ifa_flags &= ~IFA_F_TENTATIVE; 313 fprintf(fp, "tentative "); 314 } 315 if (ifa->ifa_flags&IFA_F_DEPRECATED) { 316 ifa->ifa_flags &= ~IFA_F_DEPRECATED; 317 fprintf(fp, "deprecated "); 318 } 319 if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { 320 fprintf(fp, "dynamic "); 321 } else 322 ifa->ifa_flags &= ~IFA_F_PERMANENT; 323 if (ifa->ifa_flags) 324 fprintf(fp, "flags %02x ", ifa->ifa_flags); 325 if (rta_tb[IFA_LABEL]) 326 fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL])); 327 if (rta_tb[IFA_CACHEINFO]) { 328 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); 329 char buf[128]; 330 fputc(_SL_, fp); 331 if (ci->ifa_valid == 0xFFFFFFFFU) 332 sprintf(buf, "valid_lft forever"); 333 else 334 sprintf(buf, "valid_lft %dsec", ci->ifa_valid); 335 if (ci->ifa_prefered == 0xFFFFFFFFU) 336 sprintf(buf+strlen(buf), " preferred_lft forever"); 337 else 338 sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered); 339 fprintf(fp, " %s", buf); 340 } 341 fputc('\n', fp); 342 fflush(fp); 343 return 0; 344} 345 346 347struct nlmsg_list 348{ 349 struct nlmsg_list *next; 350 struct nlmsghdr h; 351}; 352 353static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp) 354{ 355 for (; ainfo; ainfo = ainfo->next) { 356 struct nlmsghdr *n = &ainfo->h; 357 struct ifaddrmsg *ifa = NLMSG_DATA(n); 358 359 if (n->nlmsg_type != RTM_NEWADDR) 360 continue; 361 362 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa))) 363 return -1; 364 365 if (ifa->ifa_index != ifindex || 366 (filter.family && filter.family != ifa->ifa_family)) 367 continue; 368 369 print_addrinfo(NULL, n, fp); 370 } 371 return 0; 372} 373 374 375static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 376{ 377 struct nlmsg_list **linfo = (struct nlmsg_list**)arg; 378 struct nlmsg_list *h; 379 struct nlmsg_list **lp; 380 381 h = malloc(n->nlmsg_len+sizeof(void*)); 382 if (h == NULL) 383 return -1; 384 385 memcpy(&h->h, n, n->nlmsg_len); 386 h->next = NULL; 387 388 for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */; 389 *lp = h; 390 391 ll_remember_index(who, n, NULL); 392 return 0; 393} 394 395static void ipaddr_reset_filter(int _oneline) 396{ 397 memset(&filter, 0, sizeof(filter)); 398 filter.oneline = _oneline; 399} 400 401/* Return value becomes exitcode. It's okay to not return at all */ 402int ipaddr_list_or_flush(int argc, char **argv, int flush) 403{ 404 static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; 405 406 struct nlmsg_list *linfo = NULL; 407 struct nlmsg_list *ainfo = NULL; 408 struct nlmsg_list *l; 409 struct rtnl_handle rth; 410 char *filter_dev = NULL; 411 int no_link = 0; 412 413 ipaddr_reset_filter(oneline); 414 filter.showqueue = 1; 415 416 if (filter.family == AF_UNSPEC) 417 filter.family = preferred_family; 418 419 if (flush) { 420 if (argc <= 0) { 421 bb_error_msg_and_die(bb_msg_requires_arg, "flush"); 422 } 423 if (filter.family == AF_PACKET) { 424 bb_error_msg_and_die("cannot flush link addresses"); 425 } 426 } 427 428 while (argc > 0) { 429 const int option_num = index_in_strings(option, *argv); 430 switch (option_num) { 431 case 0: /* to */ 432 NEXT_ARG(); 433 get_prefix(&filter.pfx, *argv, filter.family); 434 if (filter.family == AF_UNSPEC) { 435 filter.family = filter.pfx.family; 436 } 437 break; 438 case 1: /* scope */ 439 { 440 uint32_t scope = 0; 441 NEXT_ARG(); 442 filter.scopemask = -1; 443 if (rtnl_rtscope_a2n(&scope, *argv)) { 444 if (strcmp(*argv, "all") != 0) { 445 invarg(*argv, "scope"); 446 } 447 scope = RT_SCOPE_NOWHERE; 448 filter.scopemask = 0; 449 } 450 filter.scope = scope; 451 break; 452 } 453 case 2: /* up */ 454 filter.up = 1; 455 break; 456 case 3: /* label */ 457 NEXT_ARG(); 458 filter.label = *argv; 459 break; 460 case 4: /* dev */ 461 NEXT_ARG(); 462 default: 463 if (filter_dev) { 464 duparg2("dev", *argv); 465 } 466 filter_dev = *argv; 467 } 468 argv++; 469 argc--; 470 } 471 472 xrtnl_open(&rth); 473 474 xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK); 475 xrtnl_dump_filter(&rth, store_nlmsg, &linfo); 476 477 if (filter_dev) { 478 filter.ifindex = xll_name_to_index(filter_dev); 479 } 480 481 if (flush) { 482 char flushb[4096-512]; 483 484 filter.flushb = flushb; 485 filter.flushp = 0; 486 filter.flushe = sizeof(flushb); 487 filter.rth = &rth; 488 489 for (;;) { 490 xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); 491 filter.flushed = 0; 492 xrtnl_dump_filter(&rth, print_addrinfo, stdout); 493 if (filter.flushed == 0) { 494 return 0; 495 } 496 if (flush_update() < 0) 497 return 1; 498 } 499 } 500 501 if (filter.family != AF_PACKET) { 502 xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); 503 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); 504 } 505 506 507 if (filter.family && filter.family != AF_PACKET) { 508 struct nlmsg_list **lp; 509 lp=&linfo; 510 511 if (filter.oneline) 512 no_link = 1; 513 514 while ((l=*lp)!=NULL) { 515 int ok = 0; 516 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 517 struct nlmsg_list *a; 518 519 for (a=ainfo; a; a=a->next) { 520 struct nlmsghdr *n = &a->h; 521 struct ifaddrmsg *ifa = NLMSG_DATA(n); 522 523 if (ifa->ifa_index != ifi->ifi_index || 524 (filter.family && filter.family != ifa->ifa_family)) 525 continue; 526 if ((filter.scope^ifa->ifa_scope)&filter.scopemask) 527 continue; 528 if ((filter.flags^ifa->ifa_flags)&filter.flagmask) 529 continue; 530 if (filter.pfx.family || filter.label) { 531 struct rtattr *tb[IFA_MAX+1]; 532 memset(tb, 0, sizeof(tb)); 533 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); 534 if (!tb[IFA_LOCAL]) 535 tb[IFA_LOCAL] = tb[IFA_ADDRESS]; 536 537 if (filter.pfx.family && tb[IFA_LOCAL]) { 538 inet_prefix dst; 539 memset(&dst, 0, sizeof(dst)); 540 dst.family = ifa->ifa_family; 541 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); 542 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) 543 continue; 544 } 545 if (filter.label) { 546 SPRINT_BUF(b1); 547 const char *label; 548 if (tb[IFA_LABEL]) 549 label = RTA_DATA(tb[IFA_LABEL]); 550 else 551 label = ll_idx_n2a(ifa->ifa_index, b1); 552 if (fnmatch(filter.label, label, 0) != 0) 553 continue; 554 } 555 } 556 557 ok = 1; 558 break; 559 } 560 if (!ok) 561 *lp = l->next; 562 else 563 lp = &l->next; 564 } 565 } 566 567 for (l = linfo; l; l = l->next) { 568 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { 569 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 570 if (filter.family != AF_PACKET) 571 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); 572 } 573 fflush(stdout); /* why? */ 574 } 575 576 return 0; 577} 578 579static int default_scope(inet_prefix *lcl) 580{ 581 if (lcl->family == AF_INET) { 582 if (lcl->bytelen >= 1 && *(uint8_t*)&lcl->data == 127) 583 return RT_SCOPE_HOST; 584 } 585 return 0; 586} 587 588/* Return value becomes exitcode. It's okay to not return at all */ 589static int ipaddr_modify(int cmd, int argc, char **argv) 590{ 591 static const char option[] ALIGN1 = 592 "peer\0""remote\0""broadcast\0""brd\0" 593 "anycast\0""scope\0""dev\0""label\0""local\0"; 594 struct rtnl_handle rth; 595 struct { 596 struct nlmsghdr n; 597 struct ifaddrmsg ifa; 598 char buf[256]; 599 } req; 600 char *d = NULL; 601 char *l = NULL; 602 inet_prefix lcl; 603 inet_prefix peer; 604 int local_len = 0; 605 int peer_len = 0; 606 int brd_len = 0; 607 int any_len = 0; 608 bool scoped = 0; 609 610 memset(&req, 0, sizeof(req)); 611 612 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); 613 req.n.nlmsg_flags = NLM_F_REQUEST; 614 req.n.nlmsg_type = cmd; 615 req.ifa.ifa_family = preferred_family; 616 617 while (argc > 0) { 618 const int option_num = index_in_strings(option, *argv); 619 switch (option_num) { 620 case 0: /* peer */ 621 case 1: /* remote */ 622 NEXT_ARG(); 623 624 if (peer_len) { 625 duparg("peer", *argv); 626 } 627 get_prefix(&peer, *argv, req.ifa.ifa_family); 628 peer_len = peer.bytelen; 629 if (req.ifa.ifa_family == AF_UNSPEC) { 630 req.ifa.ifa_family = peer.family; 631 } 632 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); 633 req.ifa.ifa_prefixlen = peer.bitlen; 634 break; 635 case 2: /* broadcast */ 636 case 3: /* brd */ 637 { 638 inet_prefix addr; 639 NEXT_ARG(); 640 if (brd_len) { 641 duparg("broadcast", *argv); 642 } 643 if (LONE_CHAR(*argv, '+')) { 644 brd_len = -1; 645 } 646 else if (LONE_DASH(*argv)) { 647 brd_len = -2; 648 } else { 649 get_addr(&addr, *argv, req.ifa.ifa_family); 650 if (req.ifa.ifa_family == AF_UNSPEC) 651 req.ifa.ifa_family = addr.family; 652 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); 653 brd_len = addr.bytelen; 654 } 655 break; 656 } 657 case 4: /* anycast */ 658 { 659 inet_prefix addr; 660 NEXT_ARG(); 661 if (any_len) { 662 duparg("anycast", *argv); 663 } 664 get_addr(&addr, *argv, req.ifa.ifa_family); 665 if (req.ifa.ifa_family == AF_UNSPEC) { 666 req.ifa.ifa_family = addr.family; 667 } 668 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); 669 any_len = addr.bytelen; 670 break; 671 } 672 case 5: /* scope */ 673 { 674 uint32_t scope = 0; 675 NEXT_ARG(); 676 if (rtnl_rtscope_a2n(&scope, *argv)) { 677 invarg(*argv, "scope"); 678 } 679 req.ifa.ifa_scope = scope; 680 scoped = 1; 681 break; 682 } 683 case 6: /* dev */ 684 NEXT_ARG(); 685 d = *argv; 686 break; 687 case 7: /* label */ 688 NEXT_ARG(); 689 l = *argv; 690 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); 691 break; 692 case 8: /* local */ 693 NEXT_ARG(); 694 default: 695 if (local_len) { 696 duparg2("local", *argv); 697 } 698 get_prefix(&lcl, *argv, req.ifa.ifa_family); 699 if (req.ifa.ifa_family == AF_UNSPEC) { 700 req.ifa.ifa_family = lcl.family; 701 } 702 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); 703 local_len = lcl.bytelen; 704 } 705 argc--; 706 argv++; 707 } 708 709 if (d == NULL) { 710 bb_error_msg(bb_msg_requires_arg,"\"dev\""); 711 return -1; 712 } 713 if (l && strncmp(d, l, strlen(d)) != 0) { 714 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); 715 } 716 717 if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { 718 peer = lcl; 719 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); 720 } 721 if (req.ifa.ifa_prefixlen == 0) 722 req.ifa.ifa_prefixlen = lcl.bitlen; 723 724 if (brd_len < 0 && cmd != RTM_DELADDR) { 725 inet_prefix brd; 726 int i; 727 if (req.ifa.ifa_family != AF_INET) { 728 bb_error_msg_and_die("broadcast can be set only for IPv4 addresses"); 729 } 730 brd = peer; 731 if (brd.bitlen <= 30) { 732 for (i=31; i>=brd.bitlen; i--) { 733 if (brd_len == -1) 734 brd.data[0] |= htonl(1<<(31-i)); 735 else 736 brd.data[0] &= ~htonl(1<<(31-i)); 737 } 738 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); 739 brd_len = brd.bytelen; 740 } 741 } 742 if (!scoped && cmd != RTM_DELADDR) 743 req.ifa.ifa_scope = default_scope(&lcl); 744 745 xrtnl_open(&rth); 746 747 ll_init_map(&rth); 748 749 req.ifa.ifa_index = xll_name_to_index(d); 750 751 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 752 return 2; 753 754 return 0; 755} 756 757/* Return value becomes exitcode. It's okay to not return at all */ 758int do_ipaddr(int argc, char **argv) 759{ 760 static const char commands[] ALIGN1 = 761 "add\0""delete\0""list\0""show\0""lst\0""flush\0"; 762 763 int command_num = 2; /* default command is list */ 764 765 if (*argv) { 766 command_num = index_in_substrings(commands, *argv); 767 } 768 if (command_num < 0 || command_num > 5) 769 bb_error_msg_and_die("unknown command %s", *argv); 770 --argc; 771 ++argv; 772 if (command_num == 0) /* add */ 773 return ipaddr_modify(RTM_NEWADDR, argc, argv); 774 else if (command_num == 1) /* delete */ 775 return ipaddr_modify(RTM_DELADDR, argc, argv); 776 else if (command_num == 5) /* flush */ 777 return ipaddr_list_or_flush(argc, argv, 1); 778 else /* 2 == list, 3 == show, 4 == lst */ 779 return ipaddr_list_or_flush(argc, argv, 0); 780} 781