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