]> The Tcpdump Group git mirrors - libpcap/commitdiff
DLT_LINUX_SLL2 support.
authorGuy Harris <[email protected]>
Thu, 12 Jul 2018 18:30:48 +0000 (11:30 -0700)
committerGuy Harris <[email protected]>
Thu, 12 Jul 2018 18:32:51 +0000 (11:32 -0700)
gencode.c
pcap-linux.c
pcap.c
pcap/sll.h

index 959a56e6e5e6cd1382dbc2f4938be948b5f55bd0..dd44bc9fbe40174efc171f976b936cad6b45e671 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -1330,13 +1330,20 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
-       case DLT_LINUX_SLL:     /* fake header for Linux cooked socket */
+       case DLT_LINUX_SLL:     /* fake header for Linux cooked socket v1 */
                cstate->off_linktype.constant_part = 14;
                cstate->off_linkpl.constant_part = 16;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
                break;
 
+       case DLT_LINUX_SLL2:    /* fake header for Linux cooked socket v2 */
+               cstate->off_linktype.constant_part = 0;
+               cstate->off_linkpl.constant_part = 20;
+               cstate->off_nl = 0;
+               cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
+               break;
+
        case DLT_LTALK:
                /*
                 * LocalTalk does have a 1-byte type field in the LLAP header,
@@ -7733,6 +7740,15 @@ gen_inbound(compiler_state_t *cstate, int dir)
                }
                break;
 
+       case DLT_LINUX_SLL2:
+               /* match outgoing packets */
+               b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING);
+               if (!dir) {
+                       /* to filter on inbound traffic, invert the match */
+                       gen_not(b0);
+               }
+               break;
+
 #ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
index 49144b644ed6ba2156614a5588e2dc25d3b07c19..c3f7cb2700c30b4f45f39d5e08a95896d62af8f6 100644 (file)
@@ -486,7 +486,7 @@ static int  iface_bind_old(int fd, const char *device, char *ebuf);
 #ifdef SO_ATTACH_FILTER
 static int     fix_program(pcap_t *handle, struct sock_fprog *fcode,
     int is_mapped);
-static int     fix_offset(struct bpf_insn *p);
+static int     fix_offset(pcap_t *handle, struct bpf_insn *p);
 static int     set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode);
 static int     reset_kernel_filter(pcap_t *handle);
 
@@ -1750,7 +1750,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
        int                     offset;
 #ifdef HAVE_PF_PACKET_SOCKETS
        struct sockaddr_ll      from;
-       struct sll_header       *hdrp;
 #else
        struct sockaddr         from;
 #endif
@@ -1774,9 +1773,12 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
         * If this is a cooked device, leave extra room for a
         * fake packet header.
         */
-       if (handlep->cooked)
-               offset = SLL_HDR_LEN;
-       else
+       if (handlep->cooked) {
+               if (handle->linktype == DLT_LINUX_SLL2)
+                       offset = SLL2_HDR_LEN;
+               else
+                       offset = SLL_HDR_LEN;
+       } else
                offset = 0;
 #else
        /*
@@ -1906,17 +1908,37 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
                 * Add the length of the fake header to the length
                 * of packet data we read.
                 */
-               packet_len += SLL_HDR_LEN;
-
-               hdrp = (struct sll_header *)bp;
-               hdrp->sll_pkttype = map_packet_type_to_sll_type(from.sll_pkttype);
-               hdrp->sll_hatype = htons(from.sll_hatype);
-               hdrp->sll_halen = htons(from.sll_halen);
-               memcpy(hdrp->sll_addr, from.sll_addr,
-                   (from.sll_halen > SLL_ADDRLEN) ?
-                     SLL_ADDRLEN :
-                     from.sll_halen);
-               hdrp->sll_protocol = from.sll_protocol;
+               if (handle->linktype = DLT_LINUX_SLL2) {
+                       struct sll2_header      *hdrp;
+
+                       packet_len += SLL2_HDR_LEN;
+
+                       hdrp = (struct sll2_header *)bp;
+                       hdrp->sll2_protocol = from.sll_protocol;
+                       hdrp->sll2_reserved_mbz = 0;
+                       hdrp->sll2_if_index = htonl(from.sll_ifindex);
+                       hdrp->sll2_hatype = from.sll_hatype;
+                       hdrp->sll2_pkttype = map_packet_type_to_sll_type(from.sll_pkttype);
+                       hdrp->sll2_halen = from.sll_halen;
+                       memcpy(hdrp->sll2_addr, from.sll_addr,
+                           (from.sll_halen > SLL_ADDRLEN) ?
+                             SLL_ADDRLEN :
+                             from.sll_halen);
+               } else {
+                       struct sll_header       *hdrp;
+
+                       packet_len += SLL_HDR_LEN;
+
+                       hdrp = (struct sll_header *)bp;
+                       hdrp->sll_pkttype = map_packet_type_to_sll_type(from.sll_pkttype);
+                       hdrp->sll_hatype = htons(from.sll_hatype);
+                       hdrp->sll_halen = htons(from.sll_halen);
+                       memcpy(hdrp->sll_addr, from.sll_addr,
+                           (from.sll_halen > SLL_ADDRLEN) ?
+                             SLL_ADDRLEN :
+                             from.sll_halen);
+                       hdrp->sll_protocol = from.sll_protocol;
+               }
        }
 
        /*
@@ -2129,7 +2151,7 @@ pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
 
                if (handlep->cooked) {
                        /*
-                        * We don't support sending on the "any" device.
+                        * We don't support sending on cooked-mode sockets.
                         *
                         * XXX - how do you send on a bound cooked-mode
                         * socket?
@@ -3558,6 +3580,45 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
 
 /* ===== Functions to interface to the newer kernels ================== */
 
+#ifdef PACKET_RESERVE
+static void
+set_dlt_list_cooked(pcap_t *handle, int sock_fd)
+{
+       socklen_t               len;
+       unsigned int            tp_reserve;
+
+       /*
+        * If we can't do PACKET_RESERVE, we can't reserve extra space
+        * for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2.
+        */
+       len = sizeof(tp_reserve);
+       if (getsockopt(sock_fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve,
+           &len) == 0) {
+               /*
+                * Yes, we can do DLL_LINUX_SLL2.
+                */
+               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_LINUX_SLL;
+                       handle->dlt_list[1] = DLT_LINUX_SLL2;
+                       handle->dlt_count = 2;
+               }
+       }
+}
+#else
+/*
+ * The build environment doesn't define PACKET_RESERVE, so we can't reserve
+ * extra space for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2.
+ */
+static void
+set_dlt_list_cooked(pcap_t *handle _U_, int sock_fd _U_)
+{
+}
+#endif
+
 /*
  * 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
@@ -3737,6 +3798,7 @@ activate_new(pcap_t *handle)
                                free(handle->dlt_list);
                                handle->dlt_list = NULL;
                                handle->dlt_count = 0;
+                               set_dlt_list_cooked(handle, sock_fd);
                        }
 
                        if (handle->linktype == -1) {
@@ -3797,6 +3859,9 @@ activate_new(pcap_t *handle)
                 */
                handlep->cooked = 1;
                handle->linktype = DLT_LINUX_SLL;
+               handle->dlt_list = NULL;
+               handle->dlt_count = 0;
+               set_dlt_list_cooked(handle, sock_fd);
 
                /*
                 * We're not bound to a device.
@@ -3870,10 +3935,14 @@ activate_new(pcap_t *handle)
         * 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()").
+        * XXX - we don't know whether this will be DLT_LINUX_SLL
+        * or DLT_LINUX_SLL2, so make sure it's big enough for
+        * a DLT_LINUX_SLL2 "cooked mode" header; a snapshot length
+        * that small is silly anyway.
         */
        if (handlep->cooked) {
-               if (handle->snapshot < SLL_HDR_LEN + 1)
-                       handle->snapshot = SLL_HDR_LEN + 1;
+               if (handle->snapshot < SLL2_HDR_LEN + 1)
+                       handle->snapshot = SLL2_HDR_LEN + 1;
        }
        handle->bufsize = handle->snapshot;
 
@@ -4359,7 +4428,7 @@ create_ring(pcap_t *handle, int *status)
                if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type,
                    &len) < 0) {
                        pcap_fmt_errmsg_for_errno(handle->errbuf,
-                           PCAP_ERRBUF_SIZE, errno, "getsockopt");
+                           PCAP_ERRBUF_SIZE, errno, "getsockopt (SO_TYPE)");
                        *status = PCAP_ERROR;
                        return -1;
                }
@@ -4374,14 +4443,50 @@ create_ring(pcap_t *handle, int *status)
                                 * as best we can.
                                 */
                                pcap_fmt_errmsg_for_errno(handle->errbuf,
-                                   PCAP_ERRBUF_SIZE, errno, "getsockopt");
+                                   PCAP_ERRBUF_SIZE, errno,
+                                   "getsockopt (PACKET_RESERVE)");
+                               *status = PCAP_ERROR;
+                               return -1;
+                       }
+                       /*
+                        * Older kernel, so we can't use PACKET_RESERVE;
+                        * this means we can't reserver extra space
+                        * for a DLT_LINUX_SLL2 header.
+                        */
+                       tp_reserve = 0;
+               } else {
+                       /*
+                        * We can reserve extra space for a DLT_LINUX_SLL2
+                        * header.  Do so.
+                        *
+                        * XXX - we assume that the kernel is still adding
+                        * 16 bytes of extra space; that happens to
+                        * correspond to SLL_HDR_LEN (whether intentionally
+                        * or not - the kernel code has a raw "16" in
+                        * the expression), so we subtract SLL_HDR_LEN
+                        * from SLL2_HDR_LEN to get the additional space
+                        * needed.
+                        *
+                        * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
+                        */
+                       tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
+                       len = sizeof(tp_reserve);
+                       if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
+                           &tp_reserve, len) < 0) {
+                               pcap_fmt_errmsg_for_errno(handle->errbuf,
+                                   PCAP_ERRBUF_SIZE, errno,
+                                   "setsockopt (PACKET_RESERVE)");
                                *status = PCAP_ERROR;
                                return -1;
                        }
-                       tp_reserve = 0; /* older kernel, reserve not supported */
                }
 #else
-               tp_reserve = 0; /* older kernel, reserve not supported */
+               /*
+                * Build environment for an older kernel, so we can't
+                * use PACKET_RESERVE; this means we can't reserve
+                * extra space for a DLT_LINUX_SLL2 header.
+                */
+               tp_reserve = 0;
 #endif
                maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE;
                        /* XXX: in the kernel maclen is calculated from
@@ -4425,6 +4530,49 @@ create_ring(pcap_t *handle, int *status)
 
 #ifdef HAVE_TPACKET3
        case TPACKET_V3:
+               /*
+                * If we have TPACKET_V3, we have PACKET_RESERVE.
+                */
+               len = sizeof(tp_reserve);
+               if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
+                   &tp_reserve, &len) < 0) {
+                       /*
+                        * Even ENOPROTOOPT is an error - we wouldn't
+                        * be here if the kernel didn't support
+                        * TPACKET_V3, which means it supports
+                        * PACKET_RESERVE.
+                        */
+                       pcap_fmt_errmsg_for_errno(handle->errbuf,
+                           PCAP_ERRBUF_SIZE, errno,
+                           "getsockopt (PACKET_RESERVE)");
+                       *status = PCAP_ERROR;
+                       return -1;
+               }
+               /*
+                * We can reserve extra space for a DLT_LINUX_SLL2
+                * header.  Do so.
+                *
+                * XXX - we assume that the kernel is still adding
+                * 16 bytes of extra space; that happens to
+                * correspond to SLL_HDR_LEN (whether intentionally
+                * or not - the kernel code has a raw "16" in
+                * the expression), so we subtract SLL_HDR_LEN
+                * from SLL2_HDR_LEN to get the additional space
+                * needed.
+                *
+                * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
+                */
+               tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
+               len = sizeof(tp_reserve);
+               if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
+                    &tp_reserve, len) < 0) {
+                       pcap_fmt_errmsg_for_errno(handle->errbuf,
+                           PCAP_ERRBUF_SIZE, errno,
+                           "setsockopt (PACKET_RESERVE)");
+                       *status = PCAP_ERROR;
+                       return -1;
+               }
+
                /* The "frames" for this are actually buffers that
                 * contain multiple variable-sized frames.
                 *
@@ -4932,44 +5080,87 @@ static int pcap_handle_packet_mmap(
        /* if required build in place the sll header*/
        sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen);
        if (handlep->cooked) {
-               struct sll_header *hdrp;
+               if (handle->linktype == DLT_LINUX_SLL2) {
+                       struct sll2_header *hdrp;
 
-               /*
-                * The kernel should have left us with enough
-                * space for an sll header; back up the packet
-                * data pointer into that space, as that'll be
-                * the beginning of the packet we pass to the
-                * callback.
-                */
-               bp -= SLL_HDR_LEN;
+                       /*
+                        * The kernel should have left us with enough
+                        * space for an sll header; back up the packet
+                        * data pointer into that space, as that'll be
+                        * the beginning of the packet we pass to the
+                        * callback.
+                        */
+                       bp -= SLL2_HDR_LEN;
 
-               /*
-                * Let's make sure that's past the end of
-                * the tpacket header, i.e. >=
-                * ((u_char *)thdr + TPACKET_HDRLEN), so we
-                * don't step on the header when we construct
-                * the sll header.
-                */
-               if (bp < (u_char *)frame +
-                                  TPACKET_ALIGN(handlep->tp_hdrlen) +
-                                  sizeof(struct sockaddr_ll)) {
-                       pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-                               "cooked-mode frame doesn't have room for sll header");
-                       return -1;
-               }
+                       /*
+                        * Let's make sure that's past the end of
+                        * the tpacket header, i.e. >=
+                        * ((u_char *)thdr + TPACKET_HDRLEN), so we
+                        * don't step on the header when we construct
+                        * the sll header.
+                        */
+                       if (bp < (u_char *)frame +
+                                          TPACKET_ALIGN(handlep->tp_hdrlen) +
+                                          sizeof(struct sockaddr_ll)) {
+                               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                       "cooked-mode frame doesn't have room for sll header");
+                               return -1;
+                       }
 
-               /*
-                * OK, that worked; construct the sll header.
-                */
-               hdrp = (struct sll_header *)bp;
-               hdrp->sll_pkttype = map_packet_type_to_sll_type(
-                                               sll->sll_pkttype);
-               hdrp->sll_hatype = htons(sll->sll_hatype);
-               hdrp->sll_halen = htons(sll->sll_halen);
-               memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN);
-               hdrp->sll_protocol = sll->sll_protocol;
+                       /*
+                        * OK, that worked; construct the sll header.
+                        */
+                       hdrp = (struct sll2_header *)bp;
+                       hdrp->sll2_protocol = sll->sll_protocol;
+                       hdrp->sll2_reserved_mbz = 0;
+                       hdrp->sll2_if_index = htonl(sll->sll_ifindex);
+                       hdrp->sll2_hatype = sll->sll_hatype;
+                       hdrp->sll2_pkttype = map_packet_type_to_sll_type(
+                                                       sll->sll_pkttype);
+                       hdrp->sll2_halen = sll->sll_halen;
+                       memcpy(hdrp->sll2_addr, sll->sll_addr, SLL_ADDRLEN);
+
+                       snaplen += sizeof(struct sll2_header);
+               } else {
+                       struct sll_header *hdrp;
+
+                       /*
+                        * The kernel should have left us with enough
+                        * space for an sll header; back up the packet
+                        * data pointer into that space, as that'll be
+                        * the beginning of the packet we pass to the
+                        * callback.
+                        */
+                       bp -= SLL_HDR_LEN;
 
-               snaplen += sizeof(struct sll_header);
+                       /*
+                        * Let's make sure that's past the end of
+                        * the tpacket header, i.e. >=
+                        * ((u_char *)thdr + TPACKET_HDRLEN), so we
+                        * don't step on the header when we construct
+                        * the sll header.
+                        */
+                       if (bp < (u_char *)frame +
+                                          TPACKET_ALIGN(handlep->tp_hdrlen) +
+                                          sizeof(struct sockaddr_ll)) {
+                               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                       "cooked-mode frame doesn't have room for sll header");
+                               return -1;
+                       }
+
+                       /*
+                        * OK, that worked; construct the sll header.
+                        */
+                       hdrp = (struct sll_header *)bp;
+                       hdrp->sll_pkttype = map_packet_type_to_sll_type(
+                                                       sll->sll_pkttype);
+                       hdrp->sll_hatype = htons(sll->sll_hatype);
+                       hdrp->sll_halen = htons(sll->sll_halen);
+                       memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN);
+                       hdrp->sll_protocol = sll->sll_protocol;
+
+                       snaplen += sizeof(struct sll_header);
+               }
        }
 
        if (handlep->filter_in_userland && handle->fcode.bf_insns) {
@@ -4998,8 +5189,13 @@ static int pcap_handle_packet_mmap(
        /* if required build in place the sll header*/
        if (handlep->cooked) {
                /* update packet len */
-               pcaphdr.caplen += SLL_HDR_LEN;
-               pcaphdr.len += SLL_HDR_LEN;
+               if (handle->linktype == DLT_LINUX_SLL2) {
+                       pcaphdr.caplen += SLL2_HDR_LEN;
+                       pcaphdr.len += SLL2_HDR_LEN;
+               } else {
+                       pcaphdr.caplen += SLL_HDR_LEN;
+                       pcaphdr.len += SLL_HDR_LEN;
+               }
        }
 
 #if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
@@ -6950,7 +7146,7 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
                                         * Yes, so we need to fix this
                                         * instruction.
                                         */
-                                       if (fix_offset(p) < 0) {
+                                       if (fix_offset(handle, p) < 0) {
                                                /*
                                                 * We failed to do so.
                                                 * Return 0, so our caller
@@ -6968,38 +7164,74 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
 }
 
 static int
-fix_offset(struct bpf_insn *p)
+fix_offset(pcap_t *handle, struct bpf_insn *p)
 {
-       /*
-        * What's the offset?
-        */
-       if (p->k >= SLL_HDR_LEN) {
-               /*
-                * It's within the link-layer payload; that starts at an
-                * offset of 0, as far as the kernel packet filter is
-                * concerned, so subtract the length of the link-layer
-                * header.
-                */
-               p->k -= SLL_HDR_LEN;
-       } else if (p->k == 0) {
-               /*
-                * It's the packet type field; map it to the special magic
-                * kernel offset for that field.
-                */
-               p->k = SKF_AD_OFF + SKF_AD_PKTTYPE;
-       } else if (p->k == 14) {
+       bpf_u_int32 hdr_len;
+
+       if (handle->linktype == DLT_LINUX_SLL2) {
                /*
-                * It's the protocol field; map it to the special magic
-                * kernel offset for that field.
+                * What's the offset?
                 */
-               p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
-       } else if ((bpf_int32)(p->k) > 0) {
+               if (p->k >= SLL2_HDR_LEN) {
+                       /*
+                        * It's within the link-layer payload; that starts
+                        * at an offset of 0, as far as the kernel packet
+                        * filter is concerned, so subtract the length of
+                        * the link-layer header.
+                        */
+                       p->k -= SLL_HDR_LEN;
+               } else if (p->k == 0) {
+                       /*
+                        * It's the protocol field; map it to the
+                        * special magic kernel offset for that field.
+                        */
+                       p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
+               } else if (p->k == 10) {
+                       /*
+                        * It's the packet type field; map it to the
+                        * special magic kernel offset for that field.
+                        */
+                       p->k = SKF_AD_OFF + SKF_AD_PKTTYPE;
+               } else if ((bpf_int32)(p->k) > 0) {
+                       /*
+                        * It's within the header, but it's not one of
+                        * those fields; we can't do that in the kernel,
+                        * so punt to userland.
+                        */
+                       return -1;
+               }
+       } else {
                /*
-                * It's within the header, but it's not one of those
-                * fields; we can't do that in the kernel, so punt
-                * to userland.
+                * What's the offset?
                 */
-               return -1;
+               if (p->k >= SLL_HDR_LEN) {
+                       /*
+                        * It's within the link-layer payload; that starts
+                        * at an offset of 0, as far as the kernel packet
+                        * filter is concerned, so subtract the length of
+                        * the link-layer header.
+                        */
+                       p->k -= SLL_HDR_LEN;
+               } else if (p->k == 0) {
+                       /*
+                        * It's the packet type field; map it to the
+                        * special magic kernel offset for that field.
+                        */
+                       p->k = SKF_AD_OFF + SKF_AD_PKTTYPE;
+               } else if (p->k == 14) {
+                       /*
+                        * It's the protocol field; map it to the
+                        * special magic kernel offset for that field.
+                        */
+                       p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
+               } else if ((bpf_int32)(p->k) > 0) {
+                       /*
+                        * It's within the header, but it's not one of
+                        * those fields; we can't do that in the kernel,
+                        * so punt to userland.
+                        */
+                       return -1;
+               }
        }
        return 0;
 }
diff --git a/pcap.c b/pcap.c
index 3337bcb3196a97be03d6dd1c26debf45306367fa..95ea26e3fdb65b682256e4bf5b48beb3753ec297 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -2841,7 +2841,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(FRELAY, "Frame Relay"),
        DLT_CHOICE(LOOP, "OpenBSD loopback"),
        DLT_CHOICE(ENC, "OpenBSD encapsulated IP"),
-       DLT_CHOICE(LINUX_SLL, "Linux cooked"),
+       DLT_CHOICE(LINUX_SLL, "Linux cooked v1"),
        DLT_CHOICE(LTALK, "Localtalk"),
        DLT_CHOICE(PFLOG, "OpenBSD pflog file"),
        DLT_CHOICE(PFSYNC, "Packet filter state syncing"),
@@ -2959,6 +2959,7 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"),
        DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
        DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
+       DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
        DLT_CHOICE_SENTINEL
 };
 
index c4d08862d64e0c578309dd12e4db949205f16a45..cf7fb95f3e52cdc27ff399691c2d49cc62e058ad 100644 (file)
 #ifndef lib_pcap_sll_h
 #define lib_pcap_sll_h
 
+#include <pcap/pcap-inttypes.h>
+
 /*
  * A DLT_LINUX_SLL fake link-layer header.
  */
 #define SLL_HDR_LEN    16              /* total header length */
 #define SLL_ADDRLEN    8               /* length of address field */
 
-#include <pcap/pcap-inttypes.h>
-
 struct sll_header {
        uint16_t sll_pkttype;           /* packet type */
        uint16_t sll_hatype;            /* link-layer address type */
        uint16_t sll_halen;             /* link-layer address length */
-       uint8_t sll_addr[SLL_ADDRLEN];  /* link-layer address */
+       uint8_t  sll_addr[SLL_ADDRLEN]; /* link-layer address */
        uint16_t sll_protocol;          /* protocol */
 };
 
 /*
- * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the
- * PACKET_ values on Linux, but are defined here so that they're
- * available even on systems other than Linux, and so that they
- * don't change even if the PACKET_ values change.
+ * A DLT_LINUX_SLL2 fake link-layer header.
+ */
+#define SLL2_HDR_LEN   20              /* total header length */
+
+struct sll2_header {
+       uint16_t sll2_protocol;                 /* protocol */
+       uint16_t sll2_reserved_mbz;             /* reserved - must be zero */
+       uint32_t sll2_if_index;                 /* 1-based interface index */
+       uint8_t  sll2_hatype;                   /* link-layer address type */
+       uint8_t  sll2_pkttype;                  /* packet type */
+       uint8_t  sll2_halen;                    /* link-layer address length */
+       uint8_t  sll2_addr[SLL_ADDRLEN];        /* link-layer address */
+};
+
+/*
+ * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for
+ * "sll2_pkttype"; these correspond to the PACKET_ values on Linux,
+ * but are defined here so that they're available even on systems other
+ * than Linux, and so that they don't change even if the PACKET_ values
+ * change.
  */
 #define LINUX_SLL_HOST         0
 #define LINUX_SLL_BROADCAST    1
@@ -103,10 +119,11 @@ struct sll_header {
 #define LINUX_SLL_OUTGOING     4
 
 /*
- * The LINUX_SLL_ values for "sll_protocol"; these correspond to the
- * ETH_P_ values on Linux, but are defined here so that they're
- * available even on systems other than Linux.  We assume, for now,
- * that the ETH_P_ values won't change in Linux; if they do, then:
+ * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for
+ * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but
+ * are defined here so that they're available even on systems other than
+ * Linux.  We assume, for now, that the ETH_P_ values won't change in
+ * Linux; if they do, then:
  *
  *     if we don't translate them in "pcap-linux.c", capture files
  *     won't necessarily be readable if captured on a system that