static int enter_rfmon_mode(pcap_t *handle, int sock_fd,
const char *device);
#endif /* HAVE_PF_PACKET_SOCKETS */
+#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
+static int iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf);
+#endif
static int iface_get_offload(pcap_t *handle);
static int iface_bind_old(int fd, const char *device, char *ebuf);
handle->activate_op = pcap_activate_linux;
handle->can_set_rfmon_op = pcap_can_set_rfmon_linux;
+
#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
/*
- * We claim that we support:
- *
- * software time stamps, with no details about their precision;
- * hardware time stamps, synced to the host time;
- * hardware time stamps, not synced to the host time.
- *
- * XXX - we can't ask a device whether it supports
- * hardware time stamps, so we just claim all devices do.
+ * See what time stamp types we support.
*/
- handle->tstamp_type_count = 3;
- handle->tstamp_type_list = malloc(3 * sizeof(u_int));
- if (handle->tstamp_type_list == NULL) {
+ if (iface_ethtool_get_ts_info(handle, ebuf) == -1) {
free(handle);
return NULL;
}
- handle->tstamp_type_list[0] = PCAP_TSTAMP_HOST;
- handle->tstamp_type_list[1] = PCAP_TSTAMP_ADAPTER;
- handle->tstamp_type_list[2] = PCAP_TSTAMP_ADAPTER_UNSYNCED;
#endif
#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
handle->tstamp_precision_count = 2;
handle->tstamp_precision_list = malloc(2 * sizeof(u_int));
if (handle->tstamp_precision_list == NULL) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
if (handle->tstamp_type_list != NULL)
free(handle->tstamp_type_list);
free(handle);
* Now configure the monitor interface up.
*/
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't get flags for %s: %s", device,
/*
* Attempt to get the current mode.
*/
- strncpy(ireq.ifr_ifrn.ifrn_name, handle->opt.source,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.source,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) {
/*
* Well, we got the mode; assume we can set it.
* in 2.0[.x] kernels.
*/
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, handlep->device,
+ strlcpy(ifr.ifr_name, handlep->device,
sizeof(ifr.ifr_name));
if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
fprintf(stderr,
*/
oldflags = 0;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, handlep->device,
+ strlcpy(ifr.ifr_name, handlep->device,
sizeof(ifr.ifr_name));
if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) {
if (ifr.ifr_flags & IFF_UP) {
/*
* Now restore the mode.
*/
- strncpy(ireq.ifr_ifrn.ifrn_name, handlep->device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1]
- = 0;
ireq.u.mode = handlep->oldmode;
if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
/*
{
struct pcap_linux *handlep = handle->priv;
const char *device;
+ struct ifreq ifr;
int status = 0;
+ int ret;
device = handle->opt.source;
+ /*
+ * Make sure the name we were handed will fit into the ioctls we
+ * might perform on the device; if not, return a "No such device"
+ * indication, as the Linux kernel shouldn't support creating
+ * a device whose name won't fit into those ioctls.
+ *
+ * "Will fit" means "will fit, complete with a null terminator",
+ * so if the length, which does *not* include the null terminator,
+ * is greater than *or equal to* the size of the field into which
+ * we'll be copying it, that won't fit.
+ */
+ if (strlen(device) >= sizeof(ifr.ifr_name)) {
+ status = PCAP_ERROR_NO_SUCH_DEVICE;
+ goto fail;
+ }
+
handle->inject_op = pcap_inject_linux;
handle->setfilter_op = pcap_setfilter_linux;
handle->setdirection_op = pcap_setdirection_linux;
* to be compatible with older kernels for a while so we are
* trying both methods with the newer method preferred.
*/
- status = activate_new(handle);
- if (status < 0) {
+ ret = activate_new(handle);
+ if (ret < 0) {
/*
* Fatal error with the new way; just fail.
- * status has the error return; if it's PCAP_ERROR,
+ * ret has the error return; if it's PCAP_ERROR,
* handle->errbuf has been set appropriately.
*/
+ status = ret;
goto fail;
}
- if (status == 1) {
+ if (ret == 1) {
/*
* Success.
* Try to use memory-mapped access.
/*
* We failed to set up to use it, or the kernel
* supports it, but we failed to enable it.
- * status has been set to the error status to
+ * ret has been set to the error status to
* return and, if it's PCAP_ERROR, handle->errbuf
* contains the error message.
*/
+ status = ret;
goto fail;
}
}
- else if (status == 0) {
+ else if (ret == 0) {
/* Non-fatal error; try old way */
- if ((status = activate_old(handle)) != 1) {
+ if ((ret = activate_old(handle)) != 1) {
/*
* Both methods to open the packet socket failed.
* Tidy up and report our failure (handle->errbuf
* is expected to be set by the functions above).
*/
+ status = ret;
goto fail;
}
}
/*
* We set up the socket, but not with memory-mapped access.
*/
- status = 0;
if (handle->opt.buffer_size != 0) {
/*
* Set the socket buffer size to the specified value.
int packet_len, caplen;
struct pcap_pkthdr pcap_header;
+ struct bpf_aux_data aux_data;
#ifdef HAVE_PF_PACKET_SOCKETS
/*
* If this is a cooked device, leave extra room for a
tag->vlan_tpid = htons(VLAN_TPID(aux, aux));
tag->vlan_tci = htons(aux->tp_vlan_tci);
+ /* store vlan tci to bpf_aux_data struct for userland bpf filter */
+#if defined(TP_STATUS_VLAN_VALID)
+ aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff;
+ aux_data.vlan_tag_present = (aux->tp_status & TP_STATUS_VLAN_VALID);
+#endif
packet_len += VLAN_TAG_LEN;
}
}
*
* We currently handle this by making a copy of the filter
* program, fixing all "ret" instructions with non-zero
- * operands to have an operand of 65535 so that the filter
- * doesn't truncate the packet, and supplying that modified
+ * operands to have an operand of MAXIMUM_SNAPLEN so that the
+ * filter doesn't truncate the packet, and supplying that modified
* filter to the kernel.
*/
/* Run the packet filter if not using kernel filter */
if (handlep->filter_in_userland && handle->fcode.bf_insns) {
- if (bpf_filter(handle->fcode.bf_insns, bp,
- packet_len, caplen) == 0)
- {
+ if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp,
+ packet_len, caplen, &aux_data) == 0) {
/* rejected by filter */
return 0;
}
/*
* Get the flags for this interface.
*/
- strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
+ strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
if (errno == ENXIO || errno == ENODEV)
return (0); /* device doesn't actually exist - ignore it */
/*
* Add the "any" device.
*/
- if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)
+ if (pcap_add_if(alldevsp, "any", IFF_UP|IFF_RUNNING,
+ any_descr, errbuf) < 0)
return (-1);
return (0);
if (!handle)
return -1;
if (!filter) {
- strncpy(handle->errbuf, "setfilter: No filter specified",
+ strlcpy(handle->errbuf, "setfilter: No filter specified",
PCAP_ERRBUF_SIZE);
return -1;
}
* of different size. Pointed out by Sebastian
*
* Oh, and we also need to fix it up so that all "ret"
- * instructions with non-zero operands have 65535 as the
- * operand if we're not capturing in memory-mapped modee,
- * and so that, if we're in cooked mode, all memory-reference
- * instructions use special magic offsets in references to
- * the link-layer header and assume that the link-layer
- * payload begins at 0; "fix_program()" will do that.
+ * instructions with non-zero operands have MAXIMUM_SNAPLEN
+ * as the operand if we're not capturing in memory-mapped
+ * mode, and so that, if we're in cooked mode, all memory-
+ * reference instructions use special magic offsets in
+ * references to the link-layer header and assume that the
+ * link-layer payload begins at 0; "fix_program()" will do
+ * that.
*/
switch (fix_program(handle, &fcode, is_mmapped)) {
* calling "pcap_setfilter()". Otherwise, the kernel filter may
* filter out packets that would pass the new userland filter.
*/
- if (handlep->filter_in_userland)
- reset_kernel_filter(handle);
+ if (handlep->filter_in_userland) {
+ if (reset_kernel_filter(handle) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't remove kernel filter: %s",
+ pcap_strerror(errno));
+ err = -2; /* fatal error */
+ }
+ }
/*
* Free up the copy of the filter that was made by "fix_program()".
#endif
int err = 0;
struct packet_mreq mr;
+#ifdef SO_BPF_EXTENSIONS
+ int bpf_extensions;
+ socklen_t len = sizeof(bpf_extensions);
+#endif
/*
* Open a socket with protocol family packet. If the
/*
* It doesn't support monitor mode.
*/
+ close(sock_fd);
return PCAP_ERROR_RFMON_NOTSUP;
}
break;
}
- /* Save the socket FD in the pcap structure */
- handle->fd = sock_fd;
-
#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
int nsec_tstamps = 1;
- if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) {
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS");
+ close(sock_fd);
return PCAP_ERROR;
}
}
#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
+ /*
+ * We've succeeded. Save the socket FD in the pcap structure.
+ */
+ handle->fd = sock_fd;
+
+#ifdef SO_BPF_EXTENSIONS
+ /*
+ * Can we generate special code for VLAN checks?
+ * (XXX - what if we need the special code but it's not supported
+ * by the OS? Is that possible?)
+ */
+ if (getsockopt(sock_fd, SOL_SOCKET, SO_BPF_EXTENSIONS,
+ &bpf_extensions, &len) == 0) {
+ if (bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT) {
+ /*
+ * Yes, we can. Request that we do so.
+ */
+ handle->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING;
+ }
+ }
+#endif /* SO_BPF_EXTENSIONS */
+
return 1;
#else /* HAVE_PF_PACKET_SOCKETS */
- strncpy(ebuf,
+ strlcpy(ebuf,
"New packet capturing interface not supported by build "
"environment", PCAP_ERRBUF_SIZE);
return 0;
* We pick a "frame" size of 128K to leave enough
* room for at least one reasonably-sized packet
* in the "frame". */
- req.tp_frame_size = 131072;
+ req.tp_frame_size = MAXIMUM_SNAPLEN;
req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size;
break;
#endif
+ default:
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Internal error: unknown TPACKET_ value %u",
+ handlep->tp_version);
+ *status = PCAP_ERROR;
+ return -1;
}
/* compute the minumum block size that will handle this frame.
hwconfig.rx_filter = HWTSTAMP_FILTER_ALL;
memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, handle->opt.source);
+ strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
ifr.ifr_data = (void *)&hwconfig;
if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) {
/* tell the kernel to destroy the ring*/
struct tpacket_req req;
memset(&req, 0, sizeof(req));
- setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
+ /* do not test for setsockopt failure, as we can't recover from any error */
+ (void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
(void *) &req, sizeof(req));
/* if ring is mapped, unmap it*/
if (handlep->mmapbuf) {
/* do not test for mmap failure, as we can't recover from any error */
- munmap(handlep->mmapbuf, handlep->mmapbuflen);
+ (void)munmap(handlep->mmapbuf, handlep->mmapbuflen);
handlep->mmapbuf = NULL;
}
}
{
struct pcap_linux *handlep = p->priv;
+ /*
+ * Set the file descriptor to non-blocking mode, as we use
+ * it for sending packets.
+ */
+ if (pcap_setnonblock_fd(p, nonblock, errbuf) == -1)
+ return -1;
+
/*
* Map each value to their corresponding negation to
* preserve the timeout value provided with pcap_set_timeout.
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;
}
* the filter when the ring became empty, but it can possibly
* happen a lot later... */
bp = frame + tp_mac;
- if (handlep->filter_in_userland && handle->fcode.bf_insns &&
- (bpf_filter(handle->fcode.bf_insns, bp,
- tp_len, tp_snaplen) == 0))
- return 0;
-
- sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen);
- if (!linux_check_direction(handle, sll))
- return 0;
-
- /* get required packet info from ring header */
- pcaphdr.ts.tv_sec = tp_sec;
- pcaphdr.ts.tv_usec = tp_usec;
- pcaphdr.caplen = tp_snaplen;
- pcaphdr.len = tp_len;
/* if required build in place the sll header*/
+ sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen);
if (handlep->cooked) {
struct sll_header *hdrp;
*/
bp -= SLL_HDR_LEN;
- /*/*
+ /*
* Let's make sure that's past the end of
* the tpacket header, i.e. >=
* ((u_char *)thdr + TPACKET_HDRLEN), so we
hdrp->sll_halen = htons(sll->sll_halen);
memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN);
hdrp->sll_protocol = sll->sll_protocol;
+ }
+ if (handlep->filter_in_userland && handle->fcode.bf_insns) {
+ struct bpf_aux_data aux_data;
+
+ aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
+ aux_data.vlan_tag_present = tp_vlan_tci_valid;
+
+ if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp,
+ tp_len, tp_snaplen, &aux_data) == 0)
+ return 0;
+ }
+
+ if (!linux_check_direction(handle, sll))
+ return 0;
+
+ /* get required packet info from ring header */
+ pcaphdr.ts.tv_sec = tp_sec;
+ pcaphdr.ts.tv_usec = tp_usec;
+ pcaphdr.caplen = tp_snaplen;
+ pcaphdr.len = tp_len;
+
+ /* if required build in place the sll header*/
+ if (handlep->cooked) {
/* update packet len */
pcaphdr.caplen += SLL_HDR_LEN;
pcaphdr.len += SLL_HDR_LEN;
int pkts = 0;
int ret;
+again:
if (handlep->current_packet == NULL) {
/* wait for frames availability.*/
ret = pcap_wait_for_frames_mmap(handle);
}
}
h.raw = pcap_get_ring_frame(handle, TP_STATUS_USER);
- if (!h.raw)
+ if (!h.raw) {
+ if (pkts == 0 && handlep->timeout == 0) {
+ /* Block until we see a packet. */
+ goto again;
+ }
return pkts;
+ }
/* non-positive values of max_packets are used to require all
* packets currently available in the ring */
return PCAP_ERROR_BREAK;
}
}
+ if (pkts == 0 && handlep->timeout == 0) {
+ /* Block until we see a packet. */
+ goto again;
+ }
return pkts;
}
#endif /* HAVE_TPACKET3 */
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
{
struct iwreq ireq;
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0)
return 1; /* yes */
snprintf(ebuf, PCAP_ERRBUF_SIZE,
* return EOPNOTSUPP.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
ireq.u.data.pointer = (void *)args;
ireq.u.data.length = 0;
ireq.u.data.flags = 0;
/*
* Get the old mode.
*/
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) {
/*
* We probably won't be able to set the mode, either.
* If it fails, just fall back on SIOCSIWMODE.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
ireq.u.data.length = 1; /* 1 argument */
args[0] = 3; /* request Prism header */
- memcpy(ireq.u.name, args, IFNAMSIZ);
+ memcpy(ireq.u.name, args, sizeof (int));
if (ioctl(sock_fd, cmd, &ireq) != -1) {
/*
* Success.
* might get EBUSY.
*/
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't get flags: %s", device, strerror(errno));
/*
* Then turn monitor mode on.
*/
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
ireq.u.mode = IW_MODE_MONITOR;
if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) {
/*
* Try to select the radiotap header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 3; /* request radiotap header */
memcpy(ireq.u.name, args, sizeof (int));
if (ioctl(sock_fd, cmd, &ireq) != -1)
* That failed. Try to select the AVS header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 2; /* request AVS header */
memcpy(ireq.u.name, args, sizeof (int));
if (ioctl(sock_fd, cmd, &ireq) != -1)
* That failed. Try to select the Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 1; /* request Prism header */
memcpy(ireq.u.name, args, sizeof (int));
ioctl(sock_fd, cmd, &ireq);
* Select the Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 3; /* request Prism header */
memcpy(ireq.u.name, args, sizeof (int));
ioctl(sock_fd, cmd, &ireq);
* Get the current channel.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: SIOCGIWFREQ: %s", device,
* current value.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 1; /* request Prism header */
args[1] = channel; /* set channel */
memcpy(ireq.u.name, args, 2*sizeof (int));
* Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 0; /* disallow transmitting */
memcpy(ireq.u.name, args, sizeof (int));
ioctl(sock_fd, cmd, &ireq);
* Force the Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 1; /* request Prism header */
memcpy(ireq.u.name, args, sizeof (int));
ioctl(sock_fd, cmd, &ireq);
* Force the Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
ireq.u.data.length = 1; /* 1 argument */
ireq.u.data.pointer = "1";
ireq.u.data.flags = 0;
* Force the Prism header.
*/
memset(&ireq, 0, sizeof ireq);
- strncpy(ireq.ifr_ifrn.ifrn_name, device,
+ strlcpy(ireq.ifr_ifrn.ifrn_name, device,
sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
args[0] = 1; /* request Prism header */
memcpy(ireq.u.name, args, sizeof (int));
ioctl(sock_fd, cmd, &ireq);
return 0;
}
+#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
+/*
+ * Map SOF_TIMESTAMPING_ values to PCAP_TSTAMP_ values.
+ */
+static const struct {
+ int soft_timestamping_val;
+ int pcap_tstamp_val;
+} sof_ts_type_map[3] = {
+ { SOF_TIMESTAMPING_SOFTWARE, PCAP_TSTAMP_HOST },
+ { SOF_TIMESTAMPING_SYS_HARDWARE, PCAP_TSTAMP_ADAPTER },
+ { SOF_TIMESTAMPING_RAW_HARDWARE, PCAP_TSTAMP_ADAPTER_UNSYNCED }
+};
+#define NUM_SOF_TIMESTAMPING_TYPES (sizeof sof_ts_type_map / sizeof sof_ts_type_map[0])
+
+static void
+iface_set_default_ts_types(pcap_t *handle)
+{
+ int i;
+
+ handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES;
+ handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int));
+ for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++)
+ handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val;
+}
+
+#ifdef ETHTOOL_GET_TS_INFO
+/*
+ * Get a list of time stamping capabilities.
+ */
+static int
+iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf)
+{
+ int fd;
+ struct ifreq ifr;
+ struct ethtool_ts_info info;
+ int num_ts_types;
+ int i, j;
+
+ /*
+ * This doesn't apply to the "any" device; you have to ask
+ * specific devices for their capabilities, so just default
+ * to saying we support all of them.
+ */
+ if (strcmp(handle->opt.source, "any") == 0) {
+ iface_set_default_ts_types(handle);
+ return 0;
+ }
+
+ /*
+ * Create a socket from which to fetch time stamping capabilities.
+ */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO): %s", pcap_strerror(errno));
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
+ memset(&info, 0, sizeof(info));
+ info.cmd = ETHTOOL_GET_TS_INFO;
+ ifr.ifr_data = (caddr_t)&info;
+ if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) {
+ close(fd);
+ if (errno == EOPNOTSUPP || errno == EINVAL) {
+ /*
+ * OK, let's just return all the possible time
+ * stamping types.
+ */
+ iface_set_default_ts_types(handle);
+ return 0;
+ }
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "%s: SIOCETHTOOL(ETHTOOL_GET_TS_INFO) ioctl failed: %s", handle->opt.source,
+ strerror(errno));
+ return -1;
+ }
+ close(fd);
+
+ num_ts_types = 0;
+ for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) {
+ if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val)
+ num_ts_types++;
+ }
+ handle->tstamp_type_count = num_ts_types;
+ if (num_ts_types != 0) {
+ handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int));
+ for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) {
+ if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) {
+ handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val;
+ j++;
+ }
+ }
+ } else
+ handle->tstamp_type_list = NULL;
+
+ return 0;
+}
+#else /* ETHTOOL_GET_TS_INFO */
+static int
+iface_ethtool_get_ts_info(pcap_t *handle, char *ebuf _U_)
+{
+ /*
+ * We don't have an ioctl to use to ask what's supported,
+ * so say we support everything.
+ */
+ iface_set_default_ts_types(handle);
+ return 0;
+}
+#endif /* ETHTOOL_GET_TS_INFO */
+
+#endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */
+
/*
* Find out if we have any form of fragmentation/reassembly offloading.
*
*/
#if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO))
static int
-iface_ethtool_ioctl(pcap_t *handle, int cmd, const char *cmdname)
+iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname)
{
struct ifreq ifr;
struct ethtool_value eval;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
eval.cmd = cmd;
eval.data = 0;
ifr.ifr_data = (caddr_t)&eval;
return 0;
}
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "%s: SIOETHTOOL(%s) ioctl failed: %s", handle->opt.source,
+ "%s: SIOCETHTOOL(%s) ioctl failed: %s", handle->opt.source,
cmdname, strerror(errno));
return -1;
}
int ret;
#ifdef ETHTOOL_GTSO
- ret = iface_ethtool_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO");
if (ret == -1)
return -1;
if (ret)
#endif
#ifdef ETHTOOL_GUFO
- ret = iface_ethtool_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO");
if (ret == -1)
return -1;
if (ret)
* handed to PF_PACKET sockets on transmission? If not,
* this need not be checked.
*/
- ret = iface_ethtool_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO");
if (ret == -1)
return -1;
if (ret)
#endif
#ifdef ETHTOOL_GFLAGS
- ret = iface_ethtool_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS");
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_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO");
+ ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO");
if (ret == -1)
return -1;
if (ret)
/* Bind to the given device */
if (strcmp(device, "any") == 0) {
- strncpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
+ strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
PCAP_ERRBUF_SIZE);
return PCAP_ERROR;
}
if (handle->opt.promisc) {
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFFLAGS: %s", pcap_strerror(errno));
socklen_t errlen = sizeof(err);
memset(&saddr, 0, sizeof(saddr));
- strncpy(saddr.sa_data, device, sizeof(saddr.sa_data));
+ strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data));
if (bind(fd, &saddr, sizeof(saddr)) == -1) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"bind: %s", pcap_strerror(errno));
return BIGGER_THAN_ALL_MTUS;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
* Yes - if the value to be returned,
* i.e. the snapshot length, is
* anything other than 0, make it
- * 65535, so that the packet is
- * truncated by "recvfrom()",
+ * MAXIMUM_SNAPLEN, so that the packet
+ * is truncated by "recvfrom()",
* not by the filter.
*
* XXX - there's nothing we can
* easily do if it's getting the
* value from the accumulator; we'd
* have to insert code to force
- * non-zero values to be 65535.
+ * non-zero values to be
+ * MAXIMUM_SNAPLEN.
*/
if (p->k != 0)
- p->k = 65535;
+ p->k = MAXIMUM_SNAPLEN;
}
}
break;
* "nothing more to be read" error).
*/
save_mode = fcntl(handle->fd, F_GETFL, 0);
- if (save_mode != -1 &&
- fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) >= 0) {
- while (recv(handle->fd, &drain, sizeof drain,
- MSG_TRUNC) >= 0)
- ;
- save_errno = errno;
- fcntl(handle->fd, F_SETFL, save_mode);
- if (save_errno != EAGAIN) {
- /* Fatal error */
- reset_kernel_filter(handle);
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "recv: %s", pcap_strerror(save_errno));
- return -2;
- }
+ if (save_mode == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't get FD flags when changing filter: %s",
+ pcap_strerror(errno));
+ return -2;
+ }
+ if (fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't set nonblocking mode when changing filter: %s",
+ pcap_strerror(errno));
+ return -2;
+ }
+ while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0)
+ ;
+ save_errno = errno;
+ if (save_errno != EAGAIN) {
+ /*
+ * Fatal error.
+ *
+ * If we can't restore the mode or reset the
+ * kernel filter, there's nothing we can do.
+ */
+ (void)fcntl(handle->fd, F_SETFL, save_mode);
+ (void)reset_kernel_filter(handle);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "recv failed when changing filter: %s",
+ pcap_strerror(save_errno));
+ return -2;
+ }
+ if (fcntl(handle->fd, F_SETFL, save_mode) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't restore FD flags when changing filter: %s",
+ pcap_strerror(save_errno));
+ return -2;
}
}
save_errno = errno;
/*
- * XXX - if this fails, we're really screwed;
- * we have the total filter on the socket,
- * and it won't come off. What do we do then?
+ * If this fails, we're really screwed; we have the
+ * total filter on the socket, and it won't come off.
+ * Report it as a fatal error.
*/
- reset_kernel_filter(handle);
+ if (reset_kernel_filter(handle) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't remove kernel total filter: %s",
+ pcap_strerror(errno));
+ return -2; /* fatal error */
+ }
errno = save_errno;
}