+
+#ifndef ARPHRD_FCPP
+#define ARPHRD_FCPP 784
+#endif
+ case ARPHRD_FCPP:
+#ifndef ARPHRD_FCAL
+#define ARPHRD_FCAL 785
+#endif
+ case ARPHRD_FCAL:
+#ifndef ARPHRD_FCPL
+#define ARPHRD_FCPL 786
+#endif
+ case ARPHRD_FCPL:
+#ifndef ARPHRD_FCFABRIC
+#define ARPHRD_FCFABRIC 787
+#endif
+ case ARPHRD_FCFABRIC:
+ /*
+ * We assume that those all mean RFC 2625 IP-over-
+ * Fibre Channel, with the RFC 2625 header at
+ * the beginning of the packet.
+ */
+ handle->linktype = DLT_IP_OVER_FC;
+ break;
+
+#ifndef ARPHRD_IRDA
+#define ARPHRD_IRDA 783
+#endif
+ case ARPHRD_IRDA:
+ /* Don't expect IP packet out of this interfaces... */
+ handle->linktype = DLT_LINUX_IRDA;
+ /* We need to save packet direction for IrDA decoding,
+ * so let's use "Linux-cooked" mode. Jean II */
+ //handle->md.cooked = 1;
+ break;
+
+ /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation
+#ifndef ARPHRD_LAPD
+#define ARPHRD_LAPD 8445
+#endif
+ case ARPHRD_LAPD:
+ /* Don't expect IP packet out of this interfaces... */
+ handle->linktype = DLT_LINUX_LAPD;
+ break;
+
+#ifndef ARPHRD_NONE
+#define ARPHRD_NONE 0xFFFE
+#endif
+ case ARPHRD_NONE:
+ /*
+ * No link-layer header; packets are just IP
+ * packets, so use DLT_RAW.
+ */
+ handle->linktype = DLT_RAW;
+ break;
+
+ default:
+ handle->linktype = -1;
+ break;
+ }
+}
+
+/* ===== Functions to interface to the newer kernels ================== */
+
+/*
+ * Try to open a packet socket using the new kernel PF_PACKET interface.
+ * Returns 1 on success, 0 on an error that means the new interface isn't
+ * present (so the old SOCK_PACKET interface should be tried), and a
+ * PCAP_ERROR_ value on an error that means that the old mechanism won't
+ * work either (so it shouldn't be tried).
+ */
+static int
+activate_new(pcap_t *handle)
+{
+#ifdef HAVE_PF_PACKET_SOCKETS
+ const char *device = handle->opt.source;
+ int is_any_device = (strcmp(device, "any") == 0);
+ int sock_fd = -1, arptype;
+#ifdef HAVE_PACKET_AUXDATA
+ int val;
+#endif
+ int err = 0;
+ struct packet_mreq mr;
+
+ /*
+ * Open a socket with protocol family packet. If the
+ * "any" device was specified, we open a SOCK_DGRAM
+ * socket for the cooked interface, otherwise we first
+ * try a SOCK_RAW socket for the raw interface.
+ */
+ sock_fd = is_any_device ?
+ socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) :
+ socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+
+ if (sock_fd == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
+ pcap_strerror(errno) );
+ return 0; /* try old mechanism */
+ }
+
+ /* It seems the kernel supports the new interface. */
+ handle->md.sock_packet = 0;
+
+ /*
+ * Get the interface index of the loopback device.
+ * If the attempt fails, don't fail, just set the
+ * "md.lo_ifindex" to -1.
+ *
+ * XXX - can there be more than one device that loops
+ * packets back, i.e. devices other than "lo"? If so,
+ * we'd need to find them all, and have an array of
+ * indices for them, and check all of them in
+ * "pcap_read_packet()".
+ */
+ handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf);
+
+ /*
+ * Default value for offset to align link-layer payload
+ * on a 4-byte boundary.
+ */
+ handle->offset = 0;
+
+ /*
+ * What kind of frames do we have to deal with? Fall back
+ * to cooked mode if we have an unknown interface type
+ * or a type we know doesn't work well in raw mode.
+ */
+ if (!is_any_device) {
+ /* Assume for now we don't need cooked mode. */
+ handle->md.cooked = 0;
+
+ if (handle->opt.rfmon) {
+ /*
+ * We were asked to turn on monitor mode.
+ * Do so before we get the link-layer type,
+ * because entering monitor mode could change
+ * the link-layer type.
+ */
+ err = enter_rfmon_mode(handle, sock_fd, device);
+ if (err < 0) {
+ /* Hard failure */
+ close(sock_fd);
+ return err;
+ }
+ if (err == 0) {
+ /*
+ * Nothing worked for turning monitor mode
+ * on.
+ */
+ close(sock_fd);
+ return PCAP_ERROR_RFMON_NOTSUP;
+ }
+
+ /*
+ * Either monitor mode has been turned on for
+ * the device, or we've been given a different
+ * device to open for monitor mode. If we've
+ * been given a different device, use it.
+ */
+ if (handle->md.mondevice != NULL)
+ device = handle->md.mondevice;
+ }
+ arptype = iface_get_arptype(sock_fd, device, handle->errbuf);
+ if (arptype < 0) {
+ close(sock_fd);
+ return arptype;
+ }
+ map_arphrd_to_dlt(handle, arptype, 1);
+ if (handle->linktype == -1 ||
+ handle->linktype == DLT_LINUX_SLL ||
+ handle->linktype == DLT_LINUX_IRDA ||
+ handle->linktype == DLT_LINUX_LAPD ||
+ (handle->linktype == DLT_EN10MB &&
+ (strncmp("isdn", device, 4) == 0 ||
+ strncmp("isdY", device, 4) == 0))) {
+ /*
+ * Unknown interface type (-1), or a
+ * device we explicitly chose to run
+ * in cooked mode (e.g., PPP devices),
+ * or an ISDN device (whose link-layer
+ * type we can only determine by using
+ * APIs that may be different on different
+ * kernels) - reopen in cooked mode.
+ */
+ if (close(sock_fd) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "close: %s", pcap_strerror(errno));
+ return PCAP_ERROR;
+ }
+ sock_fd = socket(PF_PACKET, SOCK_DGRAM,
+ htons(ETH_P_ALL));
+ if (sock_fd == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "socket: %s", pcap_strerror(errno));
+ return PCAP_ERROR;
+ }
+ handle->md.cooked = 1;
+
+ /*
+ * Get rid of any link-layer type list
+ * we allocated - this only supports cooked
+ * capture.
+ */
+ if (handle->dlt_list != NULL) {
+ free(handle->dlt_list);
+ handle->dlt_list = NULL;
+ handle->dlt_count = 0;
+ }
+
+ if (handle->linktype == -1) {
+ /*
+ * Warn that we're falling back on
+ * cooked mode; we may want to
+ * update "map_arphrd_to_dlt()"
+ * to handle the new type.
+ */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "arptype %d not "
+ "supported by libpcap - "
+ "falling back to cooked "
+ "socket",
+ arptype);
+ }
+
+ /*
+ * IrDA capture is not a real "cooked" capture,
+ * it's IrLAP frames, not IP packets. The
+ * same applies to LAPD capture.
+ */
+ if (handle->linktype != DLT_LINUX_IRDA &&
+ handle->linktype != DLT_LINUX_LAPD)
+ handle->linktype = DLT_LINUX_SLL;
+ }
+
+ handle->md.ifindex = iface_get_id(sock_fd, device,
+ handle->errbuf);
+ if (handle->md.ifindex == -1) {
+ close(sock_fd);
+ return PCAP_ERROR;
+ }
+
+ if ((err = iface_bind(sock_fd, handle->md.ifindex,
+ handle->errbuf)) != 1) {
+ close(sock_fd);
+ if (err < 0)
+ return err;
+ else
+ return 0; /* try old mechanism */
+ }
+ } else {
+ /*
+ * The "any" device.
+ */
+ if (handle->opt.rfmon) {
+ /*
+ * It doesn't support monitor mode.
+ */
+ return PCAP_ERROR_RFMON_NOTSUP;
+ }
+
+ /*
+ * It uses cooked mode.
+ */
+ handle->md.cooked = 1;
+ handle->linktype = DLT_LINUX_SLL;
+
+ /*
+ * We're not bound to a device.
+ * For now, we're using this as an indication
+ * that we can't transmit; stop doing that only
+ * if we figure out how to transmit in cooked
+ * mode.
+ */
+ handle->md.ifindex = -1;
+ }
+
+ /*
+ * Select promiscuous mode on if "promisc" is set.
+ *
+ * Do not turn allmulti mode on if we don't select
+ * promiscuous mode - on some devices (e.g., Orinoco
+ * wireless interfaces), allmulti mode isn't supported
+ * and the driver implements it by turning promiscuous
+ * mode on, and that screws up the operation of the
+ * card as a normal networking interface, and on no
+ * other platform I know of does starting a non-
+ * promiscuous capture affect which multicast packets
+ * are received by the interface.
+ */
+
+ /*
+ * Hmm, how can we set promiscuous mode on all interfaces?
+ * I am not sure if that is possible at all. For now, we
+ * silently ignore attempts to turn promiscuous mode on
+ * for the "any" device (so you don't have to explicitly
+ * disable it in programs such as tcpdump).
+ */
+
+ if (!is_any_device && handle->opt.promisc) {
+ memset(&mr, 0, sizeof(mr));
+ mr.mr_ifindex = handle->md.ifindex;
+ mr.mr_type = PACKET_MR_PROMISC;
+ if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
+ &mr, sizeof(mr)) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "setsockopt: %s", pcap_strerror(errno));
+ close(sock_fd);
+ return PCAP_ERROR;
+ }
+ }
+
+ /* Enable auxillary data if supported and reserve room for
+ * reconstructing VLAN headers. */
+#ifdef HAVE_PACKET_AUXDATA
+ val = 1;
+ if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val,
+ sizeof(val)) == -1 && errno != ENOPROTOOPT) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "setsockopt: %s", pcap_strerror(errno));
+ close(sock_fd);
+ return PCAP_ERROR;
+ }
+ handle->offset += VLAN_TAG_LEN;
+#endif /* HAVE_PACKET_AUXDATA */
+
+ /*
+ * This is a 2.2[.x] or later kernel (we know that
+ * because we're not using a SOCK_PACKET socket -
+ * PF_PACKET is supported only in 2.2 and later
+ * kernels).
+ *
+ * We can safely pass "recvfrom()" a byte count
+ * based on the snapshot length.
+ *
+ * If we're in cooked mode, make the snapshot length
+ * large enough to hold a "cooked mode" header plus
+ * 1 byte of packet data (so we don't pass a byte
+ * count of 0 to "recvfrom()").
+ */
+ if (handle->md.cooked) {
+ if (handle->snapshot < SLL_HDR_LEN + 1)
+ handle->snapshot = SLL_HDR_LEN + 1;
+ }
+ handle->bufsize = handle->snapshot;
+
+ /* Save the socket FD in the pcap structure */
+ handle->fd = sock_fd;
+
+ return 1;
+#else
+ strncpy(ebuf,
+ "New packet capturing interface not supported by build "
+ "environment", PCAP_ERRBUF_SIZE);
+ return 0;
+#endif
+}
+
+static int
+activate_mmap(pcap_t *handle)
+{
+#ifdef HAVE_PACKET_RING
+ int ret;
+
+ /*
+ * Attempt to allocate a buffer to hold the contents of one
+ * packet, for use by the oneshot callback.
+ */
+ handle->md.oneshot_buffer = malloc(handle->snapshot);
+ if (handle->md.oneshot_buffer == NULL) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't allocate oneshot buffer: %s",
+ pcap_strerror(errno));
+ return PCAP_ERROR;
+ }
+
+ if (handle->opt.buffer_size == 0) {
+ /* by default request 2M for the ring buffer */
+ handle->opt.buffer_size = 2*1024*1024;
+ }
+ ret = prepare_tpacket_socket(handle);
+ if (ret != 1) {
+ free(handle->md.oneshot_buffer);
+ return ret;
+ }
+ ret = create_ring(handle);
+ if (ret != 1) {
+ free(handle->md.oneshot_buffer);
+ return ret;
+ }
+
+ /* override some defaults and inherit the other fields from
+ * activate_new
+ * handle->offset is used to get the current position into the rx ring
+ * handle->cc is used to store the ring size */
+ handle->read_op = pcap_read_linux_mmap;
+ handle->cleanup_op = pcap_cleanup_linux_mmap;
+ handle->setfilter_op = pcap_setfilter_linux_mmap;
+ handle->setnonblock_op = pcap_setnonblock_mmap;
+ handle->getnonblock_op = pcap_getnonblock_mmap;
+ handle->oneshot_callback = pcap_oneshot_mmap;
+ handle->selectable_fd = handle->fd;
+ return 1;
+#else /* HAVE_PACKET_RING */
+ return 0;
+#endif /* HAVE_PACKET_RING */
+}
+
+#ifdef HAVE_PACKET_RING
+static int
+prepare_tpacket_socket(pcap_t *handle)
+{
+#ifdef HAVE_TPACKET2
+ socklen_t len;
+ int val;
+#endif
+
+ handle->md.tp_version = TPACKET_V1;
+ handle->md.tp_hdrlen = sizeof(struct tpacket_hdr);
+
+#ifdef HAVE_TPACKET2
+ /* Probe whether kernel supports TPACKET_V2 */
+ val = TPACKET_V2;
+ len = sizeof(val);
+ if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
+ if (errno == ENOPROTOOPT)
+ return 1; /* no - just drive on */
+
+ /* Yes - treat as a failure. */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't get TPACKET_V2 header len on packet socket: %s",
+ pcap_strerror(errno));
+ return -1;
+ }
+ handle->md.tp_hdrlen = val;
+
+ val = TPACKET_V2;
+ if (setsockopt(handle->fd, SOL_PACKET, PACKET_VERSION, &val,
+ sizeof(val)) < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't activate TPACKET_V2 on packet socket: %s",
+ pcap_strerror(errno));
+ return -1;
+ }
+ handle->md.tp_version = TPACKET_V2;
+
+ /* Reserve space for VLAN tag reconstruction */
+ val = VLAN_TAG_LEN;
+ if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val,
+ sizeof(val)) < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't set up reserve on packet socket: %s",
+ pcap_strerror(errno));
+ return -1;
+ }
+
+#endif /* HAVE_TPACKET2 */
+ return 1;
+}
+
+static int
+create_ring(pcap_t *handle)
+{
+ unsigned i, j, frames_per_block;
+ struct tpacket_req req;
+
+ /* Note that with large snapshot (say 64K) only a few frames
+ * will be available in the ring even with pretty large ring size
+ * (and a lot of memory will be unused).
+ * The snap len should be carefully chosen to achive best
+ * performance */
+ req.tp_frame_size = TPACKET_ALIGN(handle->snapshot +
+ TPACKET_ALIGN(handle->md.tp_hdrlen) +
+ sizeof(struct sockaddr_ll));
+ req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size;
+
+ /* compute the minumum block size that will handle this frame.
+ * The block has to be page size aligned.
+ * The max block size allowed by the kernel is arch-dependent and
+ * it's not explicitly checked here. */
+ req.tp_block_size = getpagesize();
+ while (req.tp_block_size < req.tp_frame_size)
+ req.tp_block_size <<= 1;
+
+ frames_per_block = req.tp_block_size/req.tp_frame_size;
+
+ /* ask the kernel to create the ring */
+retry:
+ req.tp_block_nr = req.tp_frame_nr / frames_per_block;
+
+ /* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */
+ req.tp_frame_nr = req.tp_block_nr * frames_per_block;
+
+ if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
+ (void *) &req, sizeof(req))) {
+ if ((errno == ENOMEM) && (req.tp_block_nr > 1)) {
+ /*
+ * Memory failure; try to reduce the requested ring
+ * size.
+ *
+ * We used to reduce this by half -- do 5% instead.
+ * That may result in more iterations and a longer
+ * startup, but the user will be much happier with
+ * the resulting buffer size.
+ */
+ if (req.tp_frame_nr < 20)
+ req.tp_frame_nr -= 1;
+ else
+ req.tp_frame_nr -= req.tp_frame_nr/20;
+ goto retry;
+ }
+ if (errno == ENOPROTOOPT) {
+ /*
+ * We don't have ring buffer support in this kernel.
+ */
+ return 0;
+ }
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't create rx ring on packet socket: %s",
+ pcap_strerror(errno));
+ return -1;
+ }
+
+ /* memory map the rx ring */
+ handle->md.mmapbuflen = req.tp_block_nr * req.tp_block_size;
+ handle->md.mmapbuf = mmap(0, handle->md.mmapbuflen,
+ PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0);
+ if (handle->md.mmapbuf == MAP_FAILED) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't mmap rx ring: %s", pcap_strerror(errno));
+
+ /* clear the allocated ring on error*/
+ destroy_ring(handle);
+ return -1;
+ }
+
+ /* allocate a ring for each frame header pointer*/
+ handle->cc = req.tp_frame_nr;
+ handle->buffer = malloc(handle->cc * sizeof(union thdr *));
+ if (!handle->buffer) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "can't allocate ring of frame headers: %s",
+ pcap_strerror(errno));
+
+ destroy_ring(handle);
+ return -1;
+ }
+
+ /* fill the header ring with proper frame ptr*/
+ handle->offset = 0;
+ for (i=0; i<req.tp_block_nr; ++i) {
+ void *base = &handle->md.mmapbuf[i*req.tp_block_size];
+ for (j=0; j<frames_per_block; ++j, ++handle->offset) {
+ RING_GET_FRAME(handle) = base;
+ base += req.tp_frame_size;
+ }
+ }
+
+ handle->bufsize = req.tp_frame_size;
+ handle->offset = 0;
+ return 1;
+}
+
+/* free all ring related resources*/
+static void
+destroy_ring(pcap_t *handle)
+{
+ /* tell the kernel to destroy the ring*/
+ struct tpacket_req req;
+ memset(&req, 0, sizeof(req));
+ setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
+ (void *) &req, sizeof(req));
+
+ /* if ring is mapped, unmap it*/
+ if (handle->md.mmapbuf) {
+ /* do not test for mmap failure, as we can't recover from any error */
+ munmap(handle->md.mmapbuf, handle->md.mmapbuflen);
+ handle->md.mmapbuf = NULL;
+ }
+}
+
+/*
+ * Special one-shot callback, used for pcap_next() and pcap_next_ex(),
+ * for Linux mmapped capture.
+ *
+ * The problem is that pcap_next() and pcap_next_ex() expect the packet
+ * data handed to the callback to be valid after the callback returns,
+ * but pcap_read_linux_mmap() has to release that packet as soon as
+ * the callback returns (otherwise, the kernel thinks there's still
+ * at least one unprocessed packet available in the ring, so a select()
+ * will immediately return indicating that there's data to process), so,
+ * in the callback, we have to make a copy of the packet.
+ *
+ * Yes, this means that, if the capture is using the ring buffer, using
+ * pcap_next() or pcap_next_ex() requires more copies than using
+ * pcap_loop() or pcap_dispatch(). If that bothers you, don't use
+ * pcap_next() or pcap_next_ex().
+ */
+static void
+pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
+ const u_char *bytes)
+{
+ struct pkt_for_oneshot *sp = (struct pkt_for_oneshot *)user;
+ bpf_u_int32 copylen;
+
+ *sp->hdr = *h;
+ memcpy(sp->pd->md.oneshot_buffer, bytes, h->caplen);
+ *sp->pkt = sp->pd->md.oneshot_buffer;
+}
+
+static void
+pcap_cleanup_linux_mmap( pcap_t *handle )
+{
+ destroy_ring(handle);
+ if (handle->md.oneshot_buffer != NULL) {
+ free(handle->md.oneshot_buffer);
+ handle->md.oneshot_buffer = NULL;
+ }
+ pcap_cleanup_linux(handle);
+}
+
+
+static int
+pcap_getnonblock_mmap(pcap_t *p, char *errbuf)
+{
+ /* use negative value of timeout to indicate non blocking ops */
+ return (p->md.timeout<0);
+}
+
+static int
+pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf)
+{
+ /* map each value to the corresponding 2's complement, to
+ * preserve the timeout value provided with pcap_set_timeout */
+ if (nonblock) {
+ if (p->md.timeout >= 0) {
+ /*
+ * Timeout is non-negative, so we're not already
+ * in non-blocking mode; set it to the 2's
+ * complement, to make it negative, as an
+ * indication that we're in non-blocking mode.
+ */
+ p->md.timeout = p->md.timeout*-1 - 1;
+ }
+ } else {
+ if (p->md.timeout < 0) {
+ /*
+ * Timeout is negative, so we're not already
+ * in blocking mode; reverse the previous
+ * operation, to make the timeout non-negative
+ * again.
+ */
+ p->md.timeout = (p->md.timeout+1)*-1;
+ }
+ }
+ return 0;
+}
+
+static inline union thdr *
+pcap_get_ring_frame(pcap_t *handle, int status)
+{
+ union thdr h;
+
+ h.raw = RING_GET_FRAME(handle);
+ switch (handle->md.tp_version) {
+ case TPACKET_V1:
+ if (status != (h.h1->tp_status ? TP_STATUS_USER :
+ TP_STATUS_KERNEL))
+ return NULL;
+ break;
+#ifdef HAVE_TPACKET2
+ case TPACKET_V2:
+ if (status != (h.h2->tp_status ? TP_STATUS_USER :
+ TP_STATUS_KERNEL))
+ return NULL;