diff --git a/Makefile b/Makefile index 01cc9ad..d1f2e95 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ install: nmrpflash install -m 755 nmrpflash $(PREFIX)/bin release/osx: - CFLAGS="-arch i686 -arch x86_64 -mmacosx-version-min=10.6" make release + CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.6" make release zip nmrpflash-osx.zip nmrpflash release/linux: release diff --git a/README.md b/README.md index 3f88532..c94fbba 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,26 @@ Prebuilt binaries for Linux, OS X and Windows are available [here](https://github.com/jclehner/nmrpflash/releases) ([WinPcap](https://www.winpcap.org/install/default.htm) is required on Windows). -```` +``` Usage: nmrpflash [OPTIONS...] -Options (-a, -i and -f are mandatory): +Options (-a, -i and -f and/or -c are mandatory): -a IP address to assign to target device + -c Command to run before (or instead of) TFTP upload -f Firmware file + -F Remote filename to use during TFTP upload -i Network interface directly connected to device -m MAC address of target device (xx:xx:xx:xx:xx:xx) -M Subnet mask to assign to target device -t Timeout (in milliseconds) for regular messages - -T Time to wait after successfull TFTP upload + -T Time (seconds) to wait after successfull TFTP upload -p Port to use for TFTP upload - -U Test TFTP upload + -R Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP) -v Be verbose -V Print version and exit -L List network interfaces -h Show this screen -```` +``` ### Using nmrpflash @@ -40,10 +42,10 @@ First, we have to assign a static IP address to our network interface. In this example, we'll use `192.168.1.2`. All available network interfaces can be listed using -```` +``` $ nmrpflash -L eth0 192.168.1.2 f2:11:a1:02:03:b1 -```` +``` Now we can `nmrpflash`. The argument for the `-a` option needs to be a *free* IP address from the same subnet as the one used by your @@ -52,15 +54,17 @@ be downloaded directly from netgear. For details on how to do this, see [here](#obtaining-firmware-images). Power on your device immediately after starting `nmrpflash`. -```` +``` $ nmrpflash -i eth0 -a 192.168.1.254 -f EX2700-V1.0.1.8.img Advertising NMRP server on eth0 ... / Received configuration request from a4:2b:8c:00:00:01. Sending configuration: ip 192.168.1.254, mask 255.255.255.0. +Received upload request: filename 'firmware'. Uploading EX2700-V1.0.1.8.img ... OK Waiting for remote to respond. Remote finished. Closing connection. -```` +Reboot your device now. +``` ### Common issues ###### "No suitable network interfaces found." @@ -74,7 +78,26 @@ The router did not respond. Try rebooting the device and run `nmrpflash` again. You could also try running `nmrpflash` with `-m` and specify your router's MAC address. It's also possible that your device does not support the NMRP protocol. -###### "Timeout while waiting for 0x04." +###### "Timeout while waiting for initial reply." + +The device did not respond to `nmrpflash`'s TFTP upload request. This could indicate a bug +in the TFTP code; try using an external tftp client (busybox in this example), by specifying +the `-c` flag instead of the `-f` flag: + +`$ nmrpflash -i eth0 -a 192.168.1.254 -c "busybox tftp -p -l EX2700-V1.0.1.8.img 192.168.1.254"` + +If the upload still fails, and you're on Windows, try executing the following command before +running `nmrpflash`: + +`C:\> netsh interface ip add neighbors ` + +where `` is the pretty interface name (e.g. "Local Area Connection"; as displayed by +`nmrpflash -L`), `` is the same IP address you'd use for `nmrpflash`'s `-a` flag, and `` +is the target device's mac address. + +Cheers to [@ntadmin](https://github.com/ntadmin) for this info! + +###### "Timeout while waiting for CLOSE_REQ." After a successful file upload, `nmrpflash` waits for up to 120 seconds for an answer from your device. You can increase this by specifying a longer timeout @@ -83,12 +106,35 @@ using `-T` switch (argument is in seconds). It's entirely possible that the image was flashed successfully, but the operation took longer than 120 seconds. +###### "Address X/Y cannot be used on interface Z." + +`nmrpflash` refuses to use an IP address / subnet mask combination that would +make the remote device unreachable from the device running `nmrpflash`. For +example, if the IP address of your computer is 192.168.0.1/255.255.255.0, assigning +192.168.2.1/255.255.255.0 to the router makes no sense, because the TFTP upload will +fail. + +###### "IP address of X has changed. Please assign a static IP to the interface." + +This can happen if the network interface in question automatically detects that +the network cable has been connected, and your computer tries to reconfigure that +interface (NetworkManager on Linux does this for example) - this can usually be +disabled. + +An alternative would be to add `-c 'ifconfig '` to the command line, +for example: + +`nmrpflash -i eth0 -a 192.168.1.1 -f firmware.bin -c 'ifconfig eth0 192.168.1.2'` + +This will execute the command specified by `-c` prior to starting the TFTP upload (in +this case setting the IP address to 192.168.1.2). + ### Building and installing ###### Linux, Mac OS X, BSDs -```` +``` $ make && sudo make install -```` +``` ###### Windows diff --git a/ethsock.c b/ethsock.c index 4bef279..24d2b82 100644 --- a/ethsock.c +++ b/ethsock.c @@ -29,6 +29,7 @@ struct ethsock int fd; #else HANDLE handle; + DWORD index; #endif unsigned timeout; uint8_t hwaddr[6]; @@ -75,7 +76,7 @@ static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr) return true; } -static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr) +static bool get_intf_info(const char *intf, uint8_t *hwaddr, void *dummy) { struct ifaddrs *ifas, *ifa; bool found; @@ -119,7 +120,7 @@ void win_perror2(const char *msg, DWORD err) } } -static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr) +static bool get_intf_info(const char *intf, uint8_t *hwaddr, DWORD *index) { PIP_ADAPTER_INFO adapters, adapter; DWORD ret; @@ -147,10 +148,10 @@ static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr) * AdapterName from GetAdaptersInfo is just "{GUID}".*/ if (strstr(intf, adapter->AdapterName)) { if (adapter->AddressLength == 6) { - for (i = 0; i != 6; ++i) { - hwaddr[i] = adapter->Address[i]; + memcpy(hwaddr, adapter->Address, 6); + if (index) { + *index = adapter->Index; } - found = true; break; } @@ -289,8 +290,13 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol) goto cleanup_pcap; } - if (!get_hwaddr_from_intf(intf, sock->hwaddr)) { - fprintf(stderr, "Failed to get MAC address of interface.\n"); +#ifndef NMRPFLASH_WINDOWS + err = !get_intf_info(intf, sock->hwaddr, NULL); +#else + err = !get_intf_info(intf, sock->hwaddr, &sock->index); +#endif + if (err) { + fprintf(stderr, "Failed to get interface info.\n"); goto cleanup_malloc; } @@ -436,6 +442,54 @@ inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec) return 0; } +#ifndef NMRPFLASH_WINDOWS +int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + return 0; +} + +int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + return 0; +} +#else +static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr, int add) +{ + DWORD ret; + MIB_IPNETROW arp = { + .dwIndex = sock->index, + .dwPhysAddrLen = 6, + .dwAddr = ipaddr->s_addr, + .dwType = MIB_IPNET_TYPE_STATIC + }; + + memcpy(arp.bPhysAddr, hwaddr, 6); + + if (add) { + ret = CreateIpNetEntry(&arp); + if (ret != NO_ERROR) { + win_perror2("CreateIpNetEntry", ret); + return -1; + } + } else { + DeleteIpNetEntry(&arp); + } + + return 0; +} + +int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + ethsock_arp_del(sock, hwaddr, ipaddr); + return ethsock_arp(sock, hwaddr, ipaddr, 1); +} + +int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + return ethsock_arp(sock, hwaddr, ipaddr, 0); +} +#endif + static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr) { #ifndef NMRPFLASH_WINDOWS @@ -458,7 +512,7 @@ static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr) } #endif - return get_hwaddr_from_intf(dev->name, hwaddr); + return get_intf_info(dev->name, hwaddr, NULL); } int ethsock_list_all(void) diff --git a/main.c b/main.c index 9760c61..69671a8 100644 --- a/main.c +++ b/main.c @@ -23,6 +23,8 @@ #include #include "nmrpd.h" +#define NMRPFLASH_SET_REGION + int verbosity = 0; void usage(FILE *fp) @@ -42,7 +44,7 @@ void usage(FILE *fp) " -T Time (seconds) to wait after successfull TFTP upload\n" " -p Port to use for TFTP upload\n" #ifdef NMRPFLASH_SET_REGION - " -R Set device region\n" + " -R Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)\n" #endif #ifdef NMRPFLASH_TFTP_TEST " -U Test TFTP upload\n" @@ -83,7 +85,7 @@ int main(int argc, char **argv) .mac = "ff:ff:ff:ff:ff:ff", .op = NMRP_UPLOAD_FW, .port = 69, - .force_root = 1 + .region = NULL, }; #ifdef NMRPFLASH_WINDOWS WSADATA wsa; @@ -121,16 +123,16 @@ int main(int argc, char **argv) case 'M': args.ipmask = optarg; break; - case 'p': #ifdef NMRPFLASH_SET_REGION case 'R': + args.region = optarg; + break; #endif + case 'p': case 'T': case 't': if (c == 'p') { max = 0xffff; - } else if (c == 'R') { - max = 0x0009; } val = atoi(optarg); @@ -145,8 +147,6 @@ int main(int argc, char **argv) args.rx_timeout = val; } else if (c == 'T') { args.ul_timeout = val * 1000; - } else if (c == 'R') { - args.region = val; } break; diff --git a/nmrp.c b/nmrp.c index c696fcc..39d37f9 100644 --- a/nmrp.c +++ b/nmrp.c @@ -27,11 +27,13 @@ #include "nmrpd.h" #define NMRP_HDR_LEN 6 -#define NMRP_OPT_LEN 4 +#define NMRP_OPT_HDR_LEN 4 #define NMRP_MIN_PKT_LEN (sizeof(struct eth_hdr) + NMRP_HDR_LEN) #define NMRP_MAX_OPT_SIZE 12 -#define NMRP_MAX_OPT_NUM 2 +#define NMRP_MAX_OPT_NUM 3 + +#define NMRP_OPT_NEXT(x) ((struct nmrp_opt*)(((char*)x) + x->len)) #define ETH_P_NMRP 0x0912 #define IP_LEN 4 @@ -80,7 +82,9 @@ struct nmrp_msg { uint8_t code; uint8_t id; uint16_t len; - struct nmrp_opt opts[2]; + /* only opts[0] is valid! think of this as a char* */ + struct nmrp_opt opts[NMRP_MAX_OPT_NUM]; + /* this is NOT part of the transmitted packet */ uint32_t num_opts; } PACKED; @@ -116,13 +120,20 @@ static const char *msg_code_str(uint16_t code) #undef CASE_CODE } -static void msg_update_len(struct nmrp_msg *msg) +static uint16_t to_region_code(const char *region) { - uint32_t i = 0; - msg->len = NMRP_HDR_LEN; - for (; i != msg->num_opts; ++i) { - msg->len += msg->opts[i].len; - } +#define REGION_CODE(r, c) if (!strcasecmp(region, r)) return c + REGION_CODE("NA", 0x0001); + REGION_CODE("WW", 0x0002); + REGION_CODE("GR", 0x0003); + REGION_CODE("PR", 0x0004); + REGION_CODE("RU", 0x0005); + REGION_CODE("BZ", 0x0006); + REGION_CODE("IN", 0x0007); + REGION_CODE("KO", 0x0008); + REGION_CODE("JP", 0x0009); +#undef REGION_CODE + return 0; } static void msg_dump(struct nmrp_msg *msg, int dump_opts) @@ -142,16 +153,18 @@ static void msg_dump(struct nmrp_msg *msg, int dump_opts) while (remain_len > 0) { len = opt->len; fprintf(stderr, " opt type=%u, len=%u", opt->type, len); - for (i = 0; i != len - NMRP_OPT_LEN; ++i) { - if (!(i % 16)) { - fprintf(stderr, "\n "); - } + if (len) { + for (i = 0; i != len - NMRP_OPT_HDR_LEN; ++i) { + if (!(i % 16)) { + fprintf(stderr, "\n "); + } - fprintf(stderr, "%02x ", ((char*)&opt->val)[i] & 0xff); + fprintf(stderr, "%02x ", ((char*)&opt->val)[i] & 0xff); + } + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); remain_len -= len; - opt = (struct nmrp_opt*)(((char*)opt) + len); + opt = NMRP_OPT_NEXT(opt); } } } @@ -159,13 +172,16 @@ static void msg_dump(struct nmrp_msg *msg, int dump_opts) static void msg_hton(struct nmrp_msg *msg) { uint32_t i = 0; + struct nmrp_opt *opt = msg->opts, *next; msg->reserved = htons(msg->reserved); msg->len = htons(msg->len); for (; i != msg->num_opts; ++i) { - msg->opts[i].len = htons(msg->opts[i].len); - msg->opts[i].type = htons(msg->opts[i].type); + next = NMRP_OPT_NEXT(opt); + opt->len = htons(opt->len); + opt->type = htons(opt->type); + opt = next; } } @@ -186,7 +202,7 @@ static int msg_ntoh(struct nmrp_msg *msg) // size is 12 if (remaining < NMRP_MAX_OPT_NUM * NMRP_MAX_OPT_SIZE) { while (remaining > 0) { - if (remaining < NMRP_OPT_LEN) { + if (remaining < NMRP_OPT_HDR_LEN) { break; } @@ -198,7 +214,7 @@ static int msg_ntoh(struct nmrp_msg *msg) } remaining -= opt->len; - ++opt; + opt = NMRP_OPT_NEXT(opt); } if (!remaining) { @@ -211,7 +227,7 @@ static int msg_ntoh(struct nmrp_msg *msg) return 1; } -static void *msg_opt_data(struct nmrp_msg *msg, int type, uint16_t *len) +static void *msg_opt_data(struct nmrp_msg *msg, uint16_t type, uint16_t *len) { static char buf[128]; struct nmrp_opt *opt = msg->opts; @@ -221,21 +237,54 @@ static void *msg_opt_data(struct nmrp_msg *msg, int type, uint16_t *len) while (remaining > 0) { if (opt->type == type) { - if (opt->len == NMRP_OPT_LEN) { + if (opt->len == NMRP_OPT_HDR_LEN) { return NULL; } - *len = opt->len - NMRP_OPT_LEN; + *len = opt->len - NMRP_OPT_HDR_LEN; memcpy(buf, &opt->val, MIN(*len, sizeof(buf)-1)); return buf; } remaining -= opt->len; - opt = (struct nmrp_opt*)((char*)opt) + opt->len; + opt = NMRP_OPT_NEXT(opt); } return NULL; } +static void msg_opt_add(struct nmrp_msg *msg, uint16_t type, void *data, + uint16_t len) +{ + uint32_t i = 0; + struct nmrp_opt *opt = msg->opts; + + if (len + NMRP_OPT_HDR_LEN > NMRP_MAX_OPT_SIZE + || msg->num_opts == NMRP_MAX_OPT_NUM) { + fprintf(stderr, "Invalid option - this is a bug.\n"); + } + + for (; i <= msg->num_opts; ++i) { + opt = NMRP_OPT_NEXT(opt); + } + + opt->len = NMRP_OPT_HDR_LEN + len; + opt->type = type; + + if (len) { + memcpy(&opt->val, data, len); + } + + msg->len += opt->len; + ++msg->num_opts; +} + +static inline void msg_init(struct nmrp_msg *msg, uint16_t code) +{ + memset(msg, 0, sizeof(*msg)); + msg->len = NMRP_HDR_LEN; + msg->code = code; +} + static int pkt_send(struct ethsock *sock, struct nmrp_pkt *pkt) { size_t len = ntohs(pkt->msg.len) + sizeof(pkt->eh); @@ -328,12 +377,19 @@ static int is_valid_ip(struct ethsock *sock, struct in_addr *ipaddr, } static struct ethsock *gsock = NULL; +static int garp = 0; +static struct in_addr arpip = { 0 }; +static uint8_t arpmac[6] = { 0 }; static void sigh(int sig) { printf("\n"); if (gsock) { + if (garp) { + ethsock_arp_del(gsock, arpmac, &arpip); + } ethsock_close(gsock); + gsock = NULL; } exit(1); @@ -345,13 +401,16 @@ int nmrp_do(struct nmrpd_args *args) { struct nmrp_pkt tx, rx; uint8_t *src, dest[6]; - uint16_t len; + uint16_t len, region; char *filename; - struct in_addr ipaddr, ipmask; time_t beg; - int i, status, ulreqs, expect; + int i, status, ulreqs, expect, upload_ok; struct ethsock *sock; void (*sigh_orig)(int); + struct { + struct in_addr addr; + struct in_addr mask; + } PACKED ipconf; if (args->op != NMRP_UPLOAD_FW) { fprintf(stderr, "Operation not implemented.\n"); @@ -363,17 +422,17 @@ int nmrp_do(struct nmrpd_args *args) return 1; } - if ((ipaddr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) { + if ((ipconf.addr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) { fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr); return 1; } - if ((ipmask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) { + if ((ipconf.mask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) { fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask); return 1; } - if (strcmp(args->file_local, "-") && access(args->file_local, R_OK) == -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; } @@ -386,6 +445,16 @@ int nmrp_do(struct nmrpd_args *args) } } + if (args->region) { + region = htons(to_region_code(args->region)); + if (!region) { + fprintf(stderr, "Invalid region code '%s'.\n", args->region); + return 1; + } + } else { + region = 0; + } + status = 1; sock = ethsock_create(args->intf, ETH_P_NMRP); @@ -393,8 +462,6 @@ int nmrp_do(struct nmrpd_args *args) return 1; } - sigh_orig = signal(SIGINT, sigh); - status = is_valid_ip(sock, &ipaddr, &ipmask); if (status <= 0) { if (!status) { @@ -405,6 +472,8 @@ int nmrp_do(struct nmrpd_args *args) } gsock = sock; + garp = 0; + sigh_orig = signal(SIGINT, sigh); if (ethsock_set_timeout(sock, args->rx_timeout)) { goto out; @@ -419,21 +488,12 @@ int nmrp_do(struct nmrpd_args *args) memcpy(tx.eh.ether_dhost, dest, 6); tx.eh.ether_type = htons(ETH_P_NMRP); - tx.msg.reserved = 0; - tx.msg.code = NMRP_C_ADVERTISE; - tx.msg.id = 0; - tx.msg.num_opts = 1; - tx.msg.opts[0].type = NMRP_O_MAGIC_NO; - tx.msg.opts[0].len = NMRP_OPT_LEN + 4; - tx.msg.opts[0].val.magic[0] = 'N'; - tx.msg.opts[0].val.magic[1] = 'T'; - tx.msg.opts[0].val.magic[2] = 'G'; - tx.msg.opts[0].val.magic[3] = 'R'; - - msg_update_len(&tx.msg); + msg_init(&tx.msg, NMRP_C_ADVERTISE); + msg_opt_add(&tx.msg, NMRP_O_MAGIC_NO, "NTGR", 4); msg_hton(&tx.msg); i = 0; + upload_ok = 0; beg = time(NULL); while (1) { @@ -472,11 +532,7 @@ int nmrp_do(struct nmrpd_args *args) msg_code_str(rx.msg.code), msg_code_str(expect)); } - tx.msg.code = NMRP_C_NONE; - tx.msg.reserved = 0; - tx.msg.id = 0; - tx.msg.num_opts = 0; - tx.msg.len = 0; + msg_init(&tx.msg, NMRP_C_NONE); status = 1; @@ -488,23 +544,14 @@ int nmrp_do(struct nmrpd_args *args) goto out; case NMRP_C_CONF_REQ: tx.msg.code = NMRP_C_CONF_ACK; - tx.msg.num_opts = 2; - tx.msg.opts[0].type = NMRP_O_DEV_IP; - tx.msg.opts[0].len = NMRP_OPT_LEN + 2 * 4; - - memcpy(tx.msg.opts[0].val.ip.addr, &ipaddr, 4); - memcpy(tx.msg.opts[0].val.ip.mask, &ipmask, 4); - - tx.msg.opts[1].type = NMRP_O_FW_UP; - tx.msg.opts[1].len = NMRP_OPT_LEN; + msg_opt_add(&tx.msg, NMRP_O_DEV_IP, &ipconf, 8); + msg_opt_add(&tx.msg, NMRP_O_FW_UP, NULL, 0); #ifdef NMRPFLASH_SET_REGION - tx.msg.num_opts = 3; - - tx.msg.opts[2].type = NMRP_O_DEV_REGION; - tx.msg.opts[2].len = NMRP_OPT_LEN + 2; - tx.msg.opts[2].val.region = args->region; + if (region) { + msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, ®ion, 2); + } #endif expect = NMRP_C_TFTP_UL_REQ; @@ -517,12 +564,30 @@ int nmrp_do(struct nmrpd_args *args) printf("Sending configuration: ip %s, mask %s.\n", args->ipaddr, args->ipmask); + memcpy(arpmac, rx.eh.ether_shost, 6); + memcpy(&arpip, &ipconf.addr, sizeof(ipconf.addr)); + + if (ethsock_arp_add(sock, arpmac, &arpip) != 0) { + goto out; + } + + garp = 1; + break; case NMRP_C_TFTP_UL_REQ: - if (++ulreqs > 5) { - fprintf(stderr, "Device re-requested file upload %d " - "times; aborting.\n", ulreqs); - tx.msg.code = NMRP_C_CLOSE_REQ; + if (!upload_ok) { + if (++ulreqs > 5) { + printf("Bailing out after %d upload requests.\n", + ulreqs); + tx.msg.code = NMRP_C_CLOSE_REQ; + break; + } + } else { + if (verbosity) { + printf("Ignoring extra upload request.\n"); + } + ethsock_set_timeout(sock, args->ul_timeout); + tx.msg.code = NMRP_C_KEEP_ALIVE_REQ; break; } @@ -535,12 +600,8 @@ int nmrp_do(struct nmrpd_args *args) printf("Received upload request: filename '%.*s'.\n", len, filename); } else if (!args->file_remote) { - if (tftp_is_valid_filename(args->file_local)) { - args->file_remote = args->file_local; - } else { - args->file_remote = "firmware"; - } - printf("Received upload request with empty filename."); + args->file_remote = args->file_local; + printf("Received upload request with empty filename.\n"); } status = 0; @@ -557,7 +618,7 @@ int nmrp_do(struct nmrpd_args *args) } if (!status && args->file_local) { - status = is_valid_ip(sock, &ipaddr, &ipmask); + status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask); if (status < 0) { goto out; } else if (!status) { @@ -575,7 +636,7 @@ int nmrp_do(struct nmrpd_args *args) if (!strcmp(args->file_local, "-")) { printf("Uploading from stdin ... "); } else { - printf("Uploading %s ... ", args->file_local); + printf("Uploading %s ... ", leafname(args->file_local)); } fflush(stdout); status = tftp_put(args); @@ -583,7 +644,9 @@ int nmrp_do(struct nmrpd_args *args) if (!status) { printf("OK\nWaiting for remote to respond.\n"); + upload_ok = 1; ethsock_set_timeout(sock, args->ul_timeout); + tx.msg.code = NMRP_C_KEEP_ALIVE_REQ; expect = NMRP_C_NONE; } else if (status == -2) { expect = NMRP_C_TFTP_UL_REQ; @@ -610,13 +673,16 @@ int nmrp_do(struct nmrpd_args *args) } if (tx.msg.code != NMRP_C_NONE) { - msg_update_len(&tx.msg); msg_hton(&tx.msg); if (pkt_send(sock, &tx) < 0) { perror("sendto"); goto out; } + + if (tx.msg.code == NMRP_C_CLOSE_REQ) { + goto out; + } } if (rx.msg.code == NMRP_C_CLOSE_REQ) { @@ -648,6 +714,7 @@ int nmrp_do(struct nmrpd_args *args) out: signal(SIGINT, sigh_orig); gsock = NULL; + ethsock_arp_del(sock, arpmac, &arpip); ethsock_close(sock); return status; } diff --git a/nmrpd.h b/nmrpd.h index cf5138d..ef25a69 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -71,10 +71,10 @@ struct nmrpd_args { const char *mac; enum nmrp_op op; uint16_t port; - uint16_t region; - int force_root; + const char *region; }; +const char *leafname(const char *path); int tftp_put(struct nmrpd_args *args); bool tftp_is_valid_filename(const char *filename); @@ -100,6 +100,8 @@ int ethsock_send(struct ethsock *sock, void *buf, size_t len); ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len); int ethsock_set_timeout(struct ethsock *sock, unsigned msec); uint8_t *ethsock_get_hwaddr(struct ethsock *sock); +int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr); +int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr); int ethsock_list_all(void); struct ethsock_ip_callback_args diff --git a/nmrpflash.dev b/nmrpflash.dev index 931bc66..7a2e4d0 100644 --- a/nmrpflash.dev +++ b/nmrpflash.dev @@ -9,7 +9,7 @@ Libs=Wpdpack\Lib PrivateResource= ResourceIncludes= MakeIncludes= -Compiler=-DNMRPFLASH_VERSION=\"0.9.2\"_@@_ +Compiler=-DNMRPFLASH_VERSION=\"0.9.3\"_@@_ CppCompiler= Linker=-liphlpapi_@@_-lws2_32_@@_-ladvapi32_@@_-lwpcap_@@_-lpacket_@@__@@_ IsCpp=0 diff --git a/tftp.c b/tftp.c index a151792..da76dc9 100644 --- a/tftp.c +++ b/tftp.c @@ -40,24 +40,6 @@ enum tftp_opcode { ERR = 5 }; -static const char *leafname(const char *path) -{ - const char *slash, *bslash; - - slash = strrchr(path, '/'); - bslash = strrchr(path, '\\'); - - if (slash && bslash) { - path = 1 + (slash > bslash ? slash : bslash); - } else if (slash) { - path = 1 + slash; - } else if (bslash) { - path = 1 + bslash; - } - - return path; -} - static bool is_netascii(const char *str) { uint8_t *p = (uint8_t*)str; @@ -211,16 +193,29 @@ static ssize_t tftp_sendto(int sock, char *pkt, size_t len, return sent; } +const char *leafname(const char *path) +{ + const char *slash, *bslash; + + slash = strrchr(path, '/'); + bslash = strrchr(path, '\\'); + + if (slash && bslash) { + path = 1 + (slash > bslash ? slash : bslash); + } else if (slash) { + path = 1 + slash; + } else if (bslash) { + path = 1 + bslash; + } + + return path; +} + #ifdef NMRPFLASH_WINDOWS void sock_perror(const char *msg) { win_perror2(msg, WSAGetLastError()); } -#else -inline void sock_perror(const char *msg) -{ - perror(msg); -} #endif inline bool tftp_is_valid_filename(const char *filename) @@ -322,7 +317,7 @@ int tftp_put(struct nmrpd_args *args) if (ret < 0) { goto cleanup; } else if (!ret) { - if (++timeout < 5) { + if (++timeout < 5 || (!block && timeout < 10)) { continue; } else if (block) { fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);