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