A patch from John F. Kelly to add in a utility for configuring
[oweals/busybox.git] / networking / libiproute / ipaddress.c
index 57956852bf6333ade9f3e33a01487a303cba3241..88438179d9c4a0bbb4b17e3ad3f1fa5ec0c8f0bf 100644 (file)
  *     Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
+
 #include <fnmatch.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/sockios.h>
+#include <arpa/inet.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
 
 #include "rt_names.h"
 #include "utils.h"
-#include "ll_map.h"
-#include "ip_common.h"
 
-#include "busybox.h"
+#include "libbb.h"
 
 static struct
 {
@@ -47,6 +41,10 @@ static struct
        int flags, flagmask;
        int up;
        char *label;
+       int flushed;
+       char *flushb;
+       int flushp;
+       int flushe;
        struct rtnl_handle *rth;
 } filter;
 
@@ -196,6 +194,16 @@ static int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
        return 0;
 }
 
+static int flush_update(void)
+{
+       if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
+               perror("Failed to send flush request\n");
+               return -1;
+       }
+       filter.flushp = 0;
+       return 0;
+}
+
 static int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
        FILE *fp = (FILE*)arg;
@@ -213,6 +221,9 @@ static int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
                return -1;
        }
 
+       if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
+               return 0;
+
        memset(rta_tb, 0, sizeof(rta_tb));
        parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
 
@@ -247,6 +258,22 @@ static int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
                }
        }
 
+       if (filter.flushb) {
+               struct nlmsghdr *fn;
+               if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
+                       if (flush_update())
+                               return -1;
+               }
+               fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
+               memcpy(fn, n, n->nlmsg_len);
+               fn->nlmsg_type = RTM_DELADDR;
+               fn->nlmsg_flags = NLM_F_REQUEST;
+               fn->nlmsg_seq = ++filter.rth->seq;
+               filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
+               filter.flushed++;
+               return 0;
+       }
+
        if (n->nlmsg_type == RTM_DELADDR)
                fprintf(fp, "Deleted ");
 
@@ -387,7 +414,7 @@ static void ipaddr_reset_filter(int _oneline)
        filter.oneline = _oneline;
 }
 
-extern int ipaddr_list(int argc, char **argv)
+extern int ipaddr_list_or_flush(int argc, char **argv, int flush)
 {
        const char *option[] = { "to", "scope", "up", "label", "dev", 0 };
        struct nlmsg_list *linfo = NULL;
@@ -403,6 +430,17 @@ extern int ipaddr_list(int argc, char **argv)
        if (filter.family == AF_UNSPEC)
                filter.family = preferred_family;
 
+       if (flush) {
+               if (argc <= 0) {
+                       fprintf(stderr, "Flush requires arguments.\n");
+                       return -1;
+               }
+               if (filter.family == AF_PACKET) {
+                       fprintf(stderr, "Cannot flush link addresses.\n");
+                       return -1;
+               }
+       }
+
        while (argc > 0) {
                const unsigned short option_num = compare_string_array(option, *argv);
                switch (option_num) {
@@ -466,6 +504,37 @@ extern int ipaddr_list(int argc, char **argv)
                }
        }
 
+       if (flush) {
+               int round = 0;
+               char flushb[4096-512];
+
+               filter.flushb = flushb;
+               filter.flushp = 0;
+               filter.flushe = sizeof(flushb);
+               filter.rth = &rth;
+
+               for (;;) {
+                       if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
+                               perror("Cannot send dump request");
+                               exit(1);
+                       }
+                       filter.flushed = 0;
+                       if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
+                               fprintf(stderr, "Flush terminated\n");
+                               exit(1);
+                       }
+                       if (filter.flushed == 0) {
+                               if (round == 0)
+                                       fprintf(stderr, "Nothing to flush.\n");
+                               fflush(stdout);
+                               return 0;
+                       }
+                       round++;
+                       if (flush_update() < 0)
+                               exit(1);
+               }
+       }
+
        if (filter.family != AF_PACKET) {
                if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
                        perror_msg_and_die("Cannot send dump request");
@@ -732,7 +801,7 @@ static int ipaddr_modify(int cmd, int argc, char **argv)
 
 extern int do_ipaddr(int argc, char **argv)
 {
-       const char *commands[] = { "add", "delete", "list", "show", "lst", 0 };
+       const char *commands[] = { "add", "delete", "list", "show", "lst", "flush", 0 };
        unsigned short command_num = 2;
 
        if (*argv) {
@@ -746,7 +815,9 @@ extern int do_ipaddr(int argc, char **argv)
                case 2: /* list */
                case 3: /* show */
                case 4: /* lst */
-                       return ipaddr_list(argc-1, argv+1);
+                       return ipaddr_list_or_flush(argc-1, argv+1, 0);
+               case 5: /* flush */
+                       return ipaddr_list_or_flush(argc-1, argv+1, 1);
        }
        error_msg_and_die("Unknown command %s", *argv);
 }