Merge branches

This commit is contained in:
Joseph C. Lehner 2016-08-09 17:16:21 +02:00
commit bc6007beb7
8 changed files with 295 additions and 131 deletions

View file

@ -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

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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, &region, 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;
}

View file

@ -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

View file

@ -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
View file

@ -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);