Don't require user to specify -a anymore
authorJoseph C. Lehner <joseph.c.lehner@gmail.com>
Sat, 12 Nov 2016 14:40:26 +0000 (15:40 +0100)
committerJoseph C. Lehner <joseph.c.lehner@gmail.com>
Sat, 12 Nov 2016 14:40:26 +0000 (15:40 +0100)
ethsock.c
main.c
nmrp.c
nmrpd.h

index 24d2b82bef16efe7f9598523149d351d3b4992cd..842d8f79e5cc6642a6aeff3265bf120993268a68 100644 (file)
--- a/ethsock.c
+++ b/ethsock.c
 #define WPCAP
 #include <pcap.h>
 #else
-#include <pcap.h>
+#include <sys/ioctl.h>
 #include <ifaddrs.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <pcap.h>
 #if defined(NMRPFLASH_LINUX)
 #define NMRPFLASH_AF_PACKET AF_PACKET
 #include <linux/if_packet.h>
@@ -35,6 +38,15 @@ struct ethsock
        uint8_t hwaddr[6];
 };
 
+struct ethsock_ip_undo
+{
+#ifndef NRMPFLASH_WINDOWS
+       uint32_t ip[2];
+#else
+       ULONG context;
+#endif
+};
+
 const char *mac_to_str(uint8_t *mac)
 {
        static char buf[18];
@@ -631,3 +643,119 @@ int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
 
        return status <= 0 ? status : 0;
 }
+
+#ifndef NMRPFLASH_WINDOWS
+static int get_ip_cb(struct ethsock_ip_callback_args* args)
+{
+       uint32_t *ip = args->arg;
+       ip[0] = args->ipaddr->s_addr;
+       ip[1] = args->ipmask->s_addr;
+
+       return 0;
+}
+#endif
+
+int ethsock_set_ip(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");
+               return -1;
+       }
+
+#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);
+       if (!fd) {
+               perror("socket");
+               return -1;
+       }
+
+       strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
+
+       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;
+       }
+
+       sin = (struct sockaddr_in*)&ifr.ifr_netmask;
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = ipmask;
+
+       if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
+               perror("ioctl(SIOCSIFNETMASK)");
+               goto out;
+       }
+
+       if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+               perror("ioctl(SIOCGIFFLAGS)");
+               goto out;
+       }
+
+       ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+               perror("ioctl(SIOCSIFFLAGS)");
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       close(fd);
+       return ret;
+#else
+       ULONG instance;
+
+       DWORD ret = AddIPAddress(ipaddr, ipmask, sock->index, &undo->context, &instance);
+       if (ret != NO_ERROR) {
+               win_perror2("AddIPAddress", ret);
+               return -1;
+       }
+
+       return 0;
+#endif
+}
+
+int ethsock_del_ip(struct ethsock *sock, struct ethsock_ip_undo **undo)
+{
+       if (!*undo) {
+               return 0;
+       }
+
+       int ret;
+
+#ifndef NMRPFLASH_WINDOWS
+       if ((*undo)->ip[0] != INADDR_NONE) {
+               ret = ethsock_set_ip(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
+       } else {
+               ret = 0;
+       }
+#else
+       DWORD err = DeleteIPAddress((*undo)->context);
+       if (err != NO_ERROR) {
+               win_perror2("DeleteIPAddress", ret);
+               ret = -1;
+       } else {
+               ret = 0;
+       }
+#endif
+
+       free(*undo);
+       *undo = NULL;
+       return ret;
+}
diff --git a/main.c b/main.c
index 9c1ce8d3822dcea7fb30d64f8291a726ba6a1778..c7e3d79eb4faebc98e2cacb2b3512d2e859682e3 100644 (file)
--- a/main.c
+++ b/main.c
@@ -32,8 +32,9 @@ void usage(FILE *fp)
        fprintf(fp,
                        "Usage: nmrpflash [OPTIONS...]\n"
                        "\n"
-                       "Options (-a, -i and -f and/or -c are mandatory):\n"
+                       "Options (-i, -f and/or -c are mandatory):\n"
                        " -a <ipaddr>     IP address to assign to target device\n"
+                       " -A <ipaddr>     IP address to assign to seleted interface\n"
                        " -c <command>    Command to run before (or instead of) TFTP upload\n"
                        " -f <firmware>   Firmware file\n"
                        " -F <filename>   Remote filename to use during TFTP upload\n"
@@ -119,6 +120,7 @@ int main(int argc, char **argv)
                .tftpcmd = NULL,
                .file_local = NULL,
                .file_remote = NULL,
+               .ipaddr_intf = NULL,
                .ipaddr = NULL,
                .ipmask = "255.255.255.0",
                .intf = NULL,
@@ -160,12 +162,15 @@ int main(int argc, char **argv)
 
        opterr = 0;
 
-       while ((c = getopt(argc, argv, "a:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
+       while ((c = getopt(argc, argv, "a:A:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
                max = 0x7fffffff;
                switch (c) {
                        case 'a':
                                args.ipaddr = optarg;
                                break;
+                       case 'A':
+                               args.ipaddr_intf = optarg;
+                               break;
                        case 'c':
                                args.tftpcmd = optarg;
                                break;
@@ -241,7 +246,12 @@ int main(int argc, char **argv)
                }
        }
 
-       if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf || !args.ipaddr)) {
+       if (args.ipaddr_intf && !args.ipaddr) {
+               fprintf(stderr, "Error: cannot use -A <ipaddr> without using -a <ipaddr>.\n");
+               return 1;
+       }
+
+       if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf /*|| !args.ipaddr*/)) {
                usage(stderr);
                return 1;
        }
diff --git a/nmrp.c b/nmrp.c
index 459a646e0741a0aa86d2f5ff7e46970a0d0e8580..669d3057cd335084e30a7f0d50b46ed4d483be56 100644 (file)
--- a/nmrp.c
+++ b/nmrp.c
@@ -371,6 +371,7 @@ static int is_valid_ip(struct ethsock *sock, struct in_addr *ipaddr,
 }
 
 static struct ethsock *gsock = NULL;
+static struct ethsock_ip_undo *gundo = NULL;
 static int garp = 0;
 static struct in_addr arpip = { 0 };
 static uint8_t arpmac[6] = { 0 };
@@ -382,6 +383,7 @@ static void sigh(int sig)
                if (garp) {
                        ethsock_arp_del(gsock, arpmac, &arpip);
                }
+               ethsock_del_ip(gsock, &gundo);
                ethsock_close(gsock);
                gsock = NULL;
        }
@@ -400,6 +402,7 @@ int nmrp_do(struct nmrpd_args *args)
        time_t beg;
        int i, status, ulreqs, expect, upload_ok, autoip;
        struct ethsock *sock;
+       uint32_t intf_addr;
        void (*sigh_orig)(int);
        struct {
                struct in_addr addr;
@@ -416,16 +419,31 @@ int nmrp_do(struct nmrpd_args *args)
                return 1;
        }
 
-       if ((ipconf.addr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) {
-               autoip = 1;
-               //fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
-               //return 1;
+       if ((ipconf.mask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) {
+               fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
+               return 1;
+       }
+
+       if (!args->ipaddr) {
+               autoip = true;
+               args->ipaddr = "10.11.12.254";
+
+               if (!args->ipaddr_intf) {
+                       args->ipaddr_intf = "10.11.12.253";
+               }
+       } else if (args->ipaddr_intf) {
+               autoip = true;
        } else {
-               autoip = 0;
+               autoip = false;
        }
 
-       if ((ipconf.mask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) {
-               fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
+       if ((ipconf.addr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) {
+               fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
+               return 1;
+       }
+
+       if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) {
+               fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf);
                return 1;
        }
 
@@ -454,12 +472,6 @@ int nmrp_do(struct nmrpd_args *args)
 
        status = 1;
 
-       if (autoip) {
-               if (arp_find_free_ip(args->intf, &ipconf.addr.s_addr) != 0) {
-                       return 1;
-               }
-       }
-
        sock = ethsock_create(args->intf, ETH_P_NMRP);
        if (!sock) {
                return 1;
@@ -469,13 +481,15 @@ int nmrp_do(struct nmrpd_args *args)
        garp = 0;
        sigh_orig = signal(SIGINT, sigh);
 
-       status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
-       if (status <= 0) {
-               if (!status) {
-                       fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n",
-                                       args->ipaddr, args->ipmask, args->intf);
+       if (!autoip) {
+               status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
+               if (status <= 0) {
+                       if (!status) {
+                               fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n",
+                                               args->ipaddr, args->ipmask, args->intf);
+                       }
+                       goto out;
                }
-               goto out;
        }
 
        if (ethsock_set_timeout(sock, args->rx_timeout)) {
@@ -608,6 +622,12 @@ int nmrp_do(struct nmrpd_args *args)
 
                                status = 0;
 
+                               if (autoip) {
+                                       if (ethsock_set_ip(sock, intf_addr, ipconf.mask.s_addr, &gundo) != 0) {
+                                               goto out;
+                                       }
+                               }
+
                                if (args->tftpcmd) {
                                        printf("Executing '%s' ... ", args->tftpcmd);
                                        fflush(stdout);
@@ -616,14 +636,16 @@ int nmrp_do(struct nmrpd_args *args)
                                }
 
                                if (!status && args->file_local) {
-                                       status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
-                                       if (status < 0) {
-                                               goto out;
-                                       } else if (!status) {
-                                               printf("IP address of %s has changed. Please assign a "
-                                                               "static ip to the interface.\n", args->intf);
-                                               tx.msg.code = NMRP_C_CLOSE_REQ;
-                                               break;
+                                       if (!autoip) {
+                                               status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
+                                               if (status < 0) {
+                                                       goto out;
+                                               } else if (!status) {
+                                                       printf("IP address of %s has changed. Please assign a "
+                                                                       "static ip to the interface.\n", args->intf);
+                                                       tx.msg.code = NMRP_C_CLOSE_REQ;
+                                                       break;
+                                               }
                                        }
 
                                        if (verbosity) {
@@ -640,6 +662,10 @@ int nmrp_do(struct nmrpd_args *args)
                                        status = tftp_put(args);
                                }
 
+                               if (ethsock_del_ip(sock, &gundo) != 0) {
+                                       goto out;
+                               }
+
                                if (!status) {
                                        printf("OK\nWaiting for remote to respond.\n");
                                        upload_ok = 1;
diff --git a/nmrpd.h b/nmrpd.h
index 77cf7271660d94bdd832882906f0d4c2e4243e88..458226106819d2c7ed5ae978d814cb404a1dfcf7 100644 (file)
--- a/nmrpd.h
+++ b/nmrpd.h
@@ -75,6 +75,7 @@ struct nmrpd_args {
        const char *tftpcmd;
        const char *file_local;
        const char *file_remote;
+       const char *ipaddr_intf;
        const char *ipaddr;
        const char *ipmask;
        const char *intf;
@@ -103,6 +104,7 @@ void sock_perror(const char *msg);
 extern int verbosity;
 
 struct ethsock;
+struct ethsock_ip_undo;
 
 struct ethsock *ethsock_create(const char *intf, uint16_t protocol);
 int ethsock_close(struct ethsock *sock);
@@ -125,5 +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 arp_find_free_ip(const char *intf, uint32_t *addr);
+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);
 #endif