source: MondoRescue/branches/3.3/mindi-busybox/networking/libiproute/ipaddress.c@ 3782

Last change on this file since 3782 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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