#include <fcntl.h>
#include <string.h>
#include <limits.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/mman.h>
#include <linux/if.h>
+#include <linux/if_packet.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if_arp.h>
/*
* 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
continue;
aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
- if (aux->tp_vlan_tci == 0)
+#if defined(TP_STATUS_VLAN_VALID)
+ if ((aux->tp_vlan_tci == 0) && !(aux->tp_status & TP_STATUS_VLAN_VALID))
+#else
+ if (aux->tp_vlan_tci == 0) /* this is ambigious but without the
+ TP_STATUS_VLAN_VALID flag, there is
+ nothing that we can do */
+#endif
continue;
len = packet_len > iov.iov_len ? iov.iov_len : packet_len;
continue;
/*
- * Ignore plain files.
+ * Ignore plain files; they do not have subdirectories
+ * and thus have no attributes.
*/
if (ent->d_type == DT_REG)
continue;
/*
- * Is there a "subsystem" file under that name?
+ * Is there an "ifindex" file under that name?
* (We don't care whether it's a directory or
* a symlink; older kernels have directories
* for devices, newer kernels have symlinks to
* directories.)
*/
snprintf(subsystem_path, sizeof subsystem_path,
- "/sys/class/net/%s/subsystem", ent->d_name);
+ "/sys/class/net/%s/ifindex", ent->d_name);
if (lstat(subsystem_path, &statb) != 0) {
- /* Stat failed, ignore */
+ /*
+ * Stat failed. Either there was an error
+ * other than ENOENT, and we don't know if
+ * this is an interface, or it's ENOENT,
+ * and either some part of "/sys/class/net/{if}"
+ * disappeared, in which case it probably means
+ * the interface disappeared, or there's no
+ * "ifindex" file, which means it's not a
+ * network interface.
+ */
continue;
}
}
#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
*
* 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
* 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 */
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 ||
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;
}
}
#ifdef HAVE_TPACKET2
- if (handle->md.tp_version == TPACKET_V2 && h.h2->tp_vlan_tci &&
+ if ((handle->md.tp_version == TPACKET_V2) &&
+#if defined(TP_STATUS_VLAN_VALID)
+ (h.h2->tp_vlan_tci || (h.h2->tp_status & TP_STATUS_VLAN_VALID)) &&
+#else
+ h.h2->tp_vlan_tci &&
+#endif
handle->md.vlan_offset != -1 &&
tp_snaplen >= (unsigned int) handle->md.vlan_offset) {
struct vlan_tag *tag;
* 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);