Merge branches
This commit is contained in:
commit
bc6007beb7
8 changed files with 295 additions and 131 deletions
2
Makefile
2
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
|
||||
|
|
70
README.md
70
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 <ipaddr> IP address to assign to target device
|
||||
-c <command> Command to run before (or instead of) TFTP upload
|
||||
-f <firmware> Firmware file
|
||||
-F <filename> Remote filename to use during TFTP upload
|
||||
-i <interface> Network interface directly connected to device
|
||||
-m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)
|
||||
-M <netmask> Subnet mask to assign to target device
|
||||
-t <timeout> Timeout (in milliseconds) for regular messages
|
||||
-T <timeout> Time to wait after successfull TFTP upload
|
||||
-T <timeout> Time (seconds) to wait after successfull TFTP upload
|
||||
-p <port> Port to use for TFTP upload
|
||||
-U Test TFTP upload
|
||||
-R <region> 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 <interface> <ip> <mac>`
|
||||
|
||||
where `<interface>` is the pretty interface name (e.g. "Local Area Connection"; as displayed by
|
||||
`nmrpflash -L`), `<ip>` is the same IP address you'd use for `nmrpflash`'s `-a` flag, and `<mac>`
|
||||
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 <interface> <ip>'` 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
|
||||
|
||||
|
|
70
ethsock.c
70
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)
|
||||
|
|
14
main.c
14
main.c
|
@ -23,6 +23,8 @@
|
|||
#include <stdio.h>
|
||||
#include "nmrpd.h"
|
||||
|
||||
#define NMRPFLASH_SET_REGION
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
void usage(FILE *fp)
|
||||
|
@ -42,7 +44,7 @@ void usage(FILE *fp)
|
|||
" -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
|
||||
" -p <port> Port to use for TFTP upload\n"
|
||||
#ifdef NMRPFLASH_SET_REGION
|
||||
" -R <region> Set device region\n"
|
||||
" -R <region> 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;
|
||||
|
|
219
nmrp.c
219
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;
|
||||
}
|
||||
|
|
6
nmrpd.h
6
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
|
||||
|
|
|
@ -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
|
||||
|
|
43
tftp.c
43
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue