From d947fbc3336afdbf507be5e70c60f7915b418c57 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 16 Feb 2016 17:41:55 +0100 Subject: [PATCH 01/30] Filename is already corrected by tftp code --- nmrp.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nmrp.c b/nmrp.c index a374c6c..f06d959 100644 --- a/nmrp.c +++ b/nmrp.c @@ -534,11 +534,7 @@ 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"; - } + args->file_remote = args->file_local; printf("Received upload request with empty filename."); } From 61980e136ed59ad036d079bc166026f2329cfd73 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 12:14:16 +0100 Subject: [PATCH 02/30] Ignore additional upload requests --- nmrp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nmrp.c b/nmrp.c index f06d959..81d9a9c 100644 --- a/nmrp.c +++ b/nmrp.c @@ -518,10 +518,11 @@ int nmrp_do(struct nmrpd_args *args) 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 (++ulreqs > 1) { + if (verbosity) { + printf("Ignoring upload request %d.\n", ulreqs); + } + ethsock_set_timeout(sock, args->ul_timeout); break; } From dc961b598ad0173776eb7e689c24a6078ca5cdbf Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 12:19:31 +0100 Subject: [PATCH 03/30] Longer timeout for initial WRQ --- tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tftp.c b/tftp.c index a151792..19866b4 100644 --- a/tftp.c +++ b/tftp.c @@ -322,7 +322,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); From 758d301c31db5dff656a41e4f14369500d0c582e Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 12:19:43 +0100 Subject: [PATCH 04/30] Shorten pathname in status message --- nmrp.c | 2 +- nmrpd.h | 1 + tftp.c | 36 ++++++++++++++++++------------------ 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/nmrp.c b/nmrp.c index 81d9a9c..521c39e 100644 --- a/nmrp.c +++ b/nmrp.c @@ -571,7 +571,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); diff --git a/nmrpd.h b/nmrpd.h index cf5138d..28d3f0f 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -75,6 +75,7 @@ struct nmrpd_args { int force_root; }; +const char *leafname(const char *path); int tftp_put(struct nmrpd_args *args); bool tftp_is_valid_filename(const char *filename); diff --git a/tftp.c b/tftp.c index 19866b4..282f6d2 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,6 +193,24 @@ 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) { From 68501ff596d30c23f260022632ef64969604e55d Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 12:31:31 +0100 Subject: [PATCH 05/30] Better handling of extra upload requests --- nmrp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/nmrp.c b/nmrp.c index 521c39e..f95fd57 100644 --- a/nmrp.c +++ b/nmrp.c @@ -349,7 +349,7 @@ int nmrp_do(struct nmrpd_args *args) char *filename; struct in_addr ipaddr, ipmask; time_t beg; - int i, status, ulreqs, expect; + int i, status, ulreqs, expect, unexpected; struct ethsock *sock; void (*sigh_orig)(int); @@ -469,6 +469,9 @@ int nmrp_do(struct nmrpd_args *args) if (expect != NMRP_C_NONE && rx.msg.code != expect) { fprintf(stderr, "Received %s while waiting for %s!\n", msg_code_str(rx.msg.code), msg_code_str(expect)); + unexpected = 1; + } else { + unexpected = 0; } tx.msg.code = NMRP_C_NONE; @@ -518,11 +521,17 @@ int nmrp_do(struct nmrpd_args *args) break; case NMRP_C_TFTP_UL_REQ: - if (++ulreqs > 1) { - if (verbosity) { - printf("Ignoring upload request %d.\n", ulreqs); + if (!unexpected) { + 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); break; } From 57a275312cc1120aaa7d167e489bf40c872307a0 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 12:42:20 +0100 Subject: [PATCH 06/30] Better handling of extra upload requests --- nmrp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nmrp.c b/nmrp.c index f95fd57..e19c843 100644 --- a/nmrp.c +++ b/nmrp.c @@ -349,7 +349,7 @@ int nmrp_do(struct nmrpd_args *args) char *filename; struct in_addr ipaddr, ipmask; time_t beg; - int i, status, ulreqs, expect, unexpected; + int i, status, ulreqs, expect, upload_ok; struct ethsock *sock; void (*sigh_orig)(int); @@ -433,6 +433,7 @@ int nmrp_do(struct nmrpd_args *args) msg_hton(&tx.msg); i = 0; + upload_ok = 0; beg = time(NULL); while (1) { @@ -469,9 +470,6 @@ int nmrp_do(struct nmrpd_args *args) if (expect != NMRP_C_NONE && rx.msg.code != expect) { fprintf(stderr, "Received %s while waiting for %s!\n", msg_code_str(rx.msg.code), msg_code_str(expect)); - unexpected = 1; - } else { - unexpected = 0; } tx.msg.code = NMRP_C_NONE; @@ -521,7 +519,7 @@ int nmrp_do(struct nmrpd_args *args) break; case NMRP_C_TFTP_UL_REQ: - if (!unexpected) { + if (!upload_ok) { if (++ulreqs > 5) { printf("Bailing out after %d upload requests.\n", ulreqs); @@ -588,6 +586,7 @@ 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); expect = NMRP_C_NONE; } else if (status == -2) { From b95bfc96e53278c701510ae8253e25b1905b5b26 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 14:10:54 +0100 Subject: [PATCH 07/30] Reset timeout when receiving extra upload requests --- nmrp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/nmrp.c b/nmrp.c index e19c843..a15530c 100644 --- a/nmrp.c +++ b/nmrp.c @@ -530,6 +530,7 @@ int nmrp_do(struct nmrpd_args *args) if (verbosity) { printf("Ignoring extra upload request.\n"); } + ethsock_set_timeout(sock, args->ul_timeout); break; } From bc0901e83f4fa4cd20cb115be0016afb165e8fd4 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Wed, 17 Feb 2016 14:14:19 +0100 Subject: [PATCH 08/30] Send keep-alive request to remote after successful upload --- nmrp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nmrp.c b/nmrp.c index a15530c..ae9fc32 100644 --- a/nmrp.c +++ b/nmrp.c @@ -531,6 +531,7 @@ int nmrp_do(struct nmrpd_args *args) printf("Ignoring extra upload request.\n"); } ethsock_set_timeout(sock, args->ul_timeout); + tx.msg.code = NMRP_C_KEEP_ALIVE_REQ; break; } @@ -589,6 +590,7 @@ int nmrp_do(struct nmrpd_args *args) 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; From 324b7fa030a63b1a75c388e1d9a2117c390f13d4 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 18:49:47 +0100 Subject: [PATCH 09/30] Update readme --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f88532..16d09bc 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ 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 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,6 +83,28 @@ 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 interface Z uses 192.168.0.1/255.255.255.0, assigning +192.168.2.100/255.255.255.0 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. + ### Building and installing ###### Linux, Mac OS X, BSDs From 86fb405fd4588dbecb127578cd51814b242cce96 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 18:50:32 +0100 Subject: [PATCH 10/30] Update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 16d09bc..38e7e84 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,8 @@ 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. +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 From 75434c99149d9ad7a7416d45d69bb91ae6d0bf17 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 18:51:43 +0100 Subject: [PATCH 11/30] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38e7e84..132fb75 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ operation took longer than 120 seconds. `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 interface Z uses 192.168.0.1/255.255.255.0, assigning -192.168.2.100/255.255.255.0 makes no sense, because the TFTP upload will +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." From ccbc7c9bba3b01f5eaa94b84e1f683cfdb22300e Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 18:53:21 +0100 Subject: [PATCH 12/30] Update readme --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 132fb75..c4be594 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,25 @@ 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 -v Be verbose -V Print version and exit -L List network interfaces -h Show this screen -```` +``` ### Using nmrpflash @@ -40,10 +41,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,7 +53,7 @@ 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. @@ -60,7 +61,7 @@ Sending configuration: ip 192.168.1.254, mask 255.255.255.0. Uploading EX2700-V1.0.1.8.img ... OK Waiting for remote to respond. Remote finished. Closing connection. -```` +``` ### Common issues ###### "No suitable network interfaces found." @@ -109,9 +110,9 @@ this case setting the IP address to 192.168.1.2). ### Building and installing ###### Linux, Mac OS X, BSDs -```` +``` $ make && sudo make install -```` +``` ###### Windows From 9371642c96c5032e70f87e6c1dd8fe81d075ba68 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 19:14:52 +0100 Subject: [PATCH 13/30] Add msg_add_opt --- nmrp.c | 54 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/nmrp.c b/nmrp.c index ae9fc32..20662fc 100644 --- a/nmrp.c +++ b/nmrp.c @@ -27,11 +27,11 @@ #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 ETH_P_NMRP 0x0912 #define IP_LEN 4 @@ -80,7 +80,7 @@ struct nmrp_msg { uint8_t code; uint8_t id; uint16_t len; - struct nmrp_opt opts[2]; + struct nmrp_opt opts[NMRP_MAX_OPT_NUM]; uint32_t num_opts; } PACKED; @@ -142,7 +142,7 @@ 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) { + for (i = 0; i != len - NMRP_OPT_HDR_LEN; ++i) { if (!(i % 16)) { fprintf(stderr, "\n "); } @@ -186,7 +186,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; } @@ -211,7 +211,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,10 +221,10 @@ 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; } @@ -236,6 +236,33 @@ static void *msg_opt_data(struct nmrp_msg *msg, int type, uint16_t *len) 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 = (struct nmrp_opt*)(((char*)opt) + msg->len); + } + + opt->len = NMRP_OPT_HDR_LEN + len; + opt->type = type; + + if (len) { + memcpy(&opt->val, data, len); + } + + ++msg->num_opts; + + return true; +} + static int pkt_send(struct ethsock *sock, struct nmrp_pkt *pkt) { size_t len = ntohs(pkt->msg.len) + sizeof(pkt->eh); @@ -421,9 +448,10 @@ int nmrp_do(struct nmrpd_args *args) tx.msg.reserved = 0; tx.msg.code = NMRP_C_ADVERTISE; tx.msg.id = 0; - tx.msg.num_opts = 1; + tx.msg.num_opts = 0; + tx.msg.opts[0].type = NMRP_O_MAGIC_NO; - tx.msg.opts[0].len = NMRP_OPT_LEN + 4; + tx.msg.opts[0].len = NMRP_OPT_HDR_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'; @@ -491,19 +519,19 @@ int nmrp_do(struct nmrpd_args *args) tx.msg.num_opts = 2; tx.msg.opts[0].type = NMRP_O_DEV_IP; - tx.msg.opts[0].len = NMRP_OPT_LEN + 2 * 4; + tx.msg.opts[0].len = NMRP_OPT_HDR_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; + tx.msg.opts[1].len = NMRP_OPT_HDR_LEN; #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].len = NMRP_OPT_HDR_LEN + 2; tx.msg.opts[2].val.region = args->region; #endif From 283742f1171bae5610f27a1d7e8264ec17f1bf53 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 19:30:31 +0100 Subject: [PATCH 14/30] Fix stack overflow --- tftp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tftp.c b/tftp.c index 282f6d2..da76dc9 100644 --- a/tftp.c +++ b/tftp.c @@ -216,11 +216,6 @@ 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) From a0d202c45ddf321633d5642597f2b7466f3bf6f7 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 19:35:57 +0100 Subject: [PATCH 15/30] Fix crash in msg_dump if opt->len == 0 --- nmrp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nmrp.c b/nmrp.c index 20662fc..ab1e071 100644 --- a/nmrp.c +++ b/nmrp.c @@ -142,14 +142,16 @@ 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_HDR_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); } From ae554074527cf44bb0610c342f4e7e5b08f28e49 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 19:36:20 +0100 Subject: [PATCH 16/30] Use msg_opt_add --- nmrp.c | 92 +++++++++++++++++++++++----------------------------------- 1 file changed, 36 insertions(+), 56 deletions(-) diff --git a/nmrp.c b/nmrp.c index ab1e071..2a801f1 100644 --- a/nmrp.c +++ b/nmrp.c @@ -33,6 +33,8 @@ #define NMRP_MAX_OPT_SIZE 12 #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 #define MAX_LOOP_RECV 1024 @@ -116,15 +118,6 @@ static const char *msg_code_str(uint16_t code) #undef CASE_CODE } -static void msg_update_len(struct nmrp_msg *msg) -{ - uint32_t i = 0; - msg->len = NMRP_HDR_LEN; - for (; i != msg->num_opts; ++i) { - msg->len += msg->opts[i].len; - } -} - static void msg_dump(struct nmrp_msg *msg, int dump_opts) { struct nmrp_opt *opt; @@ -153,7 +146,7 @@ static void msg_dump(struct nmrp_msg *msg, int dump_opts) fprintf(stderr, "\n"); } remain_len -= len; - opt = (struct nmrp_opt*)(((char*)opt) + len); + opt = NMRP_OPT_NEXT(opt); } } } @@ -161,13 +154,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; } } @@ -200,7 +196,7 @@ static int msg_ntoh(struct nmrp_msg *msg) } remaining -= opt->len; - ++opt; + opt = NMRP_OPT_NEXT(opt); } if (!remaining) { @@ -232,7 +228,7 @@ static void *msg_opt_data(struct nmrp_msg *msg, uint16_t type, uint16_t *len) } remaining -= opt->len; - opt = (struct nmrp_opt*)((char*)opt) + opt->len; + opt = NMRP_OPT_NEXT(opt); } return NULL; @@ -249,8 +245,8 @@ static void msg_opt_add(struct nmrp_msg *msg, uint16_t type, void *data, fprintf(stderr, "Invalid option - this is a bug.\n"); } - for (; i != msg->num_opts; ++i) { - opt = (struct nmrp_opt*)(((char*)opt) + msg->len); + for (; i <= msg->num_opts; ++i) { + opt = NMRP_OPT_NEXT(opt); } opt->len = NMRP_OPT_HDR_LEN + len; @@ -260,9 +256,15 @@ static void msg_opt_add(struct nmrp_msg *msg, uint16_t type, void *data, memcpy(&opt->val, data, len); } + msg->len += opt->len; ++msg->num_opts; +} - return true; +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) @@ -376,11 +378,14 @@ int nmrp_do(struct nmrpd_args *args) uint8_t *src, dest[6]; uint16_t len; char *filename; - struct in_addr ipaddr, ipmask; time_t beg; 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"); @@ -392,12 +397,12 @@ 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; } @@ -422,7 +427,7 @@ int nmrp_do(struct nmrpd_args *args) return 1; } - status = is_valid_ip(sock, &ipaddr, &ipmask); + 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", @@ -447,19 +452,8 @@ 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 = 0; - - tx.msg.opts[0].type = NMRP_O_MAGIC_NO; - tx.msg.opts[0].len = NMRP_OPT_HDR_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; @@ -502,11 +496,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; @@ -518,23 +508,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_HDR_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_HDR_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_HDR_LEN + 2; - tx.msg.opts[2].val.region = args->region; + if (args->region) { + msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, &args->region, 2); + } #endif expect = NMRP_C_TFTP_UL_REQ; @@ -575,7 +556,7 @@ int nmrp_do(struct nmrpd_args *args) len, filename); } else if (!args->file_remote) { args->file_remote = args->file_local; - printf("Received upload request with empty filename."); + printf("Received upload request with empty filename.\n"); } status = 0; @@ -592,7 +573,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) { @@ -647,7 +628,6 @@ 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) { From cbb94be759f6bd4981a807e259243d10519ac740 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 21:58:23 +0100 Subject: [PATCH 17/30] Send correct region value --- nmrp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nmrp.c b/nmrp.c index 2a801f1..db351fa 100644 --- a/nmrp.c +++ b/nmrp.c @@ -376,7 +376,7 @@ 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; time_t beg; int i, status, ulreqs, expect, upload_ok; @@ -514,7 +514,8 @@ int nmrp_do(struct nmrpd_args *args) #ifdef NMRPFLASH_SET_REGION if (args->region) { - msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, &args->region, 2); + region = htons(args->region); + msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, ®ion, 2); } #endif From d7caf78f5ebaf37e7099f470bf360e62e36fc02a Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:11:12 +0100 Subject: [PATCH 18/30] Accept pretty names for -R instead of codes --- main.c | 12 +++++------- nmrp.c | 29 +++++++++++++++++++++++++++-- nmrpd.h | 3 +-- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/main.c b/main.c index 9760c61..73f22f7 100644 --- a/main.c +++ b/main.c @@ -42,7 +42,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 +83,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 +121,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 +145,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 db351fa..327bf81 100644 --- a/nmrp.c +++ b/nmrp.c @@ -118,6 +118,22 @@ static const char *msg_code_str(uint16_t code) #undef CASE_CODE } +static uint16_t to_region_code(const char *region) +{ +#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) { struct nmrp_opt *opt; @@ -420,6 +436,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); @@ -513,8 +539,7 @@ int nmrp_do(struct nmrpd_args *args) msg_opt_add(&tx.msg, NMRP_O_FW_UP, NULL, 0); #ifdef NMRPFLASH_SET_REGION - if (args->region) { - region = htons(args->region); + if (region) { msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, ®ion, 2); } #endif diff --git a/nmrpd.h b/nmrpd.h index 28d3f0f..841b4f3 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -71,8 +71,7 @@ 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); From fb8143470f8b8dbe9b1494f3ff05d309288cc8fb Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:23:00 +0100 Subject: [PATCH 19/30] Doc updates --- nmrp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nmrp.c b/nmrp.c index 327bf81..9b05861 100644 --- a/nmrp.c +++ b/nmrp.c @@ -82,7 +82,9 @@ struct nmrp_msg { uint8_t code; uint8_t id; uint16_t len; + /* 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; From 54114efc39ab39087c6093065ca704ee1475e87c Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:23:09 +0100 Subject: [PATCH 20/30] Always enable -R option --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 73f22f7..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) From 91e314f4f8c1866cb3d6b0ce0929de14e40a21bd Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:24:16 +0100 Subject: [PATCH 21/30] Version bump --- nmrpflash.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From a4345fc93b18e68a62829561ffaf1636df5e4039 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:29:38 +0100 Subject: [PATCH 22/30] Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c4be594..91f1d43 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Options (-a, -i and -f and/or -c are mandatory): -t Timeout (in milliseconds) for regular messages -T Time (seconds) to wait after successfull TFTP upload -p Port to use for 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 From 9cf66860c481beef9cd41029acd82f3535521d5d Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Thu, 18 Feb 2016 22:41:04 +0100 Subject: [PATCH 23/30] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 91f1d43..9db374f 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,11 @@ $ 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 From 185541f19f8be82889a57b009917f5f3bbf30df5 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 8 Aug 2016 20:00:02 +0200 Subject: [PATCH 24/30] Update README.md --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 9db374f..0d9a216 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,25 @@ 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 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 for this info! + ###### "Timeout while waiting for CLOSE_REQ." After a successful file upload, `nmrpflash` waits for up to 120 seconds for an From be07c8a499c140036fb80967eb24510228160ed9 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 8 Aug 2016 20:30:26 +0200 Subject: [PATCH 25/30] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d9a216..c94fbba 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ where `` is the pretty interface name (e.g. "Local Area Connection"; `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 for this info! +Cheers to [@ntadmin](https://github.com/ntadmin) for this info! ###### "Timeout while waiting for CLOSE_REQ." From dff7f25bddb31b43049ab88decd2c2170e177089 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 9 Aug 2016 09:25:29 +0200 Subject: [PATCH 26/30] Fix crash when using -c --- nmrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nmrp.c b/nmrp.c index 9b05861..7995d42 100644 --- a/nmrp.c +++ b/nmrp.c @@ -425,7 +425,7 @@ int nmrp_do(struct nmrpd_args *args) 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; } From d58840ea45c97335ceb45fdd2ab3205950ebfb1a Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 9 Aug 2016 09:49:29 +0200 Subject: [PATCH 27/30] Store interface index on Windows --- ethsock.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ethsock.c b/ethsock.c index 8f970e1..7c1822c 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; } @@ -458,7 +464,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) From e4d61b8c7f3d6be5ca455001d0493ee8a96f124e Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 9 Aug 2016 10:08:42 +0200 Subject: [PATCH 28/30] Add windows arp code --- ethsock.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/ethsock.c b/ethsock.c index 7c1822c..232d84f 100644 --- a/ethsock.c +++ b/ethsock.c @@ -442,6 +442,50 @@ 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, int nofail) +{ + DWORD ret; + MIB_IPNETROW arp = { + .dwIndex = sock->index, + .dwPhysAddrLen = 6, + .dwAddr = ipaddr->s_addr, + .dwType = MIB_IPNET_TYPE_STATIC + }; + + memcpy(arp.bPhysAddr, hwaddr, 6); + + ret = add ? CreateIpNetEntry(&arp) : DeleteIpNetEntry(&arp); + if (ret != NO_ERROR && !nofail) { + win_perror2(add ? "CreateIpNetEntry" : "DeleteIpNetEntry", ret); + return -1; + } + + return 0; +} + +int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + ethsock_arp(sock, hwaddr, ipaddr, 0, 1); + return ethsock_arp(sock, hwaddr, ipaddr, 1, 0); +} + +int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) +{ + return ethsock_arp(sock, hwaddr, ipaddr, 0, 0); +} +#endif + static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr) { #ifndef NMRPFLASH_WINDOWS From a050f74bce84922f013d2e6363357373196ae8e6 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 9 Aug 2016 11:41:50 +0200 Subject: [PATCH 29/30] Create static ARP entry for device --- ethsock.c | 20 ++++++++++++-------- nmrp.c | 18 ++++++++++++++++++ nmrpd.h | 2 ++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/ethsock.c b/ethsock.c index 232d84f..61e9759 100644 --- a/ethsock.c +++ b/ethsock.c @@ -453,7 +453,7 @@ int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipadd return 0; } #else -static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr, int add, int nofail) +static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr, int add) { DWORD ret; MIB_IPNETROW arp = { @@ -465,10 +465,14 @@ static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ip memcpy(arp.bPhysAddr, hwaddr, 6); - ret = add ? CreateIpNetEntry(&arp) : DeleteIpNetEntry(&arp); - if (ret != NO_ERROR && !nofail) { - win_perror2(add ? "CreateIpNetEntry" : "DeleteIpNetEntry", ret); - return -1; + if (add) { + ret = CreateIpNetEntry(&arp); + if (ret != NO_ERROR) { + win_perror2("CreateIpNetEntry", ret); + return -1; + } + } else { + DeleteIpNetEntry(&arp); } return 0; @@ -476,13 +480,13 @@ static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ip int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr) { - ethsock_arp(sock, hwaddr, ipaddr, 0, 1); - return ethsock_arp(sock, hwaddr, ipaddr, 1, 0); + 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, 0); + return ethsock_arp(sock, hwaddr, ipaddr, 0); } #endif diff --git a/nmrp.c b/nmrp.c index 7995d42..fbb4cea 100644 --- a/nmrp.c +++ b/nmrp.c @@ -377,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); @@ -465,6 +472,7 @@ int nmrp_do(struct nmrpd_args *args) } gsock = sock; + garp = 0; sigh_orig = signal(SIGINT, sigh); if (ethsock_set_timeout(sock, args->rx_timeout)) { @@ -556,6 +564,15 @@ 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 (!upload_ok) { @@ -693,6 +710,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 841b4f3..ef25a69 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -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 From d46799523638b7bd172b9948aecbe9cf67a504cd Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 9 Aug 2016 12:21:10 +0200 Subject: [PATCH 30/30] Actually bail out after sending CLOSE_REQ --- nmrp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nmrp.c b/nmrp.c index fbb4cea..59938db 100644 --- a/nmrp.c +++ b/nmrp.c @@ -679,6 +679,10 @@ int nmrp_do(struct nmrpd_args *args) perror("sendto"); goto out; } + + if (tx.msg.code == NMRP_C_CLOSE_REQ) { + goto out; + } } if (rx.msg.code == NMRP_C_CLOSE_REQ) {