diff --git a/ethsock.c b/ethsock.c index 24d2b82..842d8f7 100644 --- a/ethsock.c +++ b/ethsock.c @@ -10,8 +10,11 @@ #define WPCAP #include #else -#include +#include #include +#include +#include +#include #if defined(NMRPFLASH_LINUX) #define NMRPFLASH_AF_PACKET AF_PACKET #include @@ -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 9c1ce8d..c7e3d79 100644 --- 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 IP address to assign to target device\n" + " -A IP address to assign to seleted interface\n" " -c Command to run before (or instead of) TFTP upload\n" " -f Firmware file\n" " -F 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 without using -a .\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 459a646..669d305 100644 --- 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,19 +419,34 @@ 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; - } else { - autoip = 0; - } - 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 = false; + } + + 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; + } + if (args->file_local && strcmp(args->file_local, "-") && access(args->file_local, R_OK) == -1) { fprintf(stderr, "Error accessing file '%s'.\n", args->file_local); 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 77cf727..4582261 100644 --- 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