Add IP instead of replacing it
authorJoseph C. Lehner <joseph.c.lehner@gmail.com>
Sat, 12 Nov 2016 15:44:15 +0000 (16:44 +0100)
committerJoseph C. Lehner <joseph.c.lehner@gmail.com>
Sat, 12 Nov 2016 15:44:15 +0000 (16:44 +0100)
ethsock.c
nmrp.c
nmrpd.h

index 842d8f79e5cc6642a6aeff3265bf120993268a68..024d77df6147402ba2f6b2c21303df0f3b2de590 100644 (file)
--- a/ethsock.c
+++ b/ethsock.c
@@ -645,17 +645,40 @@ int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
 }
 
 #ifndef NMRPFLASH_WINDOWS
-static int get_ip_cb(struct ethsock_ip_callback_args* args)
+static inline void set_addr(void *p, uint32_t addr)
 {
-       uint32_t *ip = args->arg;
-       ip[0] = args->ipaddr->s_addr;
-       ip[1] = args->ipmask->s_addr;
+       struct sockaddr_in* sin = p;
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = addr;
+}
 
-       return 0;
+static bool set_interface_up(int fd, const char *intf, bool up)
+{
+       struct ifreq ifr;
+       strncpy(ifr.ifr_name, intf, IFNAMSIZ);
+
+       if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+               perror("ioctl(SIOCGIFFLAGS)");
+               return false;
+       }
+
+       if (!up) {
+               ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
+       } else {
+               ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+       }
+
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+               perror("ioctl(SIOCSIFFLAGS)");
+               return false;
+       }
+
+       return true;
 }
+
 #endif
 
-int ethsock_set_ip(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
+int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
 {
        if (undo && !(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
                perror("malloc");
@@ -663,62 +686,69 @@ int ethsock_set_ip(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struc
        }
 
 #ifndef NMRPFLASH_WINDOWS
-       struct ifreq ifr = { 0 };
-       int fd, ret = -1;
-
-       if (undo) {
-               (*undo)->ip[0] = INADDR_NONE;
-               (*undo)->ip[1] = INADDR_NONE;
-
-               if (ethsock_for_each_ip(sock, &get_ip_cb, (*undo)->ip) != 0) {
-                       return 1;
-               }
-       }
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       int ret = -1;
+       int fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (!fd) {
                perror("socket");
                return -1;
        }
 
+#ifdef NMRPFLASH_LINUX
+       struct ifreq ifr;
        strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
+       // FIXME: automatically determine the next free alias
+       strcat(ifr.ifr_name, ":42");
 
-       struct sockaddr_in* sin = (struct sockaddr_in*)&ifr.ifr_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = ipaddr;
-
-       if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
-               perror("ioctl(SIOSIFADDR)");
-               goto out;
-       }
+       // XXX: undo is non-zero only if we're actually adding an ip
+       if (undo) {
+               set_addr(&ifr.ifr_addr, ipaddr);
+               if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
+                       perror("ioctl(SIOSIFADDR)");
+                       goto out;
+               }
 
-       sin = (struct sockaddr_in*)&ifr.ifr_netmask;
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = ipmask;
+               set_addr(&ifr.ifr_netmask, ipmask);
+               if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
+                       perror("ioctl(SIOCSIFNETMASK)");
+                       goto out;
+               }
 
-       if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
-               perror("ioctl(SIOCSIFNETMASK)");
-               goto out;
+               (*undo)->ip[0] = ipaddr;
+               (*undo)->ip[1] = ipmask;
        }
 
-       if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
-               perror("ioctl(SIOCGIFFLAGS)");
+       if (!set_interface_up(fd, ifr.ifr_name, undo ? true : false)) {
                goto out;
        }
+#else // NMRPFLASH_OSX (or any other BSD)
+       struct ifaliasreq ifra;
+       strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
 
-       ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+       set_addr(&ifra.ifra_addr, ipaddr);
+       set_addr(&ifra.ifra_mask, ipmask);
+       //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
+       memset(&ifra.ifra_broadaddr, 0, sizeof(ifra.ifra_broadaddr));
 
-       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
-               perror("ioctl(SIOCSIFFLAGS)");
+       // XXX: undo is non-zero only if we're actually adding an ip
+
+       if (ioctl(fd, undo ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
+               perror("ioctl(SIOCAIFADDR)");
                goto out;
        }
 
+       if (undo) {
+               (*undo)->ip[0] = ipaddr;
+               (*undo)->ip[1] = ipmask;
+               set_interface_up(fd, ifra.ifra_name, true);
+       }
+
+#endif
        ret = 0;
 
 out:
        close(fd);
        return ret;
-#else
+#else // NMRPFLASH_WINDOWS
        ULONG instance;
 
        DWORD ret = AddIPAddress(ipaddr, ipmask, sock->index, &undo->context, &instance);
@@ -731,7 +761,7 @@ out:
 #endif
 }
 
-int ethsock_del_ip(struct ethsock *sock, struct ethsock_ip_undo **undo)
+int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
 {
        if (!*undo) {
                return 0;
@@ -741,7 +771,7 @@ int ethsock_del_ip(struct ethsock *sock, struct ethsock_ip_undo **undo)
 
 #ifndef NMRPFLASH_WINDOWS
        if ((*undo)->ip[0] != INADDR_NONE) {
-               ret = ethsock_set_ip(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
+               ret = ethsock_ip_add(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
        } else {
                ret = 0;
        }
diff --git a/nmrp.c b/nmrp.c
index 669d3057cd335084e30a7f0d50b46ed4d483be56..3cdba476f83f6d92e0adeda0c973865c0b7f2217 100644 (file)
--- a/nmrp.c
+++ b/nmrp.c
@@ -383,7 +383,7 @@ static void sigh(int sig)
                if (garp) {
                        ethsock_arp_del(gsock, arpmac, &arpip);
                }
-               ethsock_del_ip(gsock, &gundo);
+               ethsock_ip_del(gsock, &gundo);
                ethsock_close(gsock);
                gsock = NULL;
        }
@@ -623,7 +623,7 @@ int nmrp_do(struct nmrpd_args *args)
                                status = 0;
 
                                if (autoip) {
-                                       if (ethsock_set_ip(sock, intf_addr, ipconf.mask.s_addr, &gundo) != 0) {
+                                       if (ethsock_ip_add(sock, intf_addr, ipconf.mask.s_addr, &gundo) != 0) {
                                                goto out;
                                        }
                                }
@@ -662,7 +662,7 @@ int nmrp_do(struct nmrpd_args *args)
                                        status = tftp_put(args);
                                }
 
-                               if (ethsock_del_ip(sock, &gundo) != 0) {
+                               if (ethsock_ip_del(sock, &gundo) != 0) {
                                        goto out;
                                }
 
diff --git a/nmrpd.h b/nmrpd.h
index 458226106819d2c7ed5ae978d814cb404a1dfcf7..d54e4eb64535386aeef2cce5918515a21ed922b0 100644 (file)
--- a/nmrpd.h
+++ b/nmrpd.h
@@ -127,6 +127,6 @@ typedef int (*ethsock_ip_callback_t)(struct ethsock_ip_callback_args *args);
 int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
                void *arg);
 
-int ethsock_set_ip(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo);
-int ethsock_del_ip(struct ethsock *sock, struct ethsock_ip_undo **undo);
+int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo);
+int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo);
 #endif