From f301e1727e530082479ba1d7f83ee01b0b19500c Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Sat, 29 Feb 2020 21:41:15 +0100 Subject: [PATCH 01/28] Send ADVERTISE and CONFIG_ACK in one go --- nmrp.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/nmrp.c b/nmrp.c index e4fcbf1..49070e9 100644 --- a/nmrp.c +++ b/nmrp.c @@ -472,7 +472,6 @@ int nmrp_do(struct nmrpd_args *args) memcpy(tx.eh.ether_dhost, dest, 6); tx.eh.ether_type = htons(ETH_P_NMRP); - msg_mkadvertise(&tx.msg, "NTGR"); i = 0; upload_ok = 0; @@ -484,8 +483,13 @@ int nmrp_do(struct nmrpd_args *args) fflush(stdout); i = (i + 1) & 3; + msg_mkadvertise(&tx.msg, "NTGR"); + if (pkt_send(sock, &tx) < 0) { + goto out; + } + + msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region); if (pkt_send(sock, &tx) < 0) { - xperror("sendto"); goto out; } @@ -510,8 +514,15 @@ int nmrp_do(struct nmrpd_args *args) } } + printf("\n"); + memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); + + if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) { + goto out; + } + expect = NMRP_C_CONF_REQ; ulreqs = 0; kareqs = 0; @@ -539,15 +550,9 @@ int nmrp_do(struct nmrpd_args *args) printf("Received configuration request from %s.\n", mac_to_str(rx.eh.ether_shost)); - memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); - printf("Sending configuration: %s/%d.\n", args->ipaddr, bitcount(ipmask.s_addr)); - if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) { - goto out; - } - break; case NMRP_C_TFTP_UL_REQ: if (!upload_ok) { @@ -651,7 +656,6 @@ int nmrp_do(struct nmrpd_args *args) if (tx.msg.code != NMRP_C_NONE) { if (pkt_send(sock, &tx) < 0) { - xperror("sendto"); goto out; } From 0ab6b37b9c801cbfa33c3c92a5591910d1cb8284 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Sun, 1 Mar 2020 20:08:37 +0100 Subject: [PATCH 02/28] Add blind mode (-B) --- main.c | 17 ++++++++++++++--- nmrp.c | 31 +++++++++++++++++++------------ nmrpd.h | 1 + 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/main.c b/main.c index 2ef2052..6dda5e8 100644 --- a/main.c +++ b/main.c @@ -33,6 +33,7 @@ void usage(FILE *fp) "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" + " -B Blind mode (don't wait for NMRP responses)\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" @@ -130,7 +131,7 @@ void require_admin() int main(int argc, char **argv) { int c, val, max; - int list = 0; + bool list = false, have_dest_mac = false; struct nmrpd_args args = { .rx_timeout = 200, .ul_timeout = 5 * 60 * 1000, @@ -145,6 +146,7 @@ int main(int argc, char **argv) .op = NMRP_UPLOAD_FW, .port = 69, .region = NULL, + .blind = false, }; #ifdef NMRPFLASH_WINDOWS char *newpath = NULL; @@ -181,7 +183,7 @@ int main(int argc, char **argv) opterr = 0; - while ((c = getopt(argc, argv, "a:A:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) { + while ((c = getopt(argc, argv, "a:A:Bc:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) { max = 0x7fffffff; switch (c) { case 'a': @@ -190,6 +192,9 @@ int main(int argc, char **argv) case 'A': args.ipaddr_intf = optarg; break; + case 'B': + args.blind = true; + break; case 'c': args.tftpcmd = optarg; break; @@ -204,6 +209,7 @@ int main(int argc, char **argv) break; case 'm': args.mac = optarg; + have_dest_mac = true; break; case 'M': args.ipmask = optarg; @@ -243,7 +249,7 @@ int main(int argc, char **argv) ++verbosity; break; case 'L': - list = 1; + list = true; break; case 'h': usage(stdout); @@ -269,6 +275,11 @@ int main(int argc, char **argv) return 1; } + if (args.blind && !have_dest_mac) { + fprintf(stderr, "Error: use of -B requires -m .\n"); + return 1; + } + #ifndef NMRPFLASH_FUZZ if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf)) { usage(stderr); diff --git a/nmrp.c b/nmrp.c index 49070e9..25e3add 100644 --- a/nmrp.c +++ b/nmrp.c @@ -356,7 +356,7 @@ int nmrp_do(struct nmrpd_args *args) uint16_t region; char *filename; time_t beg; - int i, status, ulreqs, expect, upload_ok, autoip, kareqs; + int i, timeout, status, ulreqs, expect, upload_ok, autoip, kareqs; struct ethsock *sock; struct ethsock_ip_undo *ip_undo = NULL; struct ethsock_arp_undo *arp_undo = NULL; @@ -472,9 +472,11 @@ int nmrp_do(struct nmrpd_args *args) memcpy(tx.eh.ether_dhost, dest, 6); tx.eh.ether_type = htons(ETH_P_NMRP); + msg_mkadvertise(&tx.msg, "NTGR"); i = 0; upload_ok = 0; + timeout = args->blind ? 10 : NMRP_INITIAL_TIMEOUT; beg = time_monotonic(); while (!g_interrupted) { @@ -483,12 +485,6 @@ int nmrp_do(struct nmrpd_args *args) fflush(stdout); i = (i + 1) & 3; - msg_mkadvertise(&tx.msg, "NTGR"); - if (pkt_send(sock, &tx) < 0) { - goto out; - } - - msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region); if (pkt_send(sock, &tx) < 0) { goto out; } @@ -507,14 +503,19 @@ int nmrp_do(struct nmrpd_args *args) } else { /* because we don't want nmrpflash's exit status to be zero */ status = 1; - if ((time_monotonic() - beg) >= NMRP_INITIAL_TIMEOUT) { - printf("\nNo response after 60 seconds. Bailing out.\n"); - goto out; + if ((time_monotonic() - beg) >= timeout) { + printf("\nNo response after %d seconds. ", timeout); + if (!args->blind) { + printf("Bailing out.\n"); + goto out; + } else { + printf("Continuing blindly."); + break; + } } } } - printf("\n"); memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); @@ -679,7 +680,13 @@ int nmrp_do(struct nmrpd_args *args) fprintf(stderr, "Timeout while waiting for %s.\n", msg_code_str(expect)); } - goto out; + + if (!args->blind) { + goto out; + } else { + // fake a response + msg_init(&rx.msg, expect); + } } ethsock_set_timeout(sock, args->rx_timeout); diff --git a/nmrpd.h b/nmrpd.h index 0773777..086d2af 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -92,6 +92,7 @@ struct nmrpd_args { const char *intf; const char *mac; enum nmrp_op op; + bool blind; uint16_t port; const char *region; }; From ccd4b0204b0e23a542795252dcfd1bb885444a48 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Sun, 1 Mar 2020 21:48:18 +0100 Subject: [PATCH 03/28] Blind mode improvements --- nmrp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/nmrp.c b/nmrp.c index 25e3add..1f17fd8 100644 --- a/nmrp.c +++ b/nmrp.c @@ -492,6 +492,8 @@ int nmrp_do(struct nmrpd_args *args) status = pkt_recv(sock, &rx); if (status == 0) { if (memcmp(rx.eh.ether_dhost, src, 6) == 0) { + // set the destination MAC for all subsequent packages + memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); break; } else if (verbosity) { printf("\nIgnoring bogus response: %s -> %s.\n", @@ -509,7 +511,10 @@ int nmrp_do(struct nmrpd_args *args) printf("Bailing out.\n"); goto out; } else { - printf("Continuing blindly."); + // we're blind, so fake a response from the MAC specified by -m + memcpy(rx.eh.ether_dhost, dest, 6); + msg_init(&rx.msg, NMRP_C_CONF_REQ); + printf("Faking one."); break; } } @@ -518,8 +523,6 @@ int nmrp_do(struct nmrpd_args *args) printf("\n"); - memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); - if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) { goto out; } @@ -677,15 +680,17 @@ int nmrp_do(struct nmrpd_args *args) status = pkt_recv(sock, &rx); if (status) { if (status == 2) { - fprintf(stderr, "Timeout while waiting for %s.\n", + fprintf(stderr, "Timeout while waiting for %s. ", msg_code_str(expect)); } if (!args->blind) { + printf("\n"); goto out; } else { - // fake a response + printf("Faking response.\n"); msg_init(&rx.msg, expect); + memcpy(rx.eh.ether_shost, tx.eh.ether_dhost, 6); } } From ddebe8979ef3b123f22936763e42cba8a679c6fb Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Sun, 1 Mar 2020 21:55:59 +0100 Subject: [PATCH 04/28] Extend blind mode to TFTP --- tftp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tftp.c b/tftp.c index 27ca320..b6f5ce7 100644 --- a/tftp.c +++ b/tftp.c @@ -453,6 +453,12 @@ int tftp_put(struct nmrpd_args *args) } else if (!ret) { if (++timeouts < 5 || (!block && timeouts < 10)) { continue; + } else if (args->blind) { + timeouts = 0; + // fake an ACK packet + pkt_mknum(rx, ACK); + pkt_mknum(rx + 2, block); + continue; } else if (block) { fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block); } else { From 4c376a76f86779b7f8e98871f9a864fc8aea2b60 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Sun, 1 Mar 2020 22:32:26 +0100 Subject: [PATCH 05/28] Fix mac handling in blind mode --- nmrp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nmrp.c b/nmrp.c index 1f17fd8..d85d5ae 100644 --- a/nmrp.c +++ b/nmrp.c @@ -492,8 +492,6 @@ int nmrp_do(struct nmrpd_args *args) status = pkt_recv(sock, &rx); if (status == 0) { if (memcmp(rx.eh.ether_dhost, src, 6) == 0) { - // set the destination MAC for all subsequent packages - memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); break; } else if (verbosity) { printf("\nIgnoring bogus response: %s -> %s.\n", @@ -512,7 +510,7 @@ int nmrp_do(struct nmrpd_args *args) goto out; } else { // we're blind, so fake a response from the MAC specified by -m - memcpy(rx.eh.ether_dhost, dest, 6); + memcpy(rx.eh.ether_shost, dest, 6); msg_init(&rx.msg, NMRP_C_CONF_REQ); printf("Faking one."); break; @@ -523,6 +521,8 @@ int nmrp_do(struct nmrpd_args *args) printf("\n"); + memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6); + if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) { goto out; } From 9a9abfc07cccdfbcdb3d1479938de8ed7c504359 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 08:34:44 +0100 Subject: [PATCH 06/28] Don't use -t timeout for TFTP transfers --- nmrpd.h | 4 ++++ tftp.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/nmrpd.h b/nmrpd.h index 086d2af..d65c811 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -62,6 +62,10 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + #ifndef PACKED #define PACKED __attribute__((packed)) #endif diff --git a/tftp.c b/tftp.c index b6f5ce7..9fd361a 100644 --- a/tftp.c +++ b/tftp.c @@ -315,6 +315,7 @@ int tftp_put(struct nmrpd_args *args) const char *file_remote = args->file_remote; char *val, *end; bool rollover; + unsigned rx_timeout = MAX(args->rx_timeout / 200, 1); sock = -1; ret = -1; @@ -367,6 +368,7 @@ int tftp_put(struct nmrpd_args *args) xperror("inet_addr"); goto cleanup; } + addr.sin_port = htons(args->port); blksize = 512; @@ -447,7 +449,7 @@ int tftp_put(struct nmrpd_args *args) } } - ret = tftp_recvfrom(sock, rx, &port, args->rx_timeout, blksize + 4); + ret = tftp_recvfrom(sock, rx, &port, rx_timeout, blksize + 4); if (ret < 0) { goto cleanup; } else if (!ret) { From 30a2f28f1abc60d0c988fe8498313c8f29adbdb0 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 08:45:21 +0100 Subject: [PATCH 07/28] Change select_fd args to microseconds --- ethsock.c | 4 ++-- main.c | 8 ++++---- nmrpd.h | 2 ++ tftp.c | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ethsock.c b/ethsock.c index 838f6bf..b346ce9 100644 --- a/ethsock.c +++ b/ethsock.c @@ -640,8 +640,8 @@ int select_fd(int fd, unsigned timeout) FD_ZERO(&fds); FD_SET(fd, &fds); - tv.tv_sec = timeout / 1000; - tv.tv_usec = 1000 * (timeout % 1000); + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; status = select(fd + 1, &fds, NULL, NULL, &tv); if (status < 0) { diff --git a/main.c b/main.c index 6dda5e8..242e7be 100644 --- a/main.c +++ b/main.c @@ -33,14 +33,14 @@ void usage(FILE *fp) "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" - " -B Blind mode (don't wait for NMRP responses)\n" + " -B Blind mode (don't wait for response packets)\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" " -i Network interface directly connected to device\n" " -m MAC address of target device (xx:xx:xx:xx:xx:xx)\n" " -M Subnet mask to assign to target device\n" - " -t Timeout (in milliseconds) for regular messages\n" + " -t Timeout (in milliseconds) for NMRP packets\n" " -T Time (seconds) to wait after successfull TFTP upload\n" " -p Port to use for TFTP upload\n" #ifdef NMRPFLASH_SET_REGION @@ -133,7 +133,7 @@ int main(int argc, char **argv) int c, val, max; bool list = false, have_dest_mac = false; struct nmrpd_args args = { - .rx_timeout = 200, + .rx_timeout = NMRPFLASH_DEF_RX_TIMEOUT * 1000, .ul_timeout = 5 * 60 * 1000, .tftpcmd = NULL, .file_local = NULL, @@ -235,7 +235,7 @@ int main(int argc, char **argv) if (c == 'p') { args.port = val; } else if (c == 't') { - args.rx_timeout = val; + args.rx_timeout = val * 1000; } else if (c == 'T') { args.ul_timeout = val * 1000; } diff --git a/nmrpd.h b/nmrpd.h index d65c811..c1dc77e 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -72,6 +72,8 @@ #define NMRPFLASH_SET_REGION +#define NMRPFLASH_DEF_RX_TIMEOUT 200 + struct eth_hdr { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; diff --git a/tftp.c b/tftp.c index 9fd361a..5c37693 100644 --- a/tftp.c +++ b/tftp.c @@ -315,7 +315,7 @@ int tftp_put(struct nmrpd_args *args) const char *file_remote = args->file_remote; char *val, *end; bool rollover; - unsigned rx_timeout = MAX(args->rx_timeout / 200, 1); + unsigned rx_timeout = MAX(args->rx_timeout / NMRPFLASH_DEF_RX_TIMEOUT, 1000); sock = -1; ret = -1; From da9700c71d59d389cb557878656ff4339a017390 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 09:30:27 +0100 Subject: [PATCH 08/28] Use shorter TFTP timeout in blind mode --- main.c | 2 +- nmrpd.h | 2 -- tftp.c | 5 +++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index 242e7be..58afc56 100644 --- a/main.c +++ b/main.c @@ -133,7 +133,7 @@ int main(int argc, char **argv) int c, val, max; bool list = false, have_dest_mac = false; struct nmrpd_args args = { - .rx_timeout = NMRPFLASH_DEF_RX_TIMEOUT * 1000, + .rx_timeout = 200 * 1000, .ul_timeout = 5 * 60 * 1000, .tftpcmd = NULL, .file_local = NULL, diff --git a/nmrpd.h b/nmrpd.h index c1dc77e..d65c811 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -72,8 +72,6 @@ #define NMRPFLASH_SET_REGION -#define NMRPFLASH_DEF_RX_TIMEOUT 200 - struct eth_hdr { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; diff --git a/tftp.c b/tftp.c index 5c37693..eb2c314 100644 --- a/tftp.c +++ b/tftp.c @@ -315,7 +315,8 @@ int tftp_put(struct nmrpd_args *args) const char *file_remote = args->file_remote; char *val, *end; bool rollover; - unsigned rx_timeout = MAX(args->rx_timeout / NMRPFLASH_DEF_RX_TIMEOUT, 1000); + const unsigned rx_timeout = MAX(args->rx_timeout / (args->blind ? 50 : 5), 2000); + const unsigned max_timeouts = args->blind ? 3 : 5; sock = -1; ret = -1; @@ -453,7 +454,7 @@ int tftp_put(struct nmrpd_args *args) if (ret < 0) { goto cleanup; } else if (!ret) { - if (++timeouts < 5 || (!block && timeouts < 10)) { + if (++timeouts < max_timeouts || (!block && timeouts < (max_timeouts * 4))) { continue; } else if (args->blind) { timeouts = 0; From 1f3a435eb7cee0f38da3e546c3a20c1f4aaf03dd Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 09:41:56 +0100 Subject: [PATCH 09/28] Update help text and readme --- README.md | 22 ++++++++++++++++------ main.c | 4 ++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ee9e516..639bde1 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,17 @@ Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available ``` Usage: nmrpflash [OPTIONS...] -Options (-i and -f and/or -c are mandatory): +Options (-i, and -f or -c are mandatory): -a IP address to assign to target device - -A IP address to assign to interface + -A IP address to assign to selected interface + -B Blind mode (don't wait for response packets) -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 Timeout (in milliseconds) for NMRP packets -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) @@ -93,9 +94,18 @@ C:\> net start npf ###### "No response after 60 seconds. Bailing out." -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. +The router did not respond. Always run `nmrpflash` in the following +manner: + +* Turn off the router. +* Run `nmrpflash`. +* Turn on the router. + +If that still doesn't work, you can try "blind mode", which can be +invoked using `-B`. Note that you also have to specify your router's +mac address using `-m xx:xx:xx:xx:xx:xx`. + +It's also possible that your device does not support the NMRP protocol. ###### "Timeout while waiting for ACK(0)/OACK." diff --git a/main.c b/main.c index 58afc56..cd1a81b 100644 --- a/main.c +++ b/main.c @@ -30,9 +30,9 @@ void usage(FILE *fp) fprintf(fp, "Usage: nmrpflash [OPTIONS...]\n" "\n" - "Options (-i, -f and/or -c are mandatory):\n" + "Options (-i, and -f or -c are mandatory):\n" " -a IP address to assign to target device\n" - " -A IP address to assign to seleted interface\n" + " -A IP address to assign to selected interface\n" " -B Blind mode (don't wait for response packets)\n" " -c Command to run before (or instead of) TFTP upload\n" " -f Firmware file\n" From aca33657c0efd78a26ae29d21121aff1eaa80e86 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 09:58:14 +0100 Subject: [PATCH 10/28] Clarify comment regarding default IP --- nmrp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nmrp.c b/nmrp.c index d85d5ae..29d3c6d 100644 --- a/nmrp.c +++ b/nmrp.c @@ -384,8 +384,13 @@ int nmrp_do(struct nmrpd_args *args) if (!args->ipaddr) { autoip = true; - /* The MAC of the device that was used to test this utility starts - * with a4:2b:8c, hence 164 (0xa4) and 183 (0x2b + 0x8c) + /* A random IP address. The MAC of the first device that was + * used to test this utility starts with a4:2b:8c, so we use + * 164 (0xa4) and 183 (0x2b + 0x8c). + * + * These addresses should not cause collisions on most networks, + * and if they do, the user is probably "poweruser" enough to + * be able to use the -a and -A options. */ args->ipaddr = "10.164.183.252"; From 490da10d04ac329dfb36b16a94ff306b8430d78c Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 11:29:54 +0100 Subject: [PATCH 11/28] Exit after successful upload in blind mode --- nmrp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nmrp.c b/nmrp.c index 29d3c6d..9df5b30 100644 --- a/nmrp.c +++ b/nmrp.c @@ -634,6 +634,10 @@ int nmrp_do(struct nmrpd_args *args) } if (!status) { + if (args->blind) { + goto out; + } + printf("Waiting for remote to respond.\n"); upload_ok = 1; ethsock_set_timeout(sock, args->ul_timeout); From 79daac1e2216adddf3ce41f24ceaca5766797250 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 11:47:05 +0100 Subject: [PATCH 12/28] Always show opt length in Wireshark dissector --- wireshark-nmrp.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wireshark-nmrp.lua b/wireshark-nmrp.lua index 6463ccf..234d9eb 100644 --- a/wireshark-nmrp.lua +++ b/wireshark-nmrp.lua @@ -52,13 +52,14 @@ function nmrp_dissect_opt(opt, buffer, tree) return end + tree:add(opt_len_f, buffer(2, 2)) + if opt == 0x01 or opt == 0x0181 then tree:add(buffer(4), "Value: " .. buffer(4):string()) elseif opt == 0x02 then tree:add(buffer(4, 4), "Address: " .. tostring(buffer(4, 4):ipv4())) tree:add(buffer(8, 4), "Netmask: " .. tostring(buffer(8, 4):ipv4())) else - tree:add(opt_len_f, buffer(2, 2)) tree:add(opt_data_f, buffer(4, buffer:len() - 4)) end end From cf95657f5da5dab919f861febf59cbc9d09de833 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 14:21:02 +0100 Subject: [PATCH 13/28] Add TFTP upload spinner --- tftp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tftp.c b/tftp.c index eb2c314..735f992 100644 --- a/tftp.c +++ b/tftp.c @@ -305,6 +305,8 @@ inline bool tftp_is_valid_filename(const char *filename) return strlen(filename) <= 255 && is_netascii(filename); } +static const char *spinner = "\\|/-"; + int tftp_put(struct nmrpd_args *args) { struct sockaddr_in addr; @@ -416,6 +418,10 @@ int tftp_put(struct nmrpd_args *args) } } + printf("%c ", spinner[block & 3]); + fflush(stdout); + printf("\b\b"); + pkt_mknum(tx, DATA); pkt_mknum(tx + 2, block); len = read(fd, tx + 4, blksize); From 00505bc5160b3d6805c693ff8bc4ae61dff08685 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 2 Mar 2020 14:25:09 +0100 Subject: [PATCH 14/28] Update readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 639bde1..7d88e14 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,9 @@ manner: If that still doesn't work, you can try "blind mode", which can be invoked using `-B`. Note that you also have to specify your router's -mac address using `-m xx:xx:xx:xx:xx:xx`. +mac address using `-m xx:xx:xx:xx:xx:xx`. Also beware that in this mode, +careful timing between running `nmrpflash` and turning on the router may +be required! It's also possible that your device does not support the NMRP protocol. From e95526d06cd4d8869befb79a26ade8bbc2262265 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Fri, 6 Mar 2020 18:43:03 +0100 Subject: [PATCH 15/28] Don't print messages on fake-packet receipt --- nmrp.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/nmrp.c b/nmrp.c index 9df5b30..4f262d9 100644 --- a/nmrp.c +++ b/nmrp.c @@ -356,7 +356,7 @@ int nmrp_do(struct nmrpd_args *args) uint16_t region; char *filename; time_t beg; - int i, timeout, status, ulreqs, expect, upload_ok, autoip, kareqs; + int i, timeout, status, ulreqs, expect, upload_ok, autoip, ka_reqs, fake; struct ethsock *sock; struct ethsock_ip_undo *ip_undo = NULL; struct ethsock_arp_undo *arp_undo = NULL; @@ -481,6 +481,7 @@ int nmrp_do(struct nmrpd_args *args) i = 0; upload_ok = 0; + fake = 0; timeout = args->blind ? 10 : NMRP_INITIAL_TIMEOUT; beg = time_monotonic(); @@ -517,7 +518,8 @@ int nmrp_do(struct nmrpd_args *args) // we're blind, so fake a response from the MAC specified by -m memcpy(rx.eh.ether_shost, dest, 6); msg_init(&rx.msg, NMRP_C_CONF_REQ); - printf("Faking one."); + printf("Continuing blindly."); + fake = 1; break; } } @@ -534,7 +536,7 @@ int nmrp_do(struct nmrpd_args *args) expect = NMRP_C_CONF_REQ; ulreqs = 0; - kareqs = 0; + ka_reqs = 0; while (!g_interrupted) { if (expect != NMRP_C_NONE && rx.msg.code != expect) { @@ -556,8 +558,10 @@ int nmrp_do(struct nmrpd_args *args) msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region); expect = NMRP_C_TFTP_UL_REQ; - printf("Received configuration request from %s.\n", - mac_to_str(rx.eh.ether_shost)); + if (!fake) { + printf("Received configuration request from %s.\n", + mac_to_str(rx.eh.ether_shost)); + } printf("Sending configuration: %s/%d.\n", args->ipaddr, bitcount(ipmask.s_addr)); @@ -588,7 +592,9 @@ int nmrp_do(struct nmrpd_args *args) printf("Received upload request: filename '%s'.\n", filename); } else if (!args->file_remote) { args->file_remote = leafname(args->file_local); - printf("Received upload request without filename.\n"); + if (!fake) { + printf("Received upload request without filename.\n"); + } } status = 0; @@ -653,7 +659,7 @@ int nmrp_do(struct nmrpd_args *args) case NMRP_C_KEEP_ALIVE_REQ: tx.msg.code = NMRP_C_KEEP_ALIVE_ACK; ethsock_set_timeout(sock, args->ul_timeout); - printf("\rReceived keep-alive request (%d). ", ++kareqs); + printf("\rReceived keep-alive request (%d). ", ++ka_reqs); break; case NMRP_C_CLOSE_REQ: tx.msg.code = NMRP_C_CLOSE_ACK; @@ -668,17 +674,13 @@ int nmrp_do(struct nmrpd_args *args) } if (tx.msg.code != NMRP_C_NONE) { - if (pkt_send(sock, &tx) < 0) { - goto out; - } - - if (tx.msg.code == NMRP_C_CLOSE_REQ) { + if (pkt_send(sock, &tx) != 0 || tx.msg.code == NMRP_C_CLOSE_REQ) { goto out; } } if (rx.msg.code == NMRP_C_CLOSE_REQ) { - if (kareqs) { + if (ka_reqs) { printf("\n"); } @@ -689,18 +691,21 @@ int nmrp_do(struct nmrpd_args *args) status = pkt_recv(sock, &rx); if (status) { if (status == 2) { - fprintf(stderr, "Timeout while waiting for %s. ", - msg_code_str(expect)); - } + if (!args->blind) { + fprintf(stderr, "Timeout while waiting for %s.\n", + msg_code_str(expect)); + goto out; + } - if (!args->blind) { - printf("\n"); - goto out; - } else { - printf("Faking response.\n"); + // fake response msg_init(&rx.msg, expect); memcpy(rx.eh.ether_shost, tx.eh.ether_dhost, 6); + fake = 1; + } else { + goto out; } + } else { + fake = 0; } ethsock_set_timeout(sock, args->rx_timeout); From 268374bdcd72af5aaa5114744254d8a1f4b4c5b9 Mon Sep 17 00:00:00 2001 From: Antoine Delvaux Date: Wed, 15 Apr 2020 19:24:49 +0000 Subject: [PATCH 16/28] Succesfully tested on EX6120 to flash an OpenWRT image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d88e14..76ac92e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ nmrpflash - Netgear Unbrick Utility `nmrpflash` uses Netgear's [NMRP protocol](http://www.chubb.wattle.id.au/PeterChubb/nmrp.html) to flash a new firmware image to a compatible device. It has been successfully used on a Netgear -EX2700, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible +EX2700, EX6120, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible with many other Netgear devices. Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available From bdcb29760949b499ded36125dcf585488a0c3684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lei=C3=9F?= <5084100+sleiss@users.noreply.github.com> Date: Thu, 16 Apr 2020 21:57:27 +0200 Subject: [PATCH 17/28] nmrpflash works on EX6150v2. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d88e14..9c1b116 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ nmrpflash - Netgear Unbrick Utility `nmrpflash` uses Netgear's [NMRP protocol](http://www.chubb.wattle.id.au/PeterChubb/nmrp.html) to flash a new firmware image to a compatible device. It has been successfully used on a Netgear -EX2700, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible +EX2700, EX6150v2, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible with many other Netgear devices. Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available From 6396c33402b0072867b51e4c1b7ecb2a25814bee Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 19 Apr 2020 05:57:21 +0000 Subject: [PATCH 18/28] avoid possible use of uninitialized intf_addr in nmrp_do() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silences a warning by gcc: . nmrp.c:462:7: warning: ‘intf_addr’ may be used uninitialized in this function [-Wmaybe-uninitialized] 462 | if (ethsock_ip_add(sock, intf_addr, ipmask.s_addr, &ip_undo) != 0) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- nmrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nmrp.c b/nmrp.c index 4f262d9..079271a 100644 --- a/nmrp.c +++ b/nmrp.c @@ -360,7 +360,7 @@ int nmrp_do(struct nmrpd_args *args) struct ethsock *sock; struct ethsock_ip_undo *ip_undo = NULL; struct ethsock_arp_undo *arp_undo = NULL; - uint32_t intf_addr; + uint32_t intf_addr = 0; void (*sigh_orig)(int); struct in_addr ipaddr; struct in_addr ipmask; From 9f1a6027b44ed6b359ae581e24ddc2daa8e45400 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 19 Apr 2020 06:07:13 +0000 Subject: [PATCH 19/28] support compiling outside git checkout When building nmrpflash for Debian, there is no 'git' command available, and there is no '.git' directory either. This makes the build emit warnings from the $(shell) calls in VERSION variable in the Makefile and breaks the '-V' option. The change in this patch accounts for missing 'git' command and resorts to using a STANDALONE_VERSION environment variable which in turn is provided by the package build mechanics. This change has no effect when the git command is available and the '.git' directory is present. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 797aaac..04ad2d5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC ?= gcc PREFIX ?= /usr/local -VERSION = $(shell git describe --always | tail -c +2) +VERSION := $(shell if [ -d .git ] && which git 2>&1 > /dev/null; then git describe --always | tail -c +2; else echo $$STANDALONE_VERSION; fi) LIBS = -lpcap CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\" LDFLAGS += $(LIBS) From 1679444dceb2fb9b299463699e344a79d3e984a3 Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Sun, 10 May 2020 07:13:35 +0000 Subject: [PATCH 20/28] Improve cross-building by honoring PKG_CONFIG from environment This is in response to Debian bug #960165 by Helmut Grohne. When cross-building, another pkg-config is used that accounts for the target architecture. The patch makes it possible to supply that via the PKG_CONFIG environment variable and defaults to 'pkg-config' so no such variable defaults to native build. --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 797aaac..640d7cd 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ CC ?= gcc +PKG_CONFIG ?= pkg-config PREFIX ?= /usr/local VERSION = $(shell git describe --always | tail -c +2) LIBS = -lpcap @@ -6,8 +7,8 @@ CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\" LDFLAGS += $(LIBS) ifeq ($(shell uname -s),Linux) - CFLAGS += $(shell pkg-config libnl-route-3.0 --cflags) - LIBS += $(shell pkg-config libnl-route-3.0 --libs) + CFLAGS += $(shell $(PKG_CONFIG) libnl-route-3.0 --cflags) + LIBS += $(shell $(PKG_CONFIG) libnl-route-3.0 --libs) endif nmrpflash_OBJ = nmrp.o tftp.o ethsock.o main.o util.o From ee88cee0c8d0234e8742ab648e6634f3f1a7af69 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 11 May 2020 16:25:22 +0200 Subject: [PATCH 21/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eafc05b..9baaa14 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ nmrpflash - Netgear Unbrick Utility `nmrpflash` uses Netgear's [NMRP protocol](http://www.chubb.wattle.id.au/PeterChubb/nmrp.html) to flash a new firmware image to a compatible device. It has been successfully used on a Netgear -EX2700, EX6120, EX6150v2, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, but is likely to be compatible +EX2700, EX6120, EX6150v2, DNG3700v2, R6220, R7000, D7000, WNR3500, R6400 and R6800, WNDR3800, but is likely to be compatible with many other Netgear devices. Prebuilt binaries for Linux, ~OS X~ macOS and Windows are available From b6cb61054be7936cc77b5390f7f920084ccea395 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 11 May 2020 16:50:10 +0200 Subject: [PATCH 22/28] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 9baaa14..4570db0 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,14 @@ By default, file transfers using TFTP are limited to `65535 * 512` bytes (almost 32 MiB). Uploading files exceeding this limit might fail, depending on the device. +###### "Ignoring extra upload request." + +Extraneous upload requests are usually sent by the device if the image validation +failed. If you downloaded a firmware that's contained in an archive (a `.zip` for +example), you must extract this file, and then use the contained firmware file +as the argument to the `-f` parameter. Some examples for file extensions used +for firmware: `.chk`, `.bin`, `.trx`, `.img`. + ### Building and installing ###### Linux, Mac OS X, BSDs From 7bbb247167f498a63dd01fdf4e131f9688ee0014 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 11 May 2020 22:23:31 +0200 Subject: [PATCH 23/28] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4570db0..d1aff05 100644 --- a/README.md +++ b/README.md @@ -193,4 +193,8 @@ project file (`nmrpflash.dev`). Download the latest and extract it into the root folder of the `nmrpflash` sources. +### Donate +Buy Me A Coffee + + From 9bb6324cd27d4c012fe10f7407078041cd8394e0 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 11 May 2020 22:49:57 +0200 Subject: [PATCH 24/28] Update README.md --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d1aff05..8362036 100644 --- a/README.md +++ b/README.md @@ -172,11 +172,22 @@ on the device. ###### "Ignoring extra upload request." Extraneous upload requests are usually sent by the device if the image validation -failed. If you downloaded a firmware that's contained in an archive (a `.zip` for +failed. Some possible causes are: + +* If you downloaded a firmware that's contained in an archive (a `.zip` for example), you must extract this file, and then use the contained firmware file as the argument to the `-f` parameter. Some examples for file extensions used for firmware: `.chk`, `.bin`, `.trx`, `.img`. +* Some devices prevent you from downgrading the firmware. See if it works with +the latest version available for your device. If you're already using the latest +version, it might be possible to patch the version info of the firmware file. A +future version of `nmrpflash` might incorporate an auto-patch feature for these +cases. + +* Your device might expect a different image format for `nmrpflash` than when +flashing via the web interface. + ### Building and installing ###### Linux, Mac OS X, BSDs From 442f74b2d67d6ef0753da0c38a1bbb6c3d032805 Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Tue, 26 May 2020 16:26:19 +0200 Subject: [PATCH 25/28] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8362036..7b129fa 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,8 @@ and extract it into the root folder of the `nmrpflash` sources. ### Donate -Buy Me A Coffee - +You can [buy me a coffee](https://www.buymeacoffee.com/jclehner) if you want, but please consider +donating the money for charity instead - [Médecins Sans Frontiers](https://www.msf.org/donate) comes to mind, +but any other organization, local or international, that you think deserves support will do. Thank you! From 8a26cdf4b1e37bf10dd4a0d68cdc55b0e468f943 Mon Sep 17 00:00:00 2001 From: Benjamin Joseph Date: Sat, 4 Jul 2020 10:26:24 -0700 Subject: [PATCH 26/28] Updated documentation. From painful experiences and eventual success success. --- README-R7000.md | 33 +++++++++++++++++++++++++++++++++ README.md | 17 +++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 README-R7000.md diff --git a/README-R7000.md b/README-R7000.md new file mode 100644 index 0000000..9c6ef3c --- /dev/null +++ b/README-R7000.md @@ -0,0 +1,33 @@ +Some helpful hints for putting firmware on the Netgear R7000 +============================================================ + +* As of the writing of this, July 2020, the R7000's web interface does not let you downgrade its firmware, or run 3rd party firmware on it. +* Older versions of the R7000's firmware do allow you to flash 3rd party firmware. +* You can use nrmpflash to downgrade router's firmware, for example R7000-V1.0.3.56_1.1.25. + +Here is an example set of steps +1. Plug in your router, go through the regular stock web interface setup. Note if the router's IP address is now 192.168.1.1 or 10.0.0.1 +2. Connect computer your computer to LAN1 with an ethernet cable +3. At the command prompt on your computer, run: +`sudo nmrpflash -v -i YOUR_ADAPTER_NAME -f R7000-V1.0.3.56_1.1.25.chk -t 10000 -T 10000 -A 10.0.0.2 -a 10.0.0.1` +* Note 1: The instructions from README.md that tell you how to find YOUR_ADAPTER_NAME. +* Note 2: if your router's IP address was 192.168.1.1 then swap out 10.0.0.x with 192.168.1.x for the two IP addresses above +4. Right after running the command, power on your router. Your router checks for the nmrpflash server on boot. If all goes well you should see this: + +``` +sudo nmrpflash -v -i enp0s25 -f R7000-V1.0.3.56_1.1.25.chk -t 10000 -T 10000 -A 10.0.0.2 -a 10.0.0.1 +Adding 10.0.0.2 to interface enp0s25. +Advertising NMRP server on enp0s25 ... / +Received configuration request from ab:cd:ef:12:34:56. +Sending configuration: 10.0.0.1/24. +Received upload request without filename. +Using remote filename 'R7000-V1.0.3.56_1.1.25.chk'. +Uploading R7000-V1.0.3.56_1.1.25.chk ... OK +Waiting for remote to respond. +Received keep-alive request (19). +Remote finished. Closing connection. +Reboot your device now. + +``` +5. Reboot the device. You now have old firwmare, congratulations. + diff --git a/README.md b/README.md index 7b129fa..992d5d8 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,11 @@ Your Netgear router must be connected to your network using an Ethernet cable. The device running `nmrpflash` must be connected to the same network, using either Wi-Fi or Ethernet. +Usage sequence of events: +1. Connect ethernet cable from computer to router's LAN1 +2. Run nmrpflash on command line +3. Turn on the router. + All available network interfaces can be listed using ``` @@ -188,6 +193,18 @@ cases. * Your device might expect a different image format for `nmrpflash` than when flashing via the web interface. +###### "bind: Cannot assign requested address" + +* Specify the address of the router, and address of your computer. For example: + +-A 10.0.0.2 -a 10.0.0.1 + +or + +-A 192.168.1.2 -a 192.168.1.1 + + + ### Building and installing ###### Linux, Mac OS X, BSDs From a79d40534027c895762644928829951b0f7a5f8d Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 6 Jul 2020 11:27:04 +0200 Subject: [PATCH 27/28] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 992d5d8..1c68596 100644 --- a/README.md +++ b/README.md @@ -195,15 +195,14 @@ flashing via the web interface. ###### "bind: Cannot assign requested address" -* Specify the address of the router, and address of your computer. For example: +Specify the address of the router, and address of your computer, using +`-A` and `-a`. For example: --A 10.0.0.2 -a 10.0.0.1 +`-A 10.0.0.2 -a 10.0.0.1` or --A 192.168.1.2 -a 192.168.1.1 - - +`-A 192.168.1.2 -a 192.168.1.1` ### Building and installing ###### Linux, Mac OS X, BSDs From 913f261a0c87b69ab9499305a9d3c3c31ee93f3d Mon Sep 17 00:00:00 2001 From: "Joseph C. Lehner" Date: Mon, 6 Jul 2020 11:28:30 +0200 Subject: [PATCH 28/28] Update README.md --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1c68596..c16efc3 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,10 @@ Ethernet cable. The device running `nmrpflash` must be connected to the same network, using either Wi-Fi or Ethernet. Usage sequence of events: -1. Connect ethernet cable from computer to router's LAN1 -2. Run nmrpflash on command line -3. Turn on the router. +1. Turn off the router +2. Connect ethernet cable from computer to router's LAN1 +3. Run nmrpflash on command line +4. Turn on the router. All available network interfaces can be listed using @@ -99,12 +100,8 @@ C:\> net start npf ###### "No response after 60 seconds. Bailing out." -The router did not respond. Always run `nmrpflash` in the following -manner: - -* Turn off the router. -* Run `nmrpflash`. -* Turn on the router. +The router did not respond. Always run `nmrpflash` in the sequence +described above! If that still doesn't work, you can try "blind mode", which can be invoked using `-B`. Note that you also have to specify your router's