source: branches/stable/mindi-busybox/networking/libiproute/ipaddress.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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