diff --git a/ethsock.c b/ethsock.c index 3f48e4c..615352a 100644 --- a/ethsock.c +++ b/ethsock.c @@ -1325,6 +1325,8 @@ static int ethsock_ip_add_del(struct ethsock *sock, uint32_t ipaddr, uint32_t ip (*undo)->ip[0] = ipaddr; (*undo)->ip[1] = ipmask; + } else if (!add && (!undo || !*undo)) { + return 0; } ret = -1; diff --git a/main.c b/main.c index 33292a8..b5c4e48 100644 --- a/main.c +++ b/main.c @@ -29,7 +29,7 @@ void usage(FILE *fp) fprintf(fp, "Usage: nmrpflash [OPTIONS...]\n" "\n" - "Options (-i, and -f or -c are mandatory):\n" + "Options (-i, and either -f, -c, or -R are mandatory):\n" " -a IP address to assign to target device [%s]\n" " -A IP address to assign to selected interface [%s]\n" " -B Blind mode (don't wait for response packets)\n" @@ -42,9 +42,7 @@ void usage(FILE *fp) " -t Timeout (in milliseconds) for NMRP packets [%d ms]\n" " -T Time (seconds) to wait after successfull TFTP upload [%d s]\n" " -p Port to use for TFTP upload [%d]\n" -#ifdef NMRPFLASH_SET_REGION - " -R Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)\n" -#endif + " -R Set device region (BZ, GR, IN, JP, KO, NA, PR, RU, WW)\n" " -S Skip bytes of the firmware file\n" #ifdef NMRPFLASH_TFTP_TEST " -U Test TFTP upload\n" @@ -63,15 +61,19 @@ void usage(FILE *fp) ")\n\n" #ifndef NMRPFLASH_WINDOWS "# nmrpflash -i eth0 -f firmware.bin\n" + "\nor\n\n" + "# nmrpflash -i eth0 -R WW\n" #else "C:\\> nmrpflash.exe -i net0 -f firmware.bin\n" + "\nor\n\n" + "C:\\> nmrpflash.exe -i net0 -R WW\n" #endif "\n" "When using -c, the environment variables IP, PORT, NETMASK\n" "and MAC are set to the device IP address, TFTP port, subnet\n" "mask and MAC address, respectively.\n" "\n" - "nmrpflash %s, Copyright (C) 2016-2023 Joseph C. Lehner\n" + "nmrpflash %s, Copyright (C) 2016-2024 Joseph C. Lehner\n" "nmrpflash is free software, licensed under the GNU GPLv3.\n" "Source code at https://github.com/jclehner/nmrpflash\n" "\n" @@ -151,7 +153,7 @@ int main(int argc, char **argv) .ipmask = NMRP_DEFAULT_SUBNET, .intf = NULL, .mac = "ff:ff:ff:ff:ff:ff", - .op = NMRP_UPLOAD_FW, + .op = -1, .port = NMRP_DEFAULT_TFTP_PORT, .region = NULL, .blind = false, @@ -227,11 +229,9 @@ int main(int argc, char **argv) case 'M': args.ipmask = optarg; break; -#ifdef NMRPFLASH_SET_REGION case 'R': args.region = optarg; break; -#endif case 'p': case 'S': case 'T': @@ -297,9 +297,17 @@ int main(int argc, char **argv) } #ifndef NMRPFLASH_FUZZ - if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf)) { - usage(stderr); - return 1; + if (!list) { + if (args.file_local || args.tftpcmd) { + args.op = NMRP_UPLOAD_FW; + } else if (args.region) { + args.op = NMRP_SET_REGION; + } + + if (args.op == -1 || !args.intf) { + usage(stderr); + return 1; + } } if (!list) { diff --git a/nmrp.c b/nmrp.c index 95416ea..fb58871 100644 --- a/nmrp.c +++ b/nmrp.c @@ -212,20 +212,21 @@ static void msg_mkadvertise(struct nmrp_msg *msg, const char *magic) msg_mkopt(msg, msg->opts, NMRP_O_MAGIC_NO, magic, strlen(magic)); } -static void msg_mkconfack(struct nmrp_msg *msg, uint32_t ipaddr, uint32_t ipmask, uint16_t region) +static void msg_mkconfack(struct nmrp_msg *msg, uint32_t ipaddr, uint32_t ipmask, uint16_t region, enum nmrp_op op) { - char *p; + char *p = msg->opts; uint32_t ip[2] = { ipaddr, ipmask }; msg_init(msg, NMRP_C_CONF_ACK); - p = msg_mkopt(msg, msg->opts, NMRP_O_DEV_IP, &ip, 8); - p = msg_mkopt(msg, p, NMRP_O_FW_UP, NULL, 0); -#ifdef NMRPFLASH_SET_REGION + if (op != NMRP_SET_REGION) { + p = msg_mkopt(msg, p, NMRP_O_DEV_IP, &ip, 8); + p = msg_mkopt(msg, p, NMRP_O_FW_UP, NULL, 0); + } + if (region) { p = msg_mkopt(msg, p, NMRP_O_DEV_REGION, ®ion, 2); } -#endif } #ifdef NMRPFLASH_FUZZ @@ -396,57 +397,54 @@ int nmrp_do(struct nmrpd_args *args) struct in_addr ipaddr; struct in_addr ipmask; - if (args->op != NMRP_UPLOAD_FW) { - fprintf(stderr, "Operation not implemented.\n"); - return 1; - } - - if (!mac_parse(args->mac, dest)) { - fprintf(stderr, "Invalid MAC address '%s'.\n", args->mac); - return 1; - } - - ipmask.s_addr = inet_addr(args->ipmask); - if (ipmask.s_addr == INADDR_NONE - || netmask(bitcount(ipmask.s_addr)) != ipmask.s_addr) { - fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask); - return 1; - } - - if (!args->ipaddr) { - autoip = true; - args->ipaddr = NMRP_DEFAULT_IP_REMOTE; - - if (!args->ipaddr_intf) { - args->ipaddr_intf = NMRP_DEFAULT_IP_LOCAL; - } - } else if (args->ipaddr_intf) { - autoip = true; - } else { - autoip = false; - } - - if ((ipaddr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) { - fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr); - return 1; - } - - if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) { - fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf); - return 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; - } - - if (args->file_remote) { - if (!tftp_is_valid_filename(args->file_remote)) { - fprintf(stderr, "Invalid remote filename '%s'.\n", - args->file_remote); + if (args->op == NMRP_UPLOAD_FW) { + if (!mac_parse(args->mac, dest)) { + fprintf(stderr, "Invalid MAC address '%s'.\n", args->mac); return 1; } + + ipmask.s_addr = inet_addr(args->ipmask); + if (ipmask.s_addr == INADDR_NONE + || netmask(bitcount(ipmask.s_addr)) != ipmask.s_addr) { + fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask); + return 1; + } + + if (!args->ipaddr) { + autoip = true; + args->ipaddr = NMRP_DEFAULT_IP_REMOTE; + + if (!args->ipaddr_intf) { + args->ipaddr_intf = NMRP_DEFAULT_IP_LOCAL; + } + } else if (args->ipaddr_intf) { + autoip = true; + } else { + autoip = false; + } + + if ((ipaddr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) { + fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr); + return 1; + } + + if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) { + fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf); + return 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; + } + + if (args->file_remote) { + if (!tftp_is_valid_filename(args->file_remote)) { + fprintf(stderr, "Invalid remote filename '%s'.\n", + args->file_remote); + return 1; + } + } } if (args->region) { @@ -459,6 +457,10 @@ int nmrp_do(struct nmrpd_args *args) region = 0; } + if (args->op == NMRP_SET_REGION && !region) { + fprintf(stderr, "No region code specified.\n"); + } + status = 1; sock = ethsock_create(args->intf, ETH_P_NMRP); @@ -498,22 +500,24 @@ int nmrp_do(struct nmrpd_args *args) } } - if (!autoip) { - status = is_valid_ip(sock, &ipaddr, &ipmask); - if (status <= 0) { - if (!status) { - fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n", - args->ipaddr, args->ipmask, args->intf); + if (args->op != NMRP_SET_REGION) { + if (!autoip) { + status = is_valid_ip(sock, &ipaddr, &ipmask); + if (status <= 0) { + if (!status) { + fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n", + args->ipaddr, args->ipmask, args->intf); + } + goto out; + } + } else { + if (verbosity) { + printf("Adding %s to interface %s.\n", args->ipaddr_intf, args->intf); } - goto out; - } - } else { - if (verbosity) { - printf("Adding %s to interface %s.\n", args->ipaddr_intf, args->intf); - } - if (ethsock_ip_add(sock, intf_addr, ipmask.s_addr, &ip_undo) != 0) { - goto out; + if (ethsock_ip_add(sock, intf_addr, ipmask.s_addr, &ip_undo) != 0) { + goto out; + } } } @@ -612,17 +616,28 @@ int nmrp_do(struct nmrpd_args *args) status = 1; goto out; case NMRP_C_CONF_REQ: - msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region); - expect = NMRP_C_TFTP_UL_REQ; + msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region, args->op); if (!args->blind) { 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)); + printf("Sending configuration:"); + if (args->op == NMRP_SET_REGION) { + expect = NMRP_C_CLOSE_REQ; + } else { + printf(" %s/%d", args->ipaddr, bitcount(ipmask.s_addr)); + // no support for NMRP_UPLOAD_ST + expect = NMRP_C_TFTP_UL_REQ; + } + + if (region) { + printf(" region %s", args->region); + } + + printf(".\n"); break; case NMRP_C_TFTP_UL_REQ: if (!upload_ok) { diff --git a/nmrpd.h b/nmrpd.h index f3ae224..675a92a 100644 --- a/nmrpd.h +++ b/nmrpd.h @@ -70,8 +70,6 @@ #define PACKED __attribute__((packed)) #endif -#define NMRPFLASH_SET_REGION - #define NMRP_DEFAULT_UL_TIMEOUT_S (30 * 60) #define NMRP_DEFAULT_RX_TIMEOUT_MS (10000) /*