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
|
install -m 755 nmrpflash $(PREFIX)/bin
|
||||||
|
|
||||||
release/osx:
|
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
|
zip nmrpflash-osx.zip nmrpflash
|
||||||
|
|
||||||
release/linux: release
|
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)
|
[here](https://github.com/jclehner/nmrpflash/releases)
|
||||||
([WinPcap](https://www.winpcap.org/install/default.htm) is required on Windows).
|
([WinPcap](https://www.winpcap.org/install/default.htm) is required on Windows).
|
||||||
|
|
||||||
````
|
```
|
||||||
Usage: nmrpflash [OPTIONS...]
|
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
|
-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 <firmware> Firmware file
|
||||||
|
-F <filename> Remote filename to use during TFTP upload
|
||||||
-i <interface> Network interface directly connected to device
|
-i <interface> Network interface directly connected to device
|
||||||
-m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)
|
-m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)
|
||||||
-M <netmask> Subnet mask to assign to target device
|
-M <netmask> Subnet mask to assign to target device
|
||||||
-t <timeout> Timeout (in milliseconds) for regular messages
|
-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
|
-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 Be verbose
|
||||||
-V Print version and exit
|
-V Print version and exit
|
||||||
-L List network interfaces
|
-L List network interfaces
|
||||||
-h Show this screen
|
-h Show this screen
|
||||||
````
|
```
|
||||||
|
|
||||||
### Using nmrpflash
|
### 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
|
In this example, we'll use `192.168.1.2`. All available network interfaces
|
||||||
can be listed using
|
can be listed using
|
||||||
|
|
||||||
````
|
```
|
||||||
$ nmrpflash -L
|
$ nmrpflash -L
|
||||||
eth0 192.168.1.2 f2:11:a1:02:03:b1
|
eth0 192.168.1.2 f2:11:a1:02:03:b1
|
||||||
````
|
```
|
||||||
|
|
||||||
Now we can `nmrpflash`. The argument for the `-a` option needs
|
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
|
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
|
[here](#obtaining-firmware-images). Power on your device immediately
|
||||||
after starting `nmrpflash`.
|
after starting `nmrpflash`.
|
||||||
|
|
||||||
````
|
```
|
||||||
$ nmrpflash -i eth0 -a 192.168.1.254 -f EX2700-V1.0.1.8.img
|
$ nmrpflash -i eth0 -a 192.168.1.254 -f EX2700-V1.0.1.8.img
|
||||||
Advertising NMRP server on eth0 ... /
|
Advertising NMRP server on eth0 ... /
|
||||||
Received configuration request from a4:2b:8c:00:00:01.
|
Received configuration request from a4:2b:8c:00:00:01.
|
||||||
Sending configuration: ip 192.168.1.254, mask 255.255.255.0.
|
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
|
Uploading EX2700-V1.0.1.8.img ... OK
|
||||||
Waiting for remote to respond.
|
Waiting for remote to respond.
|
||||||
Remote finished. Closing connection.
|
Remote finished. Closing connection.
|
||||||
````
|
Reboot your device now.
|
||||||
|
```
|
||||||
|
|
||||||
### Common issues
|
### Common issues
|
||||||
###### "No suitable network interfaces found."
|
###### "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
|
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.
|
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
|
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
|
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
|
It's entirely possible that the image was flashed successfully, but the
|
||||||
operation took longer than 120 seconds.
|
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
|
### Building and installing
|
||||||
###### Linux, Mac OS X, BSDs
|
###### Linux, Mac OS X, BSDs
|
||||||
|
|
||||||
````
|
```
|
||||||
$ make && sudo make install
|
$ make && sudo make install
|
||||||
````
|
```
|
||||||
|
|
||||||
###### Windows
|
###### Windows
|
||||||
|
|
||||||
|
|
70
ethsock.c
70
ethsock.c
|
@ -29,6 +29,7 @@ struct ethsock
|
||||||
int fd;
|
int fd;
|
||||||
#else
|
#else
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
|
DWORD index;
|
||||||
#endif
|
#endif
|
||||||
unsigned timeout;
|
unsigned timeout;
|
||||||
uint8_t hwaddr[6];
|
uint8_t hwaddr[6];
|
||||||
|
@ -75,7 +76,7 @@ static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
|
||||||
return true;
|
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;
|
struct ifaddrs *ifas, *ifa;
|
||||||
bool found;
|
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;
|
PIP_ADAPTER_INFO adapters, adapter;
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
@ -147,10 +148,10 @@ static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr)
|
||||||
* AdapterName from GetAdaptersInfo is just "{GUID}".*/
|
* AdapterName from GetAdaptersInfo is just "{GUID}".*/
|
||||||
if (strstr(intf, adapter->AdapterName)) {
|
if (strstr(intf, adapter->AdapterName)) {
|
||||||
if (adapter->AddressLength == 6) {
|
if (adapter->AddressLength == 6) {
|
||||||
for (i = 0; i != 6; ++i) {
|
memcpy(hwaddr, adapter->Address, 6);
|
||||||
hwaddr[i] = adapter->Address[i];
|
if (index) {
|
||||||
|
*index = adapter->Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -289,8 +290,13 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
|
||||||
goto cleanup_pcap;
|
goto cleanup_pcap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_hwaddr_from_intf(intf, sock->hwaddr)) {
|
#ifndef NMRPFLASH_WINDOWS
|
||||||
fprintf(stderr, "Failed to get MAC address of interface.\n");
|
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;
|
goto cleanup_malloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,6 +442,54 @@ inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
|
||||||
return 0;
|
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)
|
static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
|
||||||
{
|
{
|
||||||
#ifndef NMRPFLASH_WINDOWS
|
#ifndef NMRPFLASH_WINDOWS
|
||||||
|
@ -458,7 +512,7 @@ static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return get_hwaddr_from_intf(dev->name, hwaddr);
|
return get_intf_info(dev->name, hwaddr, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ethsock_list_all(void)
|
int ethsock_list_all(void)
|
||||||
|
|
14
main.c
14
main.c
|
@ -23,6 +23,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "nmrpd.h"
|
#include "nmrpd.h"
|
||||||
|
|
||||||
|
#define NMRPFLASH_SET_REGION
|
||||||
|
|
||||||
int verbosity = 0;
|
int verbosity = 0;
|
||||||
|
|
||||||
void usage(FILE *fp)
|
void usage(FILE *fp)
|
||||||
|
@ -42,7 +44,7 @@ void usage(FILE *fp)
|
||||||
" -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
|
" -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
|
||||||
" -p <port> Port to use for TFTP upload\n"
|
" -p <port> Port to use for TFTP upload\n"
|
||||||
#ifdef NMRPFLASH_SET_REGION
|
#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
|
#endif
|
||||||
#ifdef NMRPFLASH_TFTP_TEST
|
#ifdef NMRPFLASH_TFTP_TEST
|
||||||
" -U Test TFTP upload\n"
|
" -U Test TFTP upload\n"
|
||||||
|
@ -83,7 +85,7 @@ int main(int argc, char **argv)
|
||||||
.mac = "ff:ff:ff:ff:ff:ff",
|
.mac = "ff:ff:ff:ff:ff:ff",
|
||||||
.op = NMRP_UPLOAD_FW,
|
.op = NMRP_UPLOAD_FW,
|
||||||
.port = 69,
|
.port = 69,
|
||||||
.force_root = 1
|
.region = NULL,
|
||||||
};
|
};
|
||||||
#ifdef NMRPFLASH_WINDOWS
|
#ifdef NMRPFLASH_WINDOWS
|
||||||
WSADATA wsa;
|
WSADATA wsa;
|
||||||
|
@ -121,16 +123,16 @@ int main(int argc, char **argv)
|
||||||
case 'M':
|
case 'M':
|
||||||
args.ipmask = optarg;
|
args.ipmask = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
#ifdef NMRPFLASH_SET_REGION
|
#ifdef NMRPFLASH_SET_REGION
|
||||||
case 'R':
|
case 'R':
|
||||||
|
args.region = optarg;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case 'p':
|
||||||
case 'T':
|
case 'T':
|
||||||
case 't':
|
case 't':
|
||||||
if (c == 'p') {
|
if (c == 'p') {
|
||||||
max = 0xffff;
|
max = 0xffff;
|
||||||
} else if (c == 'R') {
|
|
||||||
max = 0x0009;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val = atoi(optarg);
|
val = atoi(optarg);
|
||||||
|
@ -145,8 +147,6 @@ int main(int argc, char **argv)
|
||||||
args.rx_timeout = val;
|
args.rx_timeout = val;
|
||||||
} else if (c == 'T') {
|
} else if (c == 'T') {
|
||||||
args.ul_timeout = val * 1000;
|
args.ul_timeout = val * 1000;
|
||||||
} else if (c == 'R') {
|
|
||||||
args.region = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
219
nmrp.c
219
nmrp.c
|
@ -27,11 +27,13 @@
|
||||||
#include "nmrpd.h"
|
#include "nmrpd.h"
|
||||||
|
|
||||||
#define NMRP_HDR_LEN 6
|
#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_MIN_PKT_LEN (sizeof(struct eth_hdr) + NMRP_HDR_LEN)
|
||||||
|
|
||||||
#define NMRP_MAX_OPT_SIZE 12
|
#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 ETH_P_NMRP 0x0912
|
||||||
#define IP_LEN 4
|
#define IP_LEN 4
|
||||||
|
@ -80,7 +82,9 @@ struct nmrp_msg {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint16_t len;
|
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;
|
uint32_t num_opts;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
@ -116,13 +120,20 @@ static const char *msg_code_str(uint16_t code)
|
||||||
#undef CASE_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;
|
#define REGION_CODE(r, c) if (!strcasecmp(region, r)) return c
|
||||||
msg->len = NMRP_HDR_LEN;
|
REGION_CODE("NA", 0x0001);
|
||||||
for (; i != msg->num_opts; ++i) {
|
REGION_CODE("WW", 0x0002);
|
||||||
msg->len += msg->opts[i].len;
|
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)
|
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) {
|
while (remain_len > 0) {
|
||||||
len = opt->len;
|
len = opt->len;
|
||||||
fprintf(stderr, " opt type=%u, len=%u", opt->type, len);
|
fprintf(stderr, " opt type=%u, len=%u", opt->type, len);
|
||||||
for (i = 0; i != len - NMRP_OPT_LEN; ++i) {
|
if (len) {
|
||||||
if (!(i % 16)) {
|
for (i = 0; i != len - NMRP_OPT_HDR_LEN; ++i) {
|
||||||
fprintf(stderr, "\n ");
|
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;
|
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)
|
static void msg_hton(struct nmrp_msg *msg)
|
||||||
{
|
{
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
struct nmrp_opt *opt = msg->opts, *next;
|
||||||
|
|
||||||
msg->reserved = htons(msg->reserved);
|
msg->reserved = htons(msg->reserved);
|
||||||
msg->len = htons(msg->len);
|
msg->len = htons(msg->len);
|
||||||
|
|
||||||
for (; i != msg->num_opts; ++i) {
|
for (; i != msg->num_opts; ++i) {
|
||||||
msg->opts[i].len = htons(msg->opts[i].len);
|
next = NMRP_OPT_NEXT(opt);
|
||||||
msg->opts[i].type = htons(msg->opts[i].type);
|
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
|
// size is 12
|
||||||
if (remaining < NMRP_MAX_OPT_NUM * NMRP_MAX_OPT_SIZE) {
|
if (remaining < NMRP_MAX_OPT_NUM * NMRP_MAX_OPT_SIZE) {
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
if (remaining < NMRP_OPT_LEN) {
|
if (remaining < NMRP_OPT_HDR_LEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +214,7 @@ static int msg_ntoh(struct nmrp_msg *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining -= opt->len;
|
remaining -= opt->len;
|
||||||
++opt;
|
opt = NMRP_OPT_NEXT(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remaining) {
|
if (!remaining) {
|
||||||
|
@ -211,7 +227,7 @@ static int msg_ntoh(struct nmrp_msg *msg)
|
||||||
return 1;
|
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];
|
static char buf[128];
|
||||||
struct nmrp_opt *opt = msg->opts;
|
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) {
|
while (remaining > 0) {
|
||||||
if (opt->type == type) {
|
if (opt->type == type) {
|
||||||
if (opt->len == NMRP_OPT_LEN) {
|
if (opt->len == NMRP_OPT_HDR_LEN) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*len = opt->len - NMRP_OPT_LEN;
|
*len = opt->len - NMRP_OPT_HDR_LEN;
|
||||||
memcpy(buf, &opt->val, MIN(*len, sizeof(buf)-1));
|
memcpy(buf, &opt->val, MIN(*len, sizeof(buf)-1));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining -= opt->len;
|
remaining -= opt->len;
|
||||||
opt = (struct nmrp_opt*)((char*)opt) + opt->len;
|
opt = NMRP_OPT_NEXT(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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)
|
static int pkt_send(struct ethsock *sock, struct nmrp_pkt *pkt)
|
||||||
{
|
{
|
||||||
size_t len = ntohs(pkt->msg.len) + sizeof(pkt->eh);
|
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 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)
|
static void sigh(int sig)
|
||||||
{
|
{
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (gsock) {
|
if (gsock) {
|
||||||
|
if (garp) {
|
||||||
|
ethsock_arp_del(gsock, arpmac, &arpip);
|
||||||
|
}
|
||||||
ethsock_close(gsock);
|
ethsock_close(gsock);
|
||||||
|
gsock = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -345,13 +401,16 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
{
|
{
|
||||||
struct nmrp_pkt tx, rx;
|
struct nmrp_pkt tx, rx;
|
||||||
uint8_t *src, dest[6];
|
uint8_t *src, dest[6];
|
||||||
uint16_t len;
|
uint16_t len, region;
|
||||||
char *filename;
|
char *filename;
|
||||||
struct in_addr ipaddr, ipmask;
|
|
||||||
time_t beg;
|
time_t beg;
|
||||||
int i, status, ulreqs, expect;
|
int i, status, ulreqs, expect, upload_ok;
|
||||||
struct ethsock *sock;
|
struct ethsock *sock;
|
||||||
void (*sigh_orig)(int);
|
void (*sigh_orig)(int);
|
||||||
|
struct {
|
||||||
|
struct in_addr addr;
|
||||||
|
struct in_addr mask;
|
||||||
|
} PACKED ipconf;
|
||||||
|
|
||||||
if (args->op != NMRP_UPLOAD_FW) {
|
if (args->op != NMRP_UPLOAD_FW) {
|
||||||
fprintf(stderr, "Operation not implemented.\n");
|
fprintf(stderr, "Operation not implemented.\n");
|
||||||
|
@ -363,17 +422,17 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
return 1;
|
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);
|
fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
|
||||||
return 1;
|
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);
|
fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
|
||||||
return 1;
|
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);
|
fprintf(stderr, "Error accessing file '%s'.\n", args->file_local);
|
||||||
return 1;
|
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;
|
status = 1;
|
||||||
|
|
||||||
sock = ethsock_create(args->intf, ETH_P_NMRP);
|
sock = ethsock_create(args->intf, ETH_P_NMRP);
|
||||||
|
@ -393,8 +462,6 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sigh_orig = signal(SIGINT, sigh);
|
|
||||||
|
|
||||||
status = is_valid_ip(sock, &ipaddr, &ipmask);
|
status = is_valid_ip(sock, &ipaddr, &ipmask);
|
||||||
if (status <= 0) {
|
if (status <= 0) {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
|
@ -405,6 +472,8 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
gsock = sock;
|
gsock = sock;
|
||||||
|
garp = 0;
|
||||||
|
sigh_orig = signal(SIGINT, sigh);
|
||||||
|
|
||||||
if (ethsock_set_timeout(sock, args->rx_timeout)) {
|
if (ethsock_set_timeout(sock, args->rx_timeout)) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -419,21 +488,12 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
memcpy(tx.eh.ether_dhost, dest, 6);
|
memcpy(tx.eh.ether_dhost, dest, 6);
|
||||||
tx.eh.ether_type = htons(ETH_P_NMRP);
|
tx.eh.ether_type = htons(ETH_P_NMRP);
|
||||||
|
|
||||||
tx.msg.reserved = 0;
|
msg_init(&tx.msg, NMRP_C_ADVERTISE);
|
||||||
tx.msg.code = NMRP_C_ADVERTISE;
|
msg_opt_add(&tx.msg, NMRP_O_MAGIC_NO, "NTGR", 4);
|
||||||
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_hton(&tx.msg);
|
msg_hton(&tx.msg);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
upload_ok = 0;
|
||||||
beg = time(NULL);
|
beg = time(NULL);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -472,11 +532,7 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
msg_code_str(rx.msg.code), msg_code_str(expect));
|
msg_code_str(rx.msg.code), msg_code_str(expect));
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.msg.code = NMRP_C_NONE;
|
msg_init(&tx.msg, NMRP_C_NONE);
|
||||||
tx.msg.reserved = 0;
|
|
||||||
tx.msg.id = 0;
|
|
||||||
tx.msg.num_opts = 0;
|
|
||||||
tx.msg.len = 0;
|
|
||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
||||||
|
@ -488,23 +544,14 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
goto out;
|
goto out;
|
||||||
case NMRP_C_CONF_REQ:
|
case NMRP_C_CONF_REQ:
|
||||||
tx.msg.code = NMRP_C_CONF_ACK;
|
tx.msg.code = NMRP_C_CONF_ACK;
|
||||||
tx.msg.num_opts = 2;
|
|
||||||
|
|
||||||
tx.msg.opts[0].type = NMRP_O_DEV_IP;
|
msg_opt_add(&tx.msg, NMRP_O_DEV_IP, &ipconf, 8);
|
||||||
tx.msg.opts[0].len = NMRP_OPT_LEN + 2 * 4;
|
msg_opt_add(&tx.msg, NMRP_O_FW_UP, NULL, 0);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
#ifdef NMRPFLASH_SET_REGION
|
#ifdef NMRPFLASH_SET_REGION
|
||||||
tx.msg.num_opts = 3;
|
if (region) {
|
||||||
|
msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, ®ion, 2);
|
||||||
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;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
expect = NMRP_C_TFTP_UL_REQ;
|
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",
|
printf("Sending configuration: ip %s, mask %s.\n",
|
||||||
args->ipaddr, args->ipmask);
|
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;
|
break;
|
||||||
case NMRP_C_TFTP_UL_REQ:
|
case NMRP_C_TFTP_UL_REQ:
|
||||||
if (++ulreqs > 5) {
|
if (!upload_ok) {
|
||||||
fprintf(stderr, "Device re-requested file upload %d "
|
if (++ulreqs > 5) {
|
||||||
"times; aborting.\n", ulreqs);
|
printf("Bailing out after %d upload requests.\n",
|
||||||
tx.msg.code = NMRP_C_CLOSE_REQ;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,12 +600,8 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
printf("Received upload request: filename '%.*s'.\n",
|
printf("Received upload request: filename '%.*s'.\n",
|
||||||
len, filename);
|
len, filename);
|
||||||
} else if (!args->file_remote) {
|
} else if (!args->file_remote) {
|
||||||
if (tftp_is_valid_filename(args->file_local)) {
|
args->file_remote = args->file_local;
|
||||||
args->file_remote = args->file_local;
|
printf("Received upload request with empty filename.\n");
|
||||||
} else {
|
|
||||||
args->file_remote = "firmware";
|
|
||||||
}
|
|
||||||
printf("Received upload request with empty filename.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
|
@ -557,7 +618,7 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!status && args->file_local) {
|
if (!status && args->file_local) {
|
||||||
status = is_valid_ip(sock, &ipaddr, &ipmask);
|
status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
} else if (!status) {
|
} else if (!status) {
|
||||||
|
@ -575,7 +636,7 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
if (!strcmp(args->file_local, "-")) {
|
if (!strcmp(args->file_local, "-")) {
|
||||||
printf("Uploading from stdin ... ");
|
printf("Uploading from stdin ... ");
|
||||||
} else {
|
} else {
|
||||||
printf("Uploading %s ... ", args->file_local);
|
printf("Uploading %s ... ", leafname(args->file_local));
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
status = tftp_put(args);
|
status = tftp_put(args);
|
||||||
|
@ -583,7 +644,9 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
printf("OK\nWaiting for remote to respond.\n");
|
printf("OK\nWaiting for remote to respond.\n");
|
||||||
|
upload_ok = 1;
|
||||||
ethsock_set_timeout(sock, args->ul_timeout);
|
ethsock_set_timeout(sock, args->ul_timeout);
|
||||||
|
tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
|
||||||
expect = NMRP_C_NONE;
|
expect = NMRP_C_NONE;
|
||||||
} else if (status == -2) {
|
} else if (status == -2) {
|
||||||
expect = NMRP_C_TFTP_UL_REQ;
|
expect = NMRP_C_TFTP_UL_REQ;
|
||||||
|
@ -610,13 +673,16 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.msg.code != NMRP_C_NONE) {
|
if (tx.msg.code != NMRP_C_NONE) {
|
||||||
msg_update_len(&tx.msg);
|
|
||||||
msg_hton(&tx.msg);
|
msg_hton(&tx.msg);
|
||||||
|
|
||||||
if (pkt_send(sock, &tx) < 0) {
|
if (pkt_send(sock, &tx) < 0) {
|
||||||
perror("sendto");
|
perror("sendto");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tx.msg.code == NMRP_C_CLOSE_REQ) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx.msg.code == NMRP_C_CLOSE_REQ) {
|
if (rx.msg.code == NMRP_C_CLOSE_REQ) {
|
||||||
|
@ -648,6 +714,7 @@ int nmrp_do(struct nmrpd_args *args)
|
||||||
out:
|
out:
|
||||||
signal(SIGINT, sigh_orig);
|
signal(SIGINT, sigh_orig);
|
||||||
gsock = NULL;
|
gsock = NULL;
|
||||||
|
ethsock_arp_del(sock, arpmac, &arpip);
|
||||||
ethsock_close(sock);
|
ethsock_close(sock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
6
nmrpd.h
6
nmrpd.h
|
@ -71,10 +71,10 @@ struct nmrpd_args {
|
||||||
const char *mac;
|
const char *mac;
|
||||||
enum nmrp_op op;
|
enum nmrp_op op;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
uint16_t region;
|
const char *region;
|
||||||
int force_root;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *leafname(const char *path);
|
||||||
int tftp_put(struct nmrpd_args *args);
|
int tftp_put(struct nmrpd_args *args);
|
||||||
bool tftp_is_valid_filename(const char *filename);
|
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);
|
ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len);
|
||||||
int ethsock_set_timeout(struct ethsock *sock, unsigned msec);
|
int ethsock_set_timeout(struct ethsock *sock, unsigned msec);
|
||||||
uint8_t *ethsock_get_hwaddr(struct ethsock *sock);
|
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);
|
int ethsock_list_all(void);
|
||||||
|
|
||||||
struct ethsock_ip_callback_args
|
struct ethsock_ip_callback_args
|
||||||
|
|
|
@ -9,7 +9,7 @@ Libs=Wpdpack\Lib
|
||||||
PrivateResource=
|
PrivateResource=
|
||||||
ResourceIncludes=
|
ResourceIncludes=
|
||||||
MakeIncludes=
|
MakeIncludes=
|
||||||
Compiler=-DNMRPFLASH_VERSION=\"0.9.2\"_@@_
|
Compiler=-DNMRPFLASH_VERSION=\"0.9.3\"_@@_
|
||||||
CppCompiler=
|
CppCompiler=
|
||||||
Linker=-liphlpapi_@@_-lws2_32_@@_-ladvapi32_@@_-lwpcap_@@_-lpacket_@@__@@_
|
Linker=-liphlpapi_@@_-lws2_32_@@_-ladvapi32_@@_-lwpcap_@@_-lpacket_@@__@@_
|
||||||
IsCpp=0
|
IsCpp=0
|
||||||
|
|
43
tftp.c
43
tftp.c
|
@ -40,24 +40,6 @@ enum tftp_opcode {
|
||||||
ERR = 5
|
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)
|
static bool is_netascii(const char *str)
|
||||||
{
|
{
|
||||||
uint8_t *p = (uint8_t*)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;
|
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
|
#ifdef NMRPFLASH_WINDOWS
|
||||||
void sock_perror(const char *msg)
|
void sock_perror(const char *msg)
|
||||||
{
|
{
|
||||||
win_perror2(msg, WSAGetLastError());
|
win_perror2(msg, WSAGetLastError());
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
inline void sock_perror(const char *msg)
|
|
||||||
{
|
|
||||||
perror(msg);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline bool tftp_is_valid_filename(const char *filename)
|
inline bool tftp_is_valid_filename(const char *filename)
|
||||||
|
@ -322,7 +317,7 @@ int tftp_put(struct nmrpd_args *args)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (!ret) {
|
} else if (!ret) {
|
||||||
if (++timeout < 5) {
|
if (++timeout < 5 || (!block && timeout < 10)) {
|
||||||
continue;
|
continue;
|
||||||
} else if (block) {
|
} else if (block) {
|
||||||
fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
|
fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
|
||||||
|
|
Loading…
Add table
Reference in a new issue