Fix error messages
[oweals/nmrpflash.git] / ethsock.c
1 #include <sys/types.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include "nmrpd.h"
7
8 #if defined(NMRPFLASH_WINDOWS)
9 #define NMRPFLASH_NETALIAS_PREFIX "net"
10 #define WPCAP
11 #include <pcap.h>
12 #else
13 #include <sys/ioctl.h>
14 #include <ifaddrs.h>
15 #include <unistd.h>
16 #include <net/if.h>
17 #include <pcap.h>
18 #if defined(NMRPFLASH_LINUX)
19 #define NMRPFLASH_AF_PACKET AF_PACKET
20 #include <linux/if_packet.h>
21 #else
22 #define NMRPFLASH_AF_PACKET AF_LINK
23 #include <net/if_types.h>
24 #endif
25 #endif
26
27 struct ethsock
28 {
29         const char *intf;
30         pcap_t *pcap;
31 #ifndef NMRPFLASH_WINDOWS
32         int fd;
33 #else
34         HANDLE handle;
35         DWORD index;
36 #endif
37         unsigned timeout;
38         uint8_t hwaddr[6];
39 };
40
41 struct ethsock_ip_undo
42 {
43 #ifndef NMRPFLASH_WINDOWS
44         uint32_t ip[2];
45 #else
46         ULONG context;
47 #endif
48 };
49
50 const char *mac_to_str(uint8_t *mac)
51 {
52         static char buf[18];
53         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
54                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
55         return buf;
56 }
57
58 static int x_pcap_findalldevs(pcap_if_t **devs)
59 {
60         char errbuf[PCAP_ERRBUF_SIZE];
61         if (pcap_findalldevs(devs, errbuf) != 0) {
62                 fprintf(stderr, "%s.\n", errbuf);
63                 return -1;
64         }
65
66         return 0;
67 }
68
69 #ifndef NMRPFLASH_WINDOWS
70 static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
71 {
72         void *src;
73
74         if (sa->sa_family != NMRPFLASH_AF_PACKET) {
75                 return false;
76         }
77
78 #ifndef NMRPFLASH_LINUX
79         if (((struct sockaddr_dl*)sa)->sdl_type != IFT_ETHER) {
80                 return false;
81         }
82         src = LLADDR((struct sockaddr_dl*)sa);
83 #else
84         src = ((struct sockaddr_ll*)sa)->sll_addr;
85 #endif
86
87         memcpy(hwaddr, src, 6);
88         return true;
89 }
90
91 static bool get_intf_info(const char *intf, uint8_t *hwaddr, void *dummy)
92 {
93         struct ifaddrs *ifas, *ifa;
94         bool found;
95
96         if (getifaddrs(&ifas) != 0) {
97                 perror("getifaddrs");
98                 return false;
99         }
100
101         found = false;
102
103         for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
104                 if (!strcmp(ifa->ifa_name, intf)) {
105                         if (sockaddr_get_hwaddr(ifa->ifa_addr, hwaddr)) {
106                                 found = true;
107                                 break;
108                         }
109                 }
110         }
111
112         freeifaddrs(ifas);
113         return found;
114 }
115
116 #else
117
118 void win_perror2(const char *msg, DWORD err)
119 {
120         char *buf = NULL;
121         FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
122                         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
123                         NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
124                         (LPTSTR)&buf, 0, NULL);
125
126         if (buf) {
127                 /* FormatMessageA terminates buf with CRLF! */
128                 fprintf(stderr, "%s: %s", msg, buf);
129                 LocalFree(buf);
130         } else {
131                 fprintf(stderr, "%s: error %d\n", msg, (int)err);
132         }
133 }
134
135 static bool get_intf_info(const char *intf, uint8_t *hwaddr, DWORD *index)
136 {
137         PIP_ADAPTER_INFO adapters, adapter;
138         DWORD ret;
139         ULONG i, bufLen = 0;
140         bool found = false;
141
142         if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
143                 win_perror2("GetAdaptersInfo", ret);
144                 return false;
145         }
146
147         adapters = malloc(bufLen);
148         if (!adapters) {
149                 perror("malloc");
150                 return false;
151         }
152
153         if ((ret = GetAdaptersInfo(adapters, &bufLen) == NO_ERROR)) {
154                 for (adapter = adapters; adapter; adapter = adapter->Next) {
155                         if (adapter->Type != MIB_IF_TYPE_ETHERNET && adapter->Type != IF_TYPE_IEEE80211) {
156                                 continue;
157                         }
158
159                         /* Interface names from WinPcap are "\Device\NPF_{GUID}", while
160                          * AdapterName from GetAdaptersInfo is just "{GUID}".*/
161                         if (strstr(intf, adapter->AdapterName)) {
162                                 if (adapter->AddressLength == 6) {
163                                         memcpy(hwaddr, adapter->Address, 6);
164                                         if (index) {
165                                                 *index = adapter->Index;
166                                         }
167                                         found = true;
168                                         break;
169                                 }
170                         }
171                 }
172         } else {
173                 win_perror2("GetAdaptersInfo", ret);
174         }
175
176         free(adapters);
177         return found;
178 }
179
180 static const char *intf_alias_to_wpcap(const char *intf)
181 {
182         static char buf[128];
183         pcap_if_t *devs, *dev;
184         unsigned i = 0, dev_num = 0;
185
186         if (intf[0] == '\\') {
187                 return intf;
188         } else if (sscanf(intf, NMRPFLASH_NETALIAS_PREFIX "%u", &dev_num) != 1) {
189                 fprintf(stderr, "Invalid interface alias.\n");
190                 return NULL;
191         }
192
193         if (x_pcap_findalldevs(&devs) != 0) {
194                 return NULL;
195         }
196
197         for (dev = devs; dev; dev = dev->next, ++i) {
198                 if (i == dev_num) {
199                         if (verbosity) {
200                                 printf("%s%u: %s\n", NMRPFLASH_NETALIAS_PREFIX, i, dev->name);
201                         }
202                         strncpy(buf, dev->name, sizeof(buf) - 1);
203                         buf[sizeof(buf) - 1] = '\0';
204                         break;
205                 }
206         }
207
208         pcap_freealldevs(devs);
209
210         if (!dev) {
211                 fprintf(stderr, "Interface alias not found.\n");
212                 return NULL;
213         }
214
215         return buf;
216 }
217
218 static const char *intf_get_pretty_name(const char *intf)
219 {
220         static char buf[512];
221         char *guid;
222         HKEY hkey;
223         LONG err;
224         DWORD len;
225
226         guid = strstr(intf, "NPF_{");
227         if (!guid) {
228                 return NULL;
229         }
230
231         guid += 4;
232
233         snprintf(buf, sizeof(buf),
234                         "System\\CurrentControlSet\\Control\\Network\\"
235                         "{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
236                         "%s\\Connection", guid);
237         err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &hkey);
238         if (err != ERROR_SUCCESS) {
239                 if (verbosity > 1) {
240                         win_perror2("RegOpenKeyExA", err);
241                 }
242                 return NULL;
243         }
244
245         len = sizeof(buf);
246         err = RegQueryValueExA(hkey, "Name", NULL, NULL, (LPBYTE)buf, &len);
247         if (err == ERROR_SUCCESS) {
248                 intf = buf;
249         } else {
250                 if (verbosity > 1) {
251                         win_perror2("RegQueryValueExA", err);
252                 }
253                 intf = NULL;
254         }
255
256         RegCloseKey(hkey);
257         return intf;
258 }
259 #endif
260
261 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
262 {
263         return sock->hwaddr;
264 }
265
266 struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
267 {
268         char buf[PCAP_ERRBUF_SIZE];
269         struct bpf_program fp;
270         struct ethsock *sock;
271         int err;
272
273         sock = malloc(sizeof(struct ethsock));
274         if (!sock) {
275                 perror("malloc");
276                 return NULL;
277         }
278
279 #ifdef NMRPFLASH_WINDOWS
280         intf = intf_alias_to_wpcap(intf);
281         if (!intf) {
282                 return NULL;
283         }
284 #endif
285
286         buf[0] = '\0';
287
288         sock->intf = intf;
289         sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
290         if (!sock->pcap) {
291                 fprintf(stderr, "%s.\n", buf);
292                 goto cleanup_malloc;
293         }
294
295         if (*buf) {
296                 fprintf(stderr, "Warning: %s.\n", buf);
297         }
298
299         if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
300                 fprintf(stderr, "%s is not an ethernet interface.\n",
301                                 intf);
302                 goto cleanup_pcap;
303         }
304
305 #ifndef NMRPFLASH_WINDOWS
306         err = !get_intf_info(intf, sock->hwaddr, NULL);
307 #else
308         err = !get_intf_info(intf, sock->hwaddr, &sock->index);
309 #endif
310         if (err) {
311                 fprintf(stderr, "Failed to get interface info.\n");
312                 goto cleanup_malloc;
313         }
314
315 #ifndef NMRPFLASH_WINDOWS
316         sock->fd = pcap_get_selectable_fd(sock->pcap);
317         if (sock->fd == -1) {
318                 pcap_perror(sock->pcap, "pcap_get_selectable_fd");
319                 goto cleanup_pcap;
320         }
321 #else
322         sock->handle = pcap_getevent(sock->pcap);
323         if (!sock->handle) {
324                 pcap_perror(sock->pcap, "pcap_getevent");
325                 goto cleanup_pcap;
326         }
327
328         err = pcap_setmintocopy(sock->pcap, 1);
329         if (err) {
330                 pcap_perror(sock->pcap, "pcap_setmintocopy");
331                 goto cleanup_pcap;
332         }
333 #endif
334
335         snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
336                         protocol, mac_to_str(sock->hwaddr));
337
338         err = pcap_compile(sock->pcap, &fp, buf, 0, 0);
339         if (err) {
340                 pcap_perror(sock->pcap, "pcap_compile");
341                 goto cleanup_pcap;
342         }
343
344         err = pcap_setfilter(sock->pcap, &fp);
345         pcap_freecode(&fp);
346
347         if (err) {
348                 pcap_perror(sock->pcap, "pcap_setfilter");
349                 goto cleanup_pcap;
350         }
351
352         return sock;
353
354 cleanup_pcap:
355         pcap_close(sock->pcap);
356 cleanup_malloc:
357         free(sock);
358         return NULL;
359 }
360
361 int select_fd(int fd, unsigned timeout)
362 {
363         struct timeval tv;
364         int status;
365         fd_set fds;
366
367         FD_ZERO(&fds);
368         FD_SET(fd, &fds);
369
370         tv.tv_sec = timeout / 1000;
371         tv.tv_usec = 1000 * (timeout % 1000);
372
373         status = select(fd + 1, &fds, NULL, NULL, &tv);
374         if (status < 0) {
375                 sock_perror("select");
376         }
377
378         return status;
379 }
380
381 ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len)
382 {
383         struct pcap_pkthdr* hdr;
384         const u_char *capbuf;
385         int status;
386 #ifdef NMRPFLASH_WINDOWS
387         DWORD ret;
388
389         if (sock->timeout) {
390                 ret = WaitForSingleObject(sock->handle, sock->timeout);
391                 if (ret == WAIT_TIMEOUT) {
392                         return 0;
393                 } else if (ret != WAIT_OBJECT_0) {
394                         win_perror2("WaitForSingleObject", ret);
395                         return -1;
396                 }
397         }
398 #else
399         if (sock->timeout) {
400                 status = select_fd(sock->fd, sock->timeout);
401                 if (status < 0) {
402                         return -1;
403                 } else if (status == 0) {
404                         return 0;
405                 }
406         }
407 #endif
408
409         status = pcap_next_ex(sock->pcap, &hdr, &capbuf);
410         switch (status) {
411                 case 1:
412                         memcpy(buf, capbuf, MIN(len, hdr->caplen));
413                         return hdr->caplen;
414                 case 0:
415                         return 0;
416                 case -1:
417                         pcap_perror(sock->pcap, "pcap_next_ex");
418                         return -1;
419                 default:
420                         fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
421                         return -1;
422         }
423 }
424
425 int ethsock_send(struct ethsock *sock, void *buf, size_t len)
426 {
427 #ifdef NMRPFLASH_WINDOWS
428         if (pcap_sendpacket(sock->pcap, buf, len) == 0) {
429                 return 0;
430         } else {
431                 pcap_perror(sock->pcap, "pcap_sendpacket");
432                 return -1;
433         }
434 #else
435         if (pcap_inject(sock->pcap, buf, len) == len) {
436                 return 0;
437         } else {
438                 pcap_perror(sock->pcap, "pcap_inject");
439                 return -1;
440         }
441 #endif
442 }
443
444 int ethsock_close(struct ethsock *sock)
445 {
446         pcap_close(sock->pcap);
447         free(sock);
448         return 0;
449 }
450
451 inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
452 {
453         sock->timeout = msec;
454         return 0;
455 }
456
457 #ifndef NMRPFLASH_WINDOWS
458 int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
459 {
460         return 0;
461 }
462
463 int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
464 {
465         return 0;
466 }
467 #else
468 static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr, int add)
469 {
470         DWORD ret;
471         MIB_IPNETROW arp = {
472                 .dwIndex = sock->index,
473                 .dwPhysAddrLen = 6,
474                 .dwAddr = ipaddr->s_addr,
475                 .dwType = MIB_IPNET_TYPE_STATIC
476         };
477         
478         memcpy(arp.bPhysAddr, hwaddr, 6);
479         
480         if (add) {
481                 ret = CreateIpNetEntry(&arp);
482                 if (ret != NO_ERROR) {
483                         win_perror2("CreateIpNetEntry", ret);
484                         return -1;
485                 }
486         } else {
487                 DeleteIpNetEntry(&arp);
488         }
489         
490         return 0;
491 }
492
493 int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
494 {
495         ethsock_arp_del(sock, hwaddr, ipaddr);
496         return ethsock_arp(sock, hwaddr, ipaddr, 1);
497 }
498
499 int ethsock_arp_del(struct ethsock *sock, uint8_t *hwaddr, struct in_addr *ipaddr)
500 {
501         return ethsock_arp(sock, hwaddr, ipaddr, 0);
502 }
503 #endif
504
505 static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
506 {
507 #ifndef NMRPFLASH_WINDOWS
508         pcap_addr_t *addr;
509         int i;
510
511         for (addr = dev->addresses; addr; addr = addr->next) {
512                 if (verbosity > 1) {
513                         printf("%s: sa_family=%d, sa_data={ ", dev->name,
514                                         addr->addr->sa_family);
515                         for (i = 0; i != sizeof(addr->addr->sa_data); ++i) {
516                                 printf("%02x ", addr->addr->sa_data[i] & 0xff);
517                         }
518                         printf("}\n");
519                 }
520
521                 if (sockaddr_get_hwaddr(addr->addr, hwaddr)) {
522                         return true;
523                 }
524         }
525 #endif
526
527         return get_intf_info(dev->name, hwaddr, NULL);
528 }
529
530 int ethsock_list_all(void)
531 {
532         pcap_if_t *devs, *dev;
533         pcap_addr_t *addr;
534         uint8_t hwaddr[6];
535         unsigned dev_num = 0, dev_ok = 0;
536 #ifdef NMRPFLASH_WINDOWS
537         const char *pretty;
538 #endif
539
540         if (x_pcap_findalldevs(&devs) != 0) {
541                 return -1;
542         }
543
544         memset(hwaddr, 0, 6);
545
546         for (dev = devs; dev; dev = dev->next, ++dev_num) {
547                 if (dev->flags & PCAP_IF_LOOPBACK) {
548                         if (verbosity) {
549                                 printf("%-15s  (loopback device)\n", dev->name);
550                         }
551                         continue;
552                 }
553
554                 if (!get_hwaddr_from_pcap(dev, hwaddr)) {
555                         if (verbosity) {
556                                 printf("%-15s  (not an ethernet device)\n",
557                                                 dev->name);
558                         }
559                         continue;
560                 }
561
562 #ifndef NMRPFLASH_WINDOWS
563                 printf("%-15s", dev->name);
564 #else
565                 /* Call this here so *_perror() calls don't happen within a line */
566                 pretty = intf_get_pretty_name(dev->name);
567
568                 if (!verbosity) {
569                         printf("%s%u", NMRPFLASH_NETALIAS_PREFIX, dev_num);
570                 } else {
571                         printf("%s", dev->name);
572                 }
573 #endif
574
575                 for (addr = dev->addresses; addr; addr = addr->next) {
576                         if (addr->addr->sa_family == AF_INET) {
577                                 printf("  %-15s",
578                                                 inet_ntoa(((struct sockaddr_in*)addr->addr)->sin_addr));
579                                 break;
580                         }
581                 }
582
583                 if (!addr) {
584                         printf("  %-15s", "0.0.0.0");
585                 }
586
587                 printf("  %s", mac_to_str(hwaddr));
588
589 #ifdef NMRPFLASH_WINDOWS
590                 if (pretty) {
591                         printf("  (%s)", pretty);
592                 } else if (dev->description) {
593                         printf("  (%s)", dev->description);
594                 }
595
596 #endif
597                 printf("\n");
598                 ++dev_ok;
599         }
600
601         if (!dev_ok) {
602                 printf("No suitable network interfaces found.\n");
603         }
604
605         return 0;
606 }
607
608 int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
609                 void *arg)
610 {
611         struct ethsock_ip_callback_args args;
612         pcap_if_t *devs, *dev;
613         pcap_addr_t *addr;
614         int status = 0;
615
616         if (x_pcap_findalldevs(&devs) != 0) {
617                 return -1;
618         }
619
620         args.arg = arg;
621
622         for (dev = devs; dev; dev = dev->next) {
623                 if (strcmp(sock->intf, dev->name)) {
624                         continue;
625                 }
626
627                 for (addr = dev->addresses; addr; addr = addr->next) {
628                         if (addr->addr->sa_family == AF_INET) {
629                                 args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr;
630                                 args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr;
631
632                                 status = callback(&args);
633                                 if (status <= 0) {
634                                         break;
635                                 }
636                         }
637                 }
638
639                 break;
640         }
641
642         pcap_freealldevs(devs);
643
644         return status <= 0 ? status : 0;
645 }
646
647 static inline void set_addr(void *p, uint32_t addr)
648 {
649         struct sockaddr_in* sin = p;
650         sin->sin_family = AF_INET;
651         sin->sin_addr.s_addr = addr;
652 }
653
654 #ifndef NMRPFLASH_WINDOWS
655 static bool set_interface_up(int fd, const char *intf, bool up)
656 {
657         struct ifreq ifr;
658         strncpy(ifr.ifr_name, intf, IFNAMSIZ);
659
660         if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
661                 perror("ioctl(SIOCGIFFLAGS)");
662                 return false;
663         }
664
665         if (!up) {
666                 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
667         } else {
668                 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
669         }
670
671         if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
672                 perror("ioctl(SIOCSIFFLAGS)");
673                 return false;
674         }
675
676         return true;
677 }
678
679 #endif
680
681 int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
682 {
683         if (undo && !(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
684                 perror("malloc");
685                 return -1;
686         }
687
688         int fd = socket(AF_INET, SOCK_DGRAM, 0);
689         if (!fd) {
690                 sock_perror("socket");
691                 return -1;
692         }
693
694         int ret = -1;
695 #ifndef NMRPFLASH_WINDOWS
696         // XXX: undo is non-zero only if we're adding an IP
697         bool add = undo;
698 #ifdef NMRPFLASH_LINUX
699         struct ifreq ifr;
700         strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
701         // FIXME: automatically determine the next free alias
702         strcat(ifr.ifr_name, ":42");
703
704         if (add) {
705                 set_addr(&ifr.ifr_addr, ipaddr);
706                 if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
707                         perror("ioctl(SIOSIFADDR)");
708                         goto out;
709                 }
710
711                 set_addr(&ifr.ifr_netmask, ipmask);
712                 if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
713                         perror("ioctl(SIOCSIFNETMASK)");
714                         goto out;
715                 }
716
717                 (*undo)->ip[0] = ipaddr;
718                 (*undo)->ip[1] = ipmask;
719         }
720
721         if (!set_interface_up(fd, ifr.ifr_name, add ? true : false)) {
722                 goto out;
723         }
724 #else // NMRPFLASH_OSX (or any other BSD)
725         struct ifaliasreq ifra;
726         strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
727
728         set_addr(&ifra.ifra_addr, ipaddr);
729         set_addr(&ifra.ifra_mask, ipmask);
730         //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
731         memset(&ifra.ifra_broadaddr, 0, sizeof(ifra.ifra_broadaddr));
732
733         if (ioctl(fd, add ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
734                 perror(add ? "ioctl(SIOCAIFADDR)" : "ioctl(SIOCDIFADDR)");
735                 goto out;
736         }
737
738         if (add) {
739                 (*undo)->ip[0] = ipaddr;
740                 (*undo)->ip[1] = ipmask;
741                 set_interface_up(fd, ifra.ifra_name, true);
742         }
743
744 #endif
745 #else // NMRPFLASH_WINDOWS
746         struct sockaddr_in sin;
747         ULONG instance;
748
749         (*undo)->context = 0;
750
751         DWORD err = AddIPAddress(ipaddr, ipmask, sock->index, &(*undo)->context, &instance);
752         if (err != NO_ERROR && err != ERROR_DUP_DOMAINNAME && err != ERROR_OBJECT_ALREADY_EXISTS) {
753                 win_perror2("AddIPAddress", err);
754                 goto out;
755         }
756
757         set_addr(&sin, ipaddr);
758         clock_t now = clock();
759
760         /* Wait until the new IP has actually been added */
761
762         while (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
763                 if (((clock() - now) / CLOCKS_PER_SEC) >= 5) {
764                         fprintf(stderr, "Failed to bind after 5 seconds: ");
765                         sock_perror("bind");
766                         DeleteIPAddress((*undo)->context);
767                         goto out;
768                 }
769         }
770         return 0;
771 #endif
772         ret = 0;
773
774 out:
775 #ifndef NMRPFLASH_WINDOWS
776         close(fd);
777 #else
778         closesocket(fd);
779 #endif
780         return ret;
781 }
782
783 int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
784 {
785         if (!*undo) {
786                 return 0;
787         }
788
789         int ret;
790
791 #ifndef NMRPFLASH_WINDOWS
792         if ((*undo)->ip[0] != INADDR_NONE) {
793                 ret = ethsock_ip_add(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
794         } else {
795                 ret = 0;
796         }
797 #else
798         DeleteIPAddress((*undo)->context);
799         ret = 0;
800 #endif
801
802         free(*undo);
803         *undo = NULL;
804         return ret;
805 }