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