Longer timeout for initial WRQ
[oweals/nmrpflash.git] / ethsock.c
index 371364f627efd67ac20f9ea66cdb23c126914d46..8f970e1d458e9aa980a82a723ffec8c271d12f41 100644 (file)
--- a/ethsock.c
+++ b/ethsock.c
 #include <pcap.h>
 #include <ifaddrs.h>
 #if defined(NMRPFLASH_LINUX)
+#define NMRPFLASH_AF_PACKET AF_PACKET
 #include <linux/if_packet.h>
-#elif defined (NMRPFLASH_OSX)
-#include <net/if_dl.h>
-#endif
+#else
+#define NMRPFLASH_AF_PACKET AF_LINK
+#include <net/if_types.h>
 #endif
-
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
-
 struct ethsock
 {
+       const char *intf;
        pcap_t *pcap;
 #ifndef NMRPFLASH_WINDOWS
        int fd;
@@ -56,10 +54,30 @@ static int x_pcap_findalldevs(pcap_if_t **devs)
 }
 
 #ifndef NMRPFLASH_WINDOWS
-static bool get_hwaddr(uint8_t *hwaddr, const char *intf)
+static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
 {
-       struct ifaddrs *ifas, *ifa;
        void *src;
+
+       if (sa->sa_family != NMRPFLASH_AF_PACKET) {
+               return false;
+       }
+
+#ifndef NMRPFLASH_LINUX
+       if (((struct sockaddr_dl*)sa)->sdl_type != IFT_ETHER) {
+               return false;
+       }
+       src = LLADDR((struct sockaddr_dl*)sa);
+#else
+       src = ((struct sockaddr_ll*)sa)->sll_addr;
+#endif
+
+       memcpy(hwaddr, src, 6);
+       return true;
+}
+
+static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr)
+{
+       struct ifaddrs *ifas, *ifa;
        bool found;
 
        if (getifaddrs(&ifas) != 0) {
@@ -71,26 +89,17 @@ static bool get_hwaddr(uint8_t *hwaddr, const char *intf)
 
        for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
                if (!strcmp(ifa->ifa_name, intf)) {
-#ifdef NMRPFLASH_LINUX
-                       if (ifa->ifa_addr->sa_family != AF_PACKET) {
-                               continue;
-                       }
-                       src = ((struct sockaddr_ll*)ifa->ifa_addr)->sll_addr;
-#else
-                       if (ifa->ifa_addr->sa_family != AF_LINK) {
-                               continue;
+                       if (sockaddr_get_hwaddr(ifa->ifa_addr, hwaddr)) {
+                               found = true;
+                               break;
                        }
-                       src = LLADDR((struct sockaddr_dl*)ifa->ifa_addr);
-#endif
-                       memcpy(hwaddr, src, 6);
-                       found = true;
-                       break;
                }
        }
 
        freeifaddrs(ifas);
        return found;
 }
+
 #else
 
 void win_perror2(const char *msg, DWORD err)
@@ -110,7 +119,7 @@ void win_perror2(const char *msg, DWORD err)
        }
 }
 
-static bool get_hwaddr(uint8_t *hwaddr, const char *intf)
+static bool get_hwaddr_from_intf(const char *intf, uint8_t *hwaddr)
 {
        PIP_ADAPTER_INFO adapters, adapter;
        DWORD ret;
@@ -134,14 +143,9 @@ static bool get_hwaddr(uint8_t *hwaddr, const char *intf)
                                continue;
                        }
 
-#ifndef NMRPFLASH_WINDOWS
-                       if (!strcmp(intf, adapter->AdapterName))
-#else
                        /* Interface names from WinPcap are "\Device\NPF_{GUID}", while
                         * AdapterName from GetAdaptersInfo is just "{GUID}".*/
-                       if (strstr(intf, adapter->AdapterName))
-#endif
-                       {
+                       if (strstr(intf, adapter->AdapterName)) {
                                if (adapter->AddressLength == 6) {
                                        for (i = 0; i != 6; ++i) {
                                                hwaddr[i] = adapter->Address[i];
@@ -241,7 +245,6 @@ static const char *intf_get_pretty_name(const char *intf)
 }
 #endif
 
-
 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
 {
        return sock->hwaddr;
@@ -269,7 +272,8 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
 
        buf[0] = '\0';
 
-       sock->pcap = pcap_open_live(intf, BUFSIZ, 1, 1, buf);
+       sock->intf = intf;
+       sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
        if (!sock->pcap) {
                fprintf(stderr, "%s.\n", buf);
                goto cleanup_malloc;
@@ -285,7 +289,7 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
                goto cleanup_pcap;
        }
 
-       if (!get_hwaddr(sock->hwaddr, intf)) {
+       if (!get_hwaddr_from_intf(intf, sock->hwaddr)) {
                fprintf(stderr, "Failed to get MAC address of interface.\n");
                goto cleanup_malloc;
        }
@@ -319,7 +323,10 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
                goto cleanup_pcap;
        }
 
-       if ((err = pcap_setfilter(sock->pcap, &fp))) {
+       err = pcap_setfilter(sock->pcap, &fp);
+       pcap_freecode(&fp);
+
+       if (err) {
                pcap_perror(sock->pcap, "pcap_setfilter");
                goto cleanup_pcap;
        }
@@ -429,20 +436,29 @@ inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
        return 0;
 }
 
-static bool is_ethernet(const char *intf)
+static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
 {
-       pcap_t *pcap;
-       char errbuf[PCAP_ERRBUF_SIZE];
-       bool ret = false;
+#ifndef NMRPFLASH_WINDOWS
+       pcap_addr_t *addr;
+       int i;
 
-       if ((pcap = pcap_create(intf, errbuf))) {
-               if (pcap_activate(pcap) == 0) {
-                       ret = (pcap_datalink(pcap) == DLT_EN10MB);
+       for (addr = dev->addresses; addr; addr = addr->next) {
+               if (verbosity > 1) {
+                       printf("%s: sa_family=%d, sa_data={ ", dev->name,
+                                       addr->addr->sa_family);
+                       for (i = 0; i != sizeof(addr->addr->sa_data); ++i) {
+                               printf("%02x ", addr->addr->sa_data[i] & 0xff);
+                       }
+                       printf("}\n");
+               }
+
+               if (sockaddr_get_hwaddr(addr->addr, hwaddr)) {
+                       return true;
                }
-               pcap_close(pcap);
        }
+#endif
 
-       return ret;
+       return get_hwaddr_from_intf(dev->name, hwaddr);
 }
 
 int ethsock_list_all(void)
@@ -469,7 +485,7 @@ int ethsock_list_all(void)
                        continue;
                }
 
-               if (!is_ethernet(dev->name)) {
+               if (!get_hwaddr_from_pcap(dev, hwaddr)) {
                        if (verbosity) {
                                printf("%-15s  (not an ethernet device)\n",
                                                dev->name);
@@ -477,14 +493,6 @@ int ethsock_list_all(void)
                        continue;
                }
 
-               if (!get_hwaddr(hwaddr, dev->name)) {
-                       if (verbosity) {
-                               printf("%-15s  (failed to get hardware address)\n",
-                                               dev->name);
-                       }
-                       continue;
-               }
-
 #ifndef NMRPFLASH_WINDOWS
                printf("%-15s", dev->name);
 #else
@@ -530,3 +538,42 @@ int ethsock_list_all(void)
 
        return 0;
 }
+
+int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
+               void *arg)
+{
+       struct ethsock_ip_callback_args args;
+       pcap_if_t *devs, *dev;
+       pcap_addr_t *addr;
+       int status = 0;
+
+       if (x_pcap_findalldevs(&devs) != 0) {
+               return -1;
+       }
+
+       args.arg = arg;
+
+       for (dev = devs; dev; dev = dev->next) {
+               if (strcmp(sock->intf, dev->name)) {
+                       continue;
+               }
+
+               for (addr = dev->addresses; addr; addr = addr->next) {
+                       if (addr->addr->sa_family == AF_INET) {
+                               args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr;
+                               args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr;
+
+                               status = callback(&args);
+                               if (status <= 0) {
+                                       break;
+                               }
+                       }
+               }
+
+               break;
+       }
+
+       pcap_freealldevs(devs);
+
+       return status <= 0 ? status : 0;
+}