Update README.md
[oweals/nmrpflash.git] / ethsock.c
index de8f683b1ab6fe5296516a2da45c5baf2888ea5a..d754653ca11e48ab49e0e7da02315516b725d105 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>
+#else
+#define NMRPFLASH_AF_PACKET AF_LINK
+#include <net/if_types.h>
 #endif
 #endif
 
@@ -36,6 +38,14 @@ struct ethsock
        uint8_t hwaddr[6];
 };
 
+const char *mac_to_str(uint8_t *mac)
+{
+       static char buf[18];
+       snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+       return buf;
+}
+
 static int x_pcap_findalldevs(pcap_if_t **devs)
 {
        char errbuf[PCAP_ERRBUF_SIZE];
@@ -48,10 +58,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*)addr)->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) {
@@ -63,26 +93,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)
@@ -102,7 +123,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;
@@ -126,14 +147,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];
@@ -169,7 +185,7 @@ static const char *intf_alias_to_wpcap(const char *intf)
                return NULL;
        }
 
-       for (dev = devs; dev; dev = dev->next) {
+       for (dev = devs; dev; dev = dev->next, ++i) {
                if (i == dev_num) {
                        if (verbosity) {
                                printf("%s%u: %s\n", NMRPFLASH_NETALIAS_PREFIX, i, dev->name);
@@ -233,7 +249,6 @@ static const char *intf_get_pretty_name(const char *intf)
 }
 #endif
 
-
 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
 {
        return sock->hwaddr;
@@ -277,7 +292,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;
        }
@@ -294,16 +309,27 @@ struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
                fprintf(stderr, "No event handle available.\n");
                goto cleanup_pcap;
        }
+
+       err = pcap_setmintocopy(sock->pcap, 1);
+       if (err) {
+               pcap_perror(sock->pcap, "pcap_setmintocopy");
+               goto cleanup_pcap;
+       }
 #endif
 
-       snprintf(buf, sizeof(buf), "ether proto 0x%04x", protocol);
+       snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
+                       protocol, mac_to_str(sock->hwaddr));
+
        err = pcap_compile(sock->pcap, &fp, buf, 0, 0);
        if (err) {
                pcap_perror(sock->pcap, "pcap_compile");
                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;
        }
@@ -413,20 +439,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)
@@ -434,7 +469,7 @@ int ethsock_list_all(void)
        pcap_if_t *devs, *dev;
        pcap_addr_t *addr;
        uint8_t hwaddr[6];
-       unsigned dev_num = 0;
+       unsigned dev_num = 0, dev_ok = 0;
 #ifdef NMRPFLASH_WINDOWS
        const char *pretty;
 #endif
@@ -445,18 +480,17 @@ int ethsock_list_all(void)
 
        memset(hwaddr, 0, 6);
 
-       for (dev = devs; dev; dev = dev->next) {
-               if (!is_ethernet(dev->name) || dev->flags & PCAP_IF_LOOPBACK) {
+       for (dev = devs; dev; dev = dev->next, ++dev_num) {
+               if (dev->flags & PCAP_IF_LOOPBACK) {
                        if (verbosity) {
-                               printf("%s  (not an ethernet device)\n",
-                                               dev->name);
+                               printf("%-15s  (loopback device)\n", dev->name);
                        }
                        continue;
                }
 
-               if (!get_hwaddr(hwaddr, dev->name)) {
+               if (!get_hwaddr_from_pcap(dev, hwaddr)) {
                        if (verbosity) {
-                               printf("%s  (failed to get hardware address)\n",
+                               printf("%-15s  (not an ethernet device)\n",
                                                dev->name);
                        }
                        continue;
@@ -487,8 +521,7 @@ int ethsock_list_all(void)
                        printf("  %-15s", "0.0.0.0");
                }
 
-               printf("  %02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0], hwaddr[1],
-                               hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
+               printf("  %s", mac_to_str(hwaddr));
 
 #ifdef NMRPFLASH_WINDOWS
                if (pretty) {
@@ -499,10 +532,10 @@ int ethsock_list_all(void)
 
 #endif
                printf("\n");
-               ++dev_num;
+               ++dev_ok;
        }
 
-       if (!dev_num) {
+       if (!dev_ok) {
                printf("No suitable network interfaces found.\n");
        }