Exit after successful upload in blind mode
[oweals/nmrpflash.git] / nmrp.c
1 /**
2  * nmrpflash - Netgear Unbrick Utility
3  * Copyright (C) 2016 Joseph Lehner <joseph.c.lehner@gmail.com>
4  *
5  * nmrpflash is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * nmrpflash is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with nmrpflash.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include "nmrpd.h"
28
29 #define NMRP_HDR_LEN 6
30 #define NMRP_OPT_HDR_LEN 4
31 #define NMRP_MIN_PKT_LEN (sizeof(struct eth_hdr) +  NMRP_HDR_LEN)
32
33 #define ETH_P_NMRP 0x0912
34
35 #ifndef PACKED
36 #define PACKED __attribute__((__packed__))
37 #endif
38
39 #ifdef NMRPFLASH_WINDOWS
40 #define setenv(name, value, overwrite) SetEnvironmentVariable(name, value)
41 #endif
42
43 enum nmrp_code {
44         NMRP_C_NONE = 0,
45         NMRP_C_ADVERTISE = 1,
46         NMRP_C_CONF_REQ = 2,
47         NMRP_C_CONF_ACK = 3,
48         NMRP_C_CLOSE_REQ = 4,
49         NMRP_C_CLOSE_ACK = 5,
50         NMRP_C_KEEP_ALIVE_REQ = 6,
51         NMRP_C_KEEP_ALIVE_ACK = 7,
52         NMRP_C_TFTP_UL_REQ = 16
53 };
54
55 enum nmrp_opt_type {
56         NMRP_O_MAGIC_NO = 0x0001,
57         NMRP_O_DEV_IP = 0x0002,
58         NMRP_O_DEV_REGION = 0x0004,
59         NMRP_O_FW_UP = 0x0101,
60         NMRP_O_ST_UP = 0x0102,
61         NMRP_O_FILE_NAME = 0x0181
62 };
63
64 struct nmrp_opt {
65         uint16_t type;
66         uint16_t len;
67         char val[1];
68 } PACKED;
69
70 struct nmrp_msg {
71         uint16_t reserved;
72         uint8_t code;
73         uint8_t id;
74         uint16_t len;
75         char opts[44];
76 } PACKED;
77
78 struct nmrp_pkt {
79         struct eth_hdr eh;
80         struct nmrp_msg msg;
81 } PACKED;
82
83 static const char *msg_code_str(uint16_t code)
84 {
85 #define MSG_CODE(x) case NMRP_C_ ## x: return #x
86         static char buf[16];
87
88         switch (code) {
89                 MSG_CODE(ADVERTISE);
90                 MSG_CODE(CONF_REQ);
91                 MSG_CODE(CONF_ACK);
92                 MSG_CODE(CLOSE_REQ);
93                 MSG_CODE(CLOSE_ACK);
94                 MSG_CODE(KEEP_ALIVE_REQ);
95                 MSG_CODE(KEEP_ALIVE_ACK);
96                 MSG_CODE(TFTP_UL_REQ);
97                 default:
98                         snprintf(buf, sizeof(buf), "%04x", ntohs(code));
99                         return buf;
100         }
101 #undef MSG_CODE
102 }
103
104 static uint16_t to_region_code(const char *region)
105 {
106 #define REGION_CODE(r, c) if (!strcasecmp(region, r)) return htons(c)
107         REGION_CODE("NA", 0x0001);
108         REGION_CODE("WW", 0x0002);
109         REGION_CODE("GR", 0x0003);
110         REGION_CODE("PR", 0x0004);
111         REGION_CODE("RU", 0x0005);
112         REGION_CODE("BZ", 0x0006);
113         REGION_CODE("IN", 0x0007);
114         REGION_CODE("KO", 0x0008);
115         REGION_CODE("JP", 0x0009);
116 #undef REGION_CODE
117         return 0;
118 }
119
120 static void msg_dump(struct nmrp_msg *msg)
121 {
122         int rem;
123
124         fprintf(stderr, "res=0x%04x, code=0x%02x, id=0x%02x, len=%u",
125                         ntohs(msg->reserved), msg->code, msg->id, ntohs(msg->len));
126
127         rem = ntohs(msg->len) - NMRP_HDR_LEN;
128         fprintf(stderr, "%s\n", rem ? "" : " (no opts)");
129 }
130
131 static void *msg_opt(struct nmrp_msg *msg, uint16_t type, uint16_t* len)
132 {
133         struct nmrp_opt* opt = (struct nmrp_opt*)msg->opts;
134         size_t rem = ntohs(msg->len) - NMRP_HDR_LEN;
135         uint16_t olen;
136
137         do {
138                 olen = ntohs(opt->len);
139                 if (olen < NMRP_OPT_HDR_LEN || olen > rem) {
140                         break;
141                 }
142
143                 if (ntohs(opt->type) == type) {
144                         if (len) {
145                                 *len = olen;
146                         }
147
148                         return opt->val;
149                 }
150
151                 opt = (struct nmrp_opt*)(((char *)opt) + olen);
152                 rem -= olen;
153         } while (rem);
154
155         return NULL;
156 }
157
158 static char *msg_filename(struct nmrp_msg *msg)
159 {
160         static char buf[256];
161         uint16_t len;
162         char *p = msg_opt(msg, NMRP_O_FILE_NAME, &len);
163         if (p) {
164                 len = MIN(sizeof(buf) - 1, len);
165                 memcpy(buf, p, len);
166                 buf[len] = '\0';
167                 return buf;
168         }
169
170         return NULL;
171 }
172
173 static inline void msg_init(struct nmrp_msg *msg, uint16_t code)
174 {
175         memset(msg, 0, sizeof(*msg));
176         msg->len = htons(NMRP_HDR_LEN);
177         msg->code = code;
178 }
179
180 static char *msg_mkopt(struct nmrp_msg *msg, char *p, uint16_t type, const void *val, size_t len)
181 {
182         struct nmrp_opt* opt = (struct nmrp_opt*)p;
183
184         len &= 0xffff;
185
186         msg->len = ntohs(msg->len);
187
188         if ((msg->len + len > sizeof(*msg))) {
189                 fprintf(stderr, "Error: invalid option - this is a bug\n");
190                 exit(1);
191         }
192
193         opt->type = htons(type);
194         opt->len = NMRP_OPT_HDR_LEN + len;
195
196         if (val) {
197                 memcpy(opt->val, val, len);
198         }
199
200         msg->len += opt->len;
201         p += opt->len;
202
203         msg->len = htons(msg->len);
204         opt->len = htons(opt->len);
205
206         return p;
207 }
208
209 static void msg_mkadvertise(struct nmrp_msg *msg, const char *magic)
210 {
211         msg_init(msg, NMRP_C_ADVERTISE);
212         msg_mkopt(msg, msg->opts, NMRP_O_MAGIC_NO, magic, strlen(magic));
213 }
214
215 static void msg_mkconfack(struct nmrp_msg *msg, uint32_t ipaddr, uint32_t ipmask, uint16_t region)
216 {
217         char *p;
218         uint32_t ip[2] = { ipaddr, ipmask };
219
220         msg_init(msg, NMRP_C_CONF_ACK);
221         p = msg_mkopt(msg, msg->opts, NMRP_O_DEV_IP, &ip, 8);
222         p = msg_mkopt(msg, p, NMRP_O_FW_UP, NULL, 0);
223
224 #ifdef NMRPFLASH_SET_REGION
225         if (region) {
226                 p = msg_mkopt(msg, p, NMRP_O_DEV_REGION, &region, 2);
227         }
228 #endif
229 }
230
231 #ifdef NMRPFLASH_FUZZ
232 #define NMRP_INITIAL_TIMEOUT 0
233 #define ethsock_create(a, b) ((struct ethsock*)1)
234 #define ethsock_get_hwaddr(a) ethsock_get_hwaddr_fake(a)
235 #define ethsock_recv(sock, buf, len) read(STDIN_FILENO, buf, len)
236 #define ethsock_send(a, b, c) (0)
237 #define ethsock_set_timeout(a, b) (0)
238 #define ethsock_arp_add(a, b, c, d) (0)
239 #define ethsock_arp_del(a, b) (0)
240 #define ethsock_ip_add(a, b, c, d) (0)
241 #define ethsock_ip_del(a, b) (0)
242 #define ethsock_close(a) (0)
243 #define tftp_put(a) (0)
244
245 static uint8_t *ethsock_get_hwaddr_fake(struct ethsock* sock)
246 {
247         static uint8_t hwaddr[6] = { 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa };
248         return hwaddr;
249 }
250 #else
251 #define NMRP_INITIAL_TIMEOUT 60
252 #endif
253
254 static int pkt_send(struct ethsock *sock, struct nmrp_pkt *pkt)
255 {
256         return ethsock_send(sock, pkt, sizeof(*pkt));
257 }
258
259 static int pkt_recv(struct ethsock *sock, struct nmrp_pkt *pkt)
260 {
261         ssize_t bytes, mlen;
262
263         memset(pkt, 0, sizeof(*pkt));
264         bytes = ethsock_recv(sock, pkt, sizeof(*pkt));
265         if (bytes < 0) {
266                 return 1;
267         } else if (!bytes) {
268                 return 2;
269         }
270
271         mlen = ntohs(pkt->msg.len);
272
273         if (bytes < (mlen + sizeof(pkt->eh))
274                         || bytes < NMRP_MIN_PKT_LEN
275                         || mlen < NMRP_HDR_LEN) {
276                 fprintf(stderr, "Short packet (%d raw, %d message)\n",
277                                 (int)bytes, (int)mlen);
278                 return 1;
279         } else if (mlen > sizeof(pkt->msg)) {
280                 printf("Truncating %d byte message.\n", (int)mlen);
281                 pkt->msg.len = htons(sizeof(pkt->msg));
282         }
283
284         return 0;
285 }
286
287 static int mac_parse(const char *str, uint8_t *hwaddr)
288 {
289         int i;
290         unsigned data[6];
291
292         sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x%n",
293                         data, data + 1, data + 2, data + 3, data + 4, data + 5, &i);
294
295         if (i == strlen(str)) {
296                 for (i = 0; i != 6; ++i) {
297                         if (data[i] > 255) {
298                                 break;
299                         }
300
301                         hwaddr[i] = data[i] & 0xff;
302                 }
303
304                 if (i == 6) {
305                         return 1;
306                 }
307         }
308         return 0;
309 }
310
311 struct is_valid_ip_arg
312 {
313         struct in_addr *ipaddr;
314         struct in_addr *ipmask;
315         int result;
316 };
317
318 static int is_valid_ip_cb(struct ethsock_ip_callback_args *args)
319 {
320 #define SUBNET(x) ((x)->ipaddr->s_addr & (x)->ipmask->s_addr)
321         struct is_valid_ip_arg *arg = args->arg;
322         if (SUBNET(args) == SUBNET(arg)) {
323                 arg->result = args->ipaddr->s_addr != arg->ipaddr->s_addr;
324                 return 0;
325         }
326
327         return 1;
328 #undef SUBNET
329 }
330
331 static int is_valid_ip(struct ethsock *sock, struct in_addr *ipaddr,
332                 struct in_addr *ipmask)
333 {
334         int status;
335         struct is_valid_ip_arg arg = {
336                 .ipaddr = ipaddr,
337                 .ipmask = ipmask,
338                 .result = 0
339         };
340
341         status = ethsock_for_each_ip(sock, is_valid_ip_cb, &arg);
342         return status < 0 ? status : arg.result;
343 }
344
345 static void sigh(int sig)
346 {
347         g_interrupted = 1;
348 }
349
350 static const char *spinner = "\\|/-";
351
352 int nmrp_do(struct nmrpd_args *args)
353 {
354         struct nmrp_pkt tx, rx;
355         uint8_t *src, dest[6];
356         uint16_t region;
357         char *filename;
358         time_t beg;
359         int i, timeout, status, ulreqs, expect, upload_ok, autoip, kareqs;
360         struct ethsock *sock;
361         struct ethsock_ip_undo *ip_undo = NULL;
362         struct ethsock_arp_undo *arp_undo = NULL;
363         uint32_t intf_addr;
364         void (*sigh_orig)(int);
365         struct in_addr ipaddr;
366         struct in_addr ipmask;
367
368         if (args->op != NMRP_UPLOAD_FW) {
369                 fprintf(stderr, "Operation not implemented.\n");
370                 return 1;
371         }
372
373         if (!mac_parse(args->mac, dest)) {
374                 fprintf(stderr, "Invalid MAC address '%s'.\n", args->mac);
375                 return 1;
376         }
377
378         ipmask.s_addr = inet_addr(args->ipmask);
379         if (ipmask.s_addr == INADDR_NONE
380                         || netmask(bitcount(ipmask.s_addr)) != ipmask.s_addr) {
381                 fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
382                 return 1;
383         }
384
385         if (!args->ipaddr) {
386                 autoip = true;
387                 /* A random IP address. The MAC of the first device that was
388                  * used to test this utility starts with a4:2b:8c, so we use
389                  * 164 (0xa4) and 183 (0x2b + 0x8c).
390                  *
391                  * These addresses should not cause collisions on most networks,
392                  * and if they do, the user is probably "poweruser" enough to
393                  * be able to use the -a and -A options.
394                  */
395                 args->ipaddr = "10.164.183.252";
396
397                 if (!args->ipaddr_intf) {
398                         args->ipaddr_intf = "10.164.183.253";
399                 }
400         } else if (args->ipaddr_intf) {
401                 autoip = true;
402         } else {
403                 autoip = false;
404         }
405
406         if ((ipaddr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) {
407                 fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
408                 return 1;
409         }
410
411         if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) {
412                 fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf);
413                 return 1;
414         }
415
416         if (args->file_local && strcmp(args->file_local, "-") && access(args->file_local, R_OK) == -1) {
417                 fprintf(stderr, "Error accessing file '%s'.\n", args->file_local);
418                 return 1;
419         }
420
421         if (args->file_remote) {
422                 if (!tftp_is_valid_filename(args->file_remote)) {
423                         fprintf(stderr, "Invalid remote filename '%s'.\n",
424                                         args->file_remote);
425                         return 1;
426                 }
427         }
428
429         if (args->region) {
430                 region = to_region_code(args->region);
431                 if (!region) {
432                         fprintf(stderr, "Invalid region code '%s'.\n", args->region);
433                         return 1;
434                 }
435         } else {
436                 region = 0;
437         }
438
439         status = 1;
440
441         sock = ethsock_create(args->intf, ETH_P_NMRP);
442         if (!sock) {
443                 return 1;
444         }
445
446         sigh_orig = signal(SIGINT, sigh);
447
448         if (!autoip) {
449                 status = is_valid_ip(sock, &ipaddr, &ipmask);
450                 if (status <= 0) {
451                         if (!status) {
452                                 fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n",
453                                                 args->ipaddr, args->ipmask, args->intf);
454                         }
455                         goto out;
456                 }
457         } else {
458                 if (verbosity) {
459                         printf("Adding %s to interface %s.\n", args->ipaddr_intf, args->intf);
460                 }
461
462                 if (ethsock_ip_add(sock, intf_addr, ipmask.s_addr, &ip_undo) != 0) {
463                         goto out;
464                 }
465         }
466
467         if (ethsock_set_timeout(sock, args->rx_timeout)) {
468                 goto out;
469         }
470
471         src = ethsock_get_hwaddr(sock);
472         if (!src) {
473                 goto out;
474         }
475
476         memcpy(tx.eh.ether_shost, src, 6);
477         memcpy(tx.eh.ether_dhost, dest, 6);
478         tx.eh.ether_type = htons(ETH_P_NMRP);
479
480         msg_mkadvertise(&tx.msg, "NTGR");
481
482         i = 0;
483         upload_ok = 0;
484         timeout = args->blind ? 10 : NMRP_INITIAL_TIMEOUT;
485         beg = time_monotonic();
486
487         while (!g_interrupted) {
488                 printf("\rAdvertising NMRP server on %s ... %c",
489                                 args->intf, spinner[i]);
490                 fflush(stdout);
491                 i = (i + 1) & 3;
492
493                 if (pkt_send(sock, &tx) < 0) {
494                         goto out;
495                 }
496
497                 status = pkt_recv(sock, &rx);
498                 if (status == 0) {
499                         if (memcmp(rx.eh.ether_dhost, src, 6) == 0) {
500                                 break;
501                         } else if (verbosity) {
502                                 printf("\nIgnoring bogus response: %s -> %s.\n",
503                                                 mac_to_str(rx.eh.ether_shost),
504                                                 mac_to_str(rx.eh.ether_dhost));
505                         }
506                 } else if (status == 1) {
507                         goto out;
508                 } else {
509                         /* because we don't want nmrpflash's exit status to be zero */
510                         status = 1;
511                         if ((time_monotonic() - beg) >= timeout) {
512                                 printf("\nNo response after %d seconds. ", timeout);
513                                 if (!args->blind) {
514                                         printf("Bailing out.\n");
515                                         goto out;
516                                 } else {
517                                         // we're blind, so fake a response from the MAC specified by -m
518                                         memcpy(rx.eh.ether_shost, dest, 6);
519                                         msg_init(&rx.msg, NMRP_C_CONF_REQ);
520                                         printf("Faking one.");
521                                         break;
522                                 }
523                         }
524                 }
525         }
526
527         printf("\n");
528
529         memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6);
530
531         if (ethsock_arp_add(sock, rx.eh.ether_shost, ipaddr.s_addr, &arp_undo) != 0) {
532                 goto out;
533         }
534
535         expect = NMRP_C_CONF_REQ;
536         ulreqs = 0;
537         kareqs = 0;
538
539         while (!g_interrupted) {
540                 if (expect != NMRP_C_NONE && rx.msg.code != expect) {
541                         fprintf(stderr, "Received %s while waiting for %s!\n",
542                                         msg_code_str(rx.msg.code), msg_code_str(expect));
543                 }
544
545                 msg_init(&tx.msg, NMRP_C_NONE);
546
547                 status = 1;
548
549                 switch (rx.msg.code) {
550                         case NMRP_C_ADVERTISE:
551                                 printf("Received NMRP advertisement from %s.\n",
552                                                 mac_to_str(rx.eh.ether_shost));
553                                 status = 1;
554                                 goto out;
555                         case NMRP_C_CONF_REQ:
556                                 msg_mkconfack(&tx.msg, ipaddr.s_addr, ipmask.s_addr, region);
557                                 expect = NMRP_C_TFTP_UL_REQ;
558
559                                 printf("Received configuration request from %s.\n",
560                                                 mac_to_str(rx.eh.ether_shost));
561
562                                 printf("Sending configuration: %s/%d.\n",
563                                                 args->ipaddr, bitcount(ipmask.s_addr));
564
565                                 break;
566                         case NMRP_C_TFTP_UL_REQ:
567                                 if (!upload_ok) {
568                                         if (++ulreqs > 5) {
569                                                 printf("Bailing out after %d upload requests.\n",
570                                                                 ulreqs);
571                                                 tx.msg.code = NMRP_C_CLOSE_REQ;
572                                                 break;
573                                         }
574                                 } else {
575                                         if (verbosity) {
576                                                 printf("Ignoring extra upload request.\n");
577                                         }
578                                         ethsock_set_timeout(sock, args->ul_timeout);
579                                         tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
580                                         break;
581                                 }
582
583                                 filename = msg_filename(&rx.msg);
584                                 if (filename) {
585                                         if (!args->file_remote) {
586                                                 args->file_remote = filename;
587                                         }
588                                         printf("Received upload request: filename '%s'.\n", filename);
589                                 } else if (!args->file_remote) {
590                                         args->file_remote = leafname(args->file_local);
591                                         printf("Received upload request without filename.\n");
592                                 }
593
594                                 status = 0;
595
596                                 if (args->tftpcmd) {
597                                         printf("Executing '%s' ... \n", args->tftpcmd);
598                                         setenv("IP", inet_ntoa(ipaddr), 1);
599                                         setenv("PORT", lltostr(args->port, 10), 1);
600                                         setenv("MAC", mac_to_str(rx.eh.ether_shost), 1);
601                                         setenv("NETMASK", inet_ntoa(ipmask), 1);
602                                         //setenv("FILENAME", args->file_remote ? args->file_remote : "", 1);
603                                         status = system(args->tftpcmd);
604                                 }
605
606                                 if (!status && args->file_local) {
607                                         if (!autoip) {
608                                                 status = is_valid_ip(sock, &ipaddr, &ipmask);
609                                                 if (status < 0) {
610                                                         goto out;
611                                                 } else if (!status) {
612                                                         printf("IP address of %s has changed. Please assign a "
613                                                                         "static ip to the interface.\n", args->intf);
614                                                         tx.msg.code = NMRP_C_CLOSE_REQ;
615                                                         break;
616                                                 }
617                                         }
618
619                                         if (verbosity) {
620                                                 printf("Using remote filename '%s'.\n",
621                                                                 args->file_remote);
622                                         }
623
624                                         if (!strcmp(args->file_local, "-")) {
625                                                 printf("Uploading from stdin ... ");
626                                         } else {
627                                                 printf("Uploading %s ... ", leafname(args->file_local));
628                                         }
629                                         fflush(stdout);
630                                         if (!(status = tftp_put(args))) {
631                                                 printf("OK\n");
632                                         }
633
634                                 }
635
636                                 if (!status) {
637                                         if (args->blind) {
638                                                 goto out;
639                                         }
640
641                                         printf("Waiting for remote to respond.\n");
642                                         upload_ok = 1;
643                                         ethsock_set_timeout(sock, args->ul_timeout);
644                                         tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
645                                         expect = NMRP_C_NONE;
646                                 } else if (status == -2) {
647                                         expect = NMRP_C_TFTP_UL_REQ;
648                                 } else {
649                                         goto out;
650                                 }
651
652                                 break;
653                         case NMRP_C_KEEP_ALIVE_REQ:
654                                 tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
655                                 ethsock_set_timeout(sock, args->ul_timeout);
656                                 printf("\rReceived keep-alive request (%d).  ", ++kareqs);
657                                 break;
658                         case NMRP_C_CLOSE_REQ:
659                                 tx.msg.code = NMRP_C_CLOSE_ACK;
660                                 break;
661                         case NMRP_C_CLOSE_ACK:
662                                 status = 0;
663                                 goto out;
664                         default:
665                                 fprintf(stderr, "Unknown message code 0x%02x!\n",
666                                                 rx.msg.code);
667                                 msg_dump(&rx.msg);
668                 }
669
670                 if (tx.msg.code != NMRP_C_NONE) {
671                         if (pkt_send(sock, &tx) < 0) {
672                                 goto out;
673                         }
674
675                         if (tx.msg.code == NMRP_C_CLOSE_REQ) {
676                                 goto out;
677                         }
678                 }
679
680                 if (rx.msg.code == NMRP_C_CLOSE_REQ) {
681                         if (kareqs) {
682                                 printf("\n");
683                         }
684
685                         printf("Remote finished. Closing connection.\n");
686                         break;
687                 }
688
689                 status = pkt_recv(sock, &rx);
690                 if (status) {
691                         if (status == 2) {
692                                 fprintf(stderr, "Timeout while waiting for %s. ",
693                                                 msg_code_str(expect));
694                         }
695
696                         if (!args->blind) {
697                                 printf("\n");
698                                 goto out;
699                         } else {
700                                 printf("Faking response.\n");
701                                 msg_init(&rx.msg, expect);
702                                 memcpy(rx.eh.ether_shost, tx.eh.ether_dhost, 6);
703                         }
704                 }
705
706                 ethsock_set_timeout(sock, args->rx_timeout);
707
708         }
709
710         if (!g_interrupted) {
711                 status = 0;
712                 if (ulreqs) {
713                         printf("Reboot your device now.\n");
714                 } else {
715                         printf("No upload request received.\n");
716                 }
717         }
718
719 out:
720         signal(SIGINT, sigh_orig);
721         ethsock_arp_del(sock, &arp_undo);
722         ethsock_ip_del(sock, &ip_undo);
723         ethsock_close(sock);
724         return status;
725 }