]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap-linux.c
Travis: Add .travis.yml (same as in version 1.4)
[libpcap] / pcap-linux.c
index 9fddadb6cf567ee9fa943ee605be465c9144d63d..e5c3afa7d86da2cc7a427444bb64cfd591299d90 100644 (file)
@@ -318,7 +318,7 @@ typedef int         socklen_t;
 /*
  * Prototypes for internal functions and methods.
  */
-static void map_arphrd_to_dlt(pcap_t *, int, int);
+static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int);
 #ifdef HAVE_PF_PACKET_SOCKETS
 static short int map_packet_type_to_sll_type(short int);
 #endif
@@ -2587,6 +2587,51 @@ map_packet_type_to_sll_type(short int sll_pkttype)
 }
 #endif
 
+static int
+is_wifi(int sock_fd
+#ifndef IW_MODE_MONITOR
+_U_
+#endif
+, const char *device)
+{
+       char *pathstr;
+       struct stat statb;
+#ifdef IW_MODE_MONITOR
+       char errbuf[PCAP_ERRBUF_SIZE];
+#endif
+
+       /*
+        * See if there's a sysfs wireless directory for it.
+        * If so, it's a wireless interface.
+        */
+       if (asprintf(&pathstr, "/sys/class/net/%s/wireless", device) == -1) {
+               /*
+                * Just give up here.
+                */
+               return 0;
+       }
+       if (stat(pathstr, &statb) == 0) {
+               free(pathstr);
+               return 1;
+       }
+       free(pathstr);
+
+#ifdef IW_MODE_MONITOR
+       /*
+        * OK, maybe it's not wireless, or maybe this kernel doesn't
+        * support sysfs.  Try the wireless extensions.
+        */
+       if (has_wext(sock_fd, device, errbuf) == 1) {
+               /*
+                * It supports the wireless extensions, so it's a Wi-Fi
+                * device.
+                */
+               return 1;
+       }
+#endif
+       return 0;
+}
+
 /*
  *  Linux uses the ARP hardware type to identify the type of an
  *  interface. pcap uses the DLT_xxx constants for this. This
@@ -2605,13 +2650,33 @@ map_packet_type_to_sll_type(short int sll_pkttype)
  *
  *  Sets the link type to -1 if unable to map the type.
  */
-static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
+static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
+                             const char *device, int cooked_ok)
 {
+       static const char cdma_rmnet[] = "cdma_rmnet";
+
        switch (arptype) {
 
        case ARPHRD_ETHER:
                /*
-                * This is (presumably) a real Ethernet capture; give it a
+                * For various annoying reasons having to do with DHCP
+                * software, some versions of Android give the mobile-
+                * phone-network interface an ARPHRD_ value of
+                * ARPHRD_ETHER, even though the packets supplied by
+                * that interface have no link-layer header, and begin
+                * with an IP header, so that the ARPHRD_ value should
+                * be ARPHRD_NONE.
+                *
+                * Detect those devices by checking the device name, and
+                * use DLT_RAW for them.
+                */
+               if (strncmp(device, cdma_rmnet, sizeof cdma_rmnet - 1) == 0) {
+                       handle->linktype = DLT_RAW;
+                       return;
+               }
+       
+               /*
+                * Is this a real Ethernet device?  If so, give it a
                 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
                 * that an application can let you choose it, in case you're
                 * capturing DOCSIS traffic that a Cisco Cable Modem
@@ -2620,21 +2685,27 @@ static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
                 * DOCSIS frames out on the wire inside the low-level
                 * Ethernet framing).
                 *
-                * XXX - are there any sorts of "fake Ethernet" that have
-                * ARPHRD_ETHER but that *shouldn't offer DLT_DOCSIS as
+                * XXX - are there any other sorts of "fake Ethernet" that
+                * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as
                 * a Cisco CMTS won't put traffic onto it or get traffic
                 * bridged onto it?  ISDN is handled in "activate_new()",
-                * as we fall back on cooked mode there; are there any
+                * as we fall back on cooked mode there, and we use
+                * is_wifi() to check for 802.11 devices; are there any
                 * others?
                 */
-               handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
-               /*
-                * If that fails, just leave the list empty.
-                */
-               if (handle->dlt_list != NULL) {
-                       handle->dlt_list[0] = DLT_EN10MB;
-                       handle->dlt_list[1] = DLT_DOCSIS;
-                       handle->dlt_count = 2;
+               if (!is_wifi(sock_fd, device)) {
+                       /*
+                        * It's not a Wi-Fi device; offer DOCSIS.
+                        */
+                       handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
+                       /*
+                        * If that fails, just leave the list empty.
+                        */
+                       if (handle->dlt_list != NULL) {
+                               handle->dlt_list[0] = DLT_EN10MB;
+                               handle->dlt_list[1] = DLT_DOCSIS;
+                               handle->dlt_count = 2;
+                       }
                }
                /* FALLTHROUGH */
 
@@ -3035,7 +3106,7 @@ activate_new(pcap_t *handle)
                        close(sock_fd);
                        return arptype;
                }
-               map_arphrd_to_dlt(handle, arptype, 1);
+               map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1);
                if (handle->linktype == -1 ||
                    handle->linktype == DLT_LINUX_SLL ||
                    handle->linktype == DLT_LINUX_IRDA ||
@@ -3980,7 +4051,7 @@ pcap_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback,
                if (tp_mac + tp_snaplen > handle->bufsize) {
                        snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 
                                "corrupted frame on kernel ring mac "
-                               "offset %d + caplen %d > frame len %d", 
+                               "offset %u + caplen %u > frame len %d", 
                                tp_mac, tp_snaplen, handle->bufsize);
                        return -1;
                }
@@ -5152,7 +5223,7 @@ activate_old(pcap_t *handle)
         * Try to find the DLT_ type corresponding to that
         * link-layer type.
         */
-       map_arphrd_to_dlt(handle, arptype, 0);
+       map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0);
        if (handle->linktype == -1) {
                snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "unknown arptype %d", arptype);