#include <net/if_arp.h>
#include <poll.h>
#include <dirent.h>
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
#include "pcap-int.h"
#include "pcap/sll.h"
#include "pcap/vlan.h"
-#ifdef HAVE_SYS_EVENTFD_H
-#include <sys/eventfd.h>
-#endif
-
+#include "diag-control.h"
/*
* If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET
static int pcap_can_set_rfmon_linux(pcap_t *);
static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
-static int pcap_inject_linux(pcap_t *, const void *, size_t);
+static int pcap_inject_linux(pcap_t *, const void *, int);
static int pcap_stats_linux(pcap_t *, struct pcap_stat *);
static int pcap_setfilter_linux(pcap_t *, struct bpf_program *);
static int pcap_setdirection_linux(pcap_t *, pcap_direction_t);
genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
0, NL80211_CMD_NEW_INTERFACE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+DIAG_OFF_NARROWING
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
+DIAG_ON_NARROWING
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
err = nl_send_auto_complete(state->nl_sock, msg);
char buffer[512];
char * bufptr;
FILE * file;
- int field_to_convert = 3, if_name_sz = strlen(if_name);
+ int field_to_convert = 3;
+ size_t if_name_sz = strlen(if_name);
long int dropped_pkts = 0;
file = fopen("/proc/net/dev", "r");
#ifdef HAVE_TPACKET3
struct utsname utsname;
char *version_component, *endp;
- int major, minor;
+ long major, minor;
int broken_tpacket_v3 = 1;
/*
#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
socklen_t fromlen;
#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
- int packet_len, caplen;
+ ssize_t packet_len;
+ int caplen;
struct pcap_pkthdr pcap_header;
struct bpf_aux_data aux_data;
if (handlep->vlan_offset != -1) {
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
struct tpacket_auxdata *aux;
- unsigned int len;
+ size_t len;
struct vlan_tag *tag;
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
continue;
}
- len = (u_int)packet_len > iov.iov_len ? iov.iov_len : (u_int)packet_len;
- if (len < (u_int)handlep->vlan_offset)
+ len = (size_t)packet_len > iov.iov_len ? iov.iov_len : (u_int)packet_len;
+ if (len < (size_t)handlep->vlan_offset)
break;
/*
* filter to the kernel.
*/
- caplen = packet_len;
+ caplen = (int)packet_len;
if (caplen > handle->snapshot)
caplen = handle->snapshot;
/* Run the packet filter if not using kernel filter */
if (handlep->filter_in_userland && handle->fcode.bf_insns) {
- if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp,
- packet_len, caplen, &aux_data) == 0) {
+ if (pcap_filter_with_aux_data(handle->fcode.bf_insns, bp,
+ (int)packet_len, caplen, &aux_data) == 0) {
/* rejected by filter */
return 0;
}
}
pcap_header.caplen = caplen;
- pcap_header.len = packet_len;
+ pcap_header.len = (bpf_u_int32)packet_len;
/*
* Count the packet.
}
static int
-pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
+pcap_inject_linux(pcap_t *handle, const void *buf, int size)
{
struct pcap_linux *handlep = handle->priv;
int ret;
}
#endif
- ret = send(handle->fd, buf, size, 0);
+ ret = (int)send(handle->fd, buf, size, 0);
if (ret == -1) {
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
errno, "send");
/*
* Get the status field of the ring buffer frame at a specified offset.
*/
-static inline int
+static inline u_int
pcap_get_ring_frame_status(pcap_t *handle, int offset)
{
struct pcap_linux *handlep = handle->priv;
h.raw = RING_GET_FRAME_AT(handle, offset);
switch (handlep->tp_version) {
case TPACKET_V1:
- return (h.h1->tp_status);
+ /*
+ * This is an unsigned long, but only the lower 32
+ * bits are used.
+ */
+ return (u_int)(h.h1->tp_status);
break;
case TPACKET_V1_64:
- return (h.h1_64->tp_status);
+ /*
+ * This is an unsigned long in the kernel, which is 64-bit,
+ * but only the lower 32 bits are used.
+ */
+ return (u_int)(h.h1_64->tp_status);
break;
#ifdef HAVE_TPACKET2
case TPACKET_V2:
aux_data.vlan_tag_present = tp_vlan_tci_valid;
aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
- if (bpf_filter_with_aux_data(handle->fcode.bf_insns,
- bp,
- tp_len,
- snaplen,
- &aux_data) == 0)
+ if (pcap_filter_with_aux_data(handle->fcode.bf_insns,
+ bp,
+ tp_len,
+ snaplen,
+ &aux_data) == 0)
return 0;
}
* if SIOCETHTOOL isn't defined, or we don't have any #defines for any
* of the types of offloading, there's nothing we can do to check, so
* we just say "no, we don't".
+ *
+ * We treat EOPNOTSUPP, EINVAL and, if eperm_ok is true, EPERM as
+ * indications that the operation isn't supported. We do EPERM
+ * weirdly because the SIOCETHTOOL code in later kernels 1) doesn't
+ * support ETHTOOL_GUFO, 2) also doesn't include it in the list
+ * of ethtool operations that don't require CAP_NET_ADMIN privileges,
+ * and 3) does the "is this permitted" check before doing the "is
+ * this even supported" check, so it fails with "this is not permitted"
+ * rather than "this is not even supported". To work around this
+ * annoyance, we only treat EPERM as an error for the first feature,
+ * and assume that they all do the same permission checks, so if the
+ * first one is allowed all the others are allowed if supported.
*/
#if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO))
static int
-iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname)
+iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname,
+ int eperm_ok)
{
struct ifreq ifr;
struct ethtool_value eval;
eval.data = 0;
ifr.ifr_data = (caddr_t)&eval;
if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) {
- if (errno == EOPNOTSUPP || errno == EINVAL) {
+ if (errno == EOPNOTSUPP || errno == EINVAL ||
+ (errno == EPERM && eperm_ok)) {
/*
* OK, let's just return 0, which, in our
* case, either means "no, what we're asking
return eval.data;
}
+/*
+ * XXX - it's annoying that we have to check for offloading at all, but,
+ * given that we have to, it's still annoying that we have to check for
+ * particular types of offloading, especially that shiny new types of
+ * offloading may be added - and, worse, may not be checkable with
+ * a particular ETHTOOL_ operation; ETHTOOL_GFEATURES would, in
+ * theory, give those to you, but the actual flags being used are
+ * opaque (defined in a non-uapi header), and there doesn't seem to
+ * be any obvious way to ask the kernel what all the offloading flags
+ * are - at best, you can ask for a set of strings(!) to get *names*
+ * for various flags. (That whole mechanism appears to have been
+ * designed for the sole purpose of letting ethtool report flags
+ * by name and set flags by name, with the names having no semantics
+ * ethtool understands.)
+ */
static int
iface_get_offload(pcap_t *handle)
{
int ret;
#ifdef ETHTOOL_GTSO
- ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO", 0);
if (ret == -1)
return -1;
if (ret)
return 1; /* TCP segmentation offloading on */
#endif
-#ifdef ETHTOOL_GUFO
- ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO");
- if (ret == -1)
- return -1;
- if (ret)
- return 1; /* UDP fragmentation offloading on */
-#endif
-
#ifdef ETHTOOL_GGSO
/*
* XXX - will this cause large unsegmented packets to be
* handed to PF_PACKET sockets on transmission? If not,
* this need not be checked.
*/
- ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO", 0);
if (ret == -1)
return -1;
if (ret)
#endif
#ifdef ETHTOOL_GFLAGS
- ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS", 0);
if (ret == -1)
return -1;
if (ret & ETH_FLAG_LRO)
* handed to PF_PACKET sockets on receipt? If not,
* this need not be checked.
*/
- ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO", 0);
if (ret == -1)
return -1;
if (ret)
return 1; /* generic (large) receive offloading on */
#endif
+#ifdef ETHTOOL_GUFO
+ /*
+ * Do this one last, as support for it was removed in later
+ * kernels, and it fails with EPERM on those kernels rather
+ * than with EOPNOTSUPP (see explanation in comment for
+ * iface_ethtool_flag_ioctl()).
+ */
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO", 1);
+ if (ret == -1)
+ return -1;
+ if (ret)
+ return 1; /* UDP fragmentation offloading on */
+#endif
+
return 0;
}
#else /* SIOCETHTOOL */