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