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