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