]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add support for a new link layer type DLT_LINUX_SLL, for use when doing
authorguy <guy>
Thu, 21 Dec 2000 10:29:21 +0000 (10:29 +0000)
committerguy <guy>
Thu, 21 Dec 2000 10:29:21 +0000 (10:29 +0000)
live captures with a "cooked" (SOCK_DGRAM) rather than a "raw"
(SOCK_RAW) PF_PACKET socket; it includes a bunch of the fields from the
"struct sockaddr_ll" you get in a "recvfrom()", including the Ethernet
protocol field.

This requires us to rewrite the BPF program if we're stuffing it into
the kernel; as long as we're doing *ex post facto* rewriting, we might
as well also do the "ret <snaplen>" -> "ret 65535" fixup there as well,
rather than in the code generator.

FILES
bpf/net/bpf.h
configure.in
gencode.c
pcap-int.h
pcap-linux.c
savefile.c
sll.h [new file with mode: 0644]

diff --git a/FILES b/FILES
index 85de8f0410d0ff5643bacb6dbdbed2a4a90a9a56..36141caed19762a20014b079fac0f3f057ce5917 100644 (file)
--- a/FILES
+++ b/FILES
@@ -55,3 +55,4 @@ pcap.h
 ppp.h
 savefile.c
 scanner.l
+sll.h
index 5629c4af03e2812c6ca32588c4b5f97473dabab2..57f429729487fa97c15db90a5b7d3946c1d4e16a 100644 (file)
@@ -37,7 +37,7 @@
  *
  *      @(#)bpf.h       7.1 (Berkeley) 5/7/91
  *
- * @(#) $Header: /tcpdump/master/libpcap/bpf/net/Attic/bpf.h,v 1.43 2000-12-16 22:19:12 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/bpf/net/Attic/bpf.h,v 1.44 2000-12-21 10:29:24 guy Exp $ (LBL)
  */
 
 #ifndef BPF_MAJOR_VERSION
@@ -271,7 +271,12 @@ struct bpf_hdr {
  */
 
 /*
- * The instruction encondings.
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL  113
+
+/*
+ * The instruction encodings.
  */
 /* instruction classes */
 #define BPF_CLASS(code) ((code) & 0x07)
index 6df9821e12d11afb7d8d4001a0868daafff850d5..816d67621cc7f66a8b0d6b3ba9a194d2a7cc95e3 100644 (file)
@@ -1,4 +1,4 @@
-dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.86 2000-10-21 04:50:43 guy Exp $ (LBL)
+dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.87 2000-12-21 10:29:22 guy Exp $ (LBL)
 dnl
 dnl Copyright (c) 1994, 1995, 1996, 1997
 dnl    The Regents of the University of California.  All rights reserved.
@@ -6,7 +6,7 @@ dnl
 dnl Process this file with autoconf to produce a configure script.
 dnl
 
-AC_REVISION($Revision: 1.86 $)
+AC_REVISION($Revision: 1.87 $)
 AC_INIT(pcap.c)
 
 AC_CANONICAL_SYSTEM
@@ -15,6 +15,8 @@ AC_LBL_C_INIT(V_CCOPT, V_INCLS)
 AC_C_INLINE
 AC_C___ATTRIBUTE__
 
+AC_LBL_CHECK_TYPE(u_int8_t, u_char)
+AC_LBL_CHECK_TYPE(u_int16_t, u_short)
 AC_LBL_CHECK_TYPE(u_int32_t, u_int)
 
 dnl
index 5d501270c1af9420efbf2d832cb8e9f55c3dad4f..40044fb6f39ab37fb8ccc55ae1c5cb8e4792e0a9 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -21,7 +21,7 @@
  */
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.139 2000-12-16 21:31:10 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.140 2000-12-21 10:29:22 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -53,6 +53,7 @@ struct rtentry;
 #include "nlpid.h"
 #include "gencode.h"
 #include "ppp.h"
+#include "sll.h"
 #include <pcap-namedb.h>
 #ifdef INET6
 #include <netdb.h>
@@ -293,15 +294,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
 
        netmask = mask;
        
-       /* On Linux we do not use the BPF filter to truncate the packet
-        * since the kernel provides other ways for that. In fact if we
-        * are using the packet filter for that duty we will be unable 
-        * to acquire the original packet size.  -- Torsten */
-#ifndef linux
        snaplen = pcap_snapshot(p);
-#else
-       snaplen = 0xffff;
-#endif
        if (snaplen == 0) {
                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                         "snaplen of 0 rejects all packets");
@@ -658,6 +651,11 @@ init_linktype(type)
                off_linktype = 6;
                off_nl = 8;
                return;
+
+       case DLT_LINUX_SLL:     /* fake header for Linux cooked socket */
+               off_linktype = 2;
+               off_nl = 16;
+               return;
        }
        bpf_error("unknown data link type %d", linktype);
        /* NOTREACHED */
index 74c0c8b62c057836c93d9bcb209c10fa1c979e18..2dc27a146c8e2a4524f94382d165141333956ce1 100644 (file)
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.31 2000-12-16 10:43:26 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.32 2000-12-21 10:29:23 guy Exp $ (LBL)
  */
 
 #ifndef pcap_int_h
@@ -68,6 +68,7 @@ struct pcap_md {
        int     readlen;        /* byte count to hand to "recvmsg()" */
        int     timeout;        /* timeout specified to pcap_open_live */
        int     clear_promisc;  /* must clear promiscuous mode when we close */
+       int     cooked;         /* using SOCK_DGRAM rather than SOCK_RAW */
        int     lo_ifindex;     /* interface index of the loopback device */
        char    *device;        /* device name */
        struct pcap *next;      /* list of open promiscuous sock_packet pcaps */
index 34718e976b29bfd7203706d6e773eaf7b3444808..2beae0d059b91095ddd6189327b7de77bbd97772 100644 (file)
@@ -26,7 +26,7 @@
  */
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.43 2000-12-18 00:20:51 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.44 2000-12-21 10:29:23 guy Exp $ (LBL)";
 #endif
 
 /*
@@ -59,6 +59,7 @@ static const char rcsid[] =
 #endif
 
 #include "pcap-int.h"
+#include "sll.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -119,6 +120,11 @@ static int         iface_bind(int fd, int ifindex, char *ebuf);
 #endif
 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);
+static int     fix_offset(struct bpf_insn *p);
+#endif
+
 /*
  *  Get a handle for a live capture from the given device. You can 
  *  pass NULL as device to get all packages (without link level 
@@ -290,8 +296,10 @@ pcap_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
 static int
 pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 {
+       int                     offset;
 #ifdef HAVE_NETPACKET_PACKET_H
        struct sockaddr_ll      from;
+       struct sll_header       *hdrp;
 #else
        struct sockaddr         from;
 #endif
@@ -299,18 +307,30 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
        int                     packet_len, caplen;
        struct pcap_pkthdr      pcap_header;
 
+#ifdef HAVE_NETPACKET_PACKET_H
+       /*
+        * If this is a cooked device, leave extra room for a
+        * fake packet header.
+        */
+       if (handle->md.cooked)
+               offset = SLL_HDR_LEN;
+       else
+               offset = 0;
+#else
        /*
-        * We don't currently use the from return value of recvfrom but
-        * this will probably be implemented in the future.
+        * This system doesn't have PF_PACKET sockets, so it doesn't
+        * support cooked devices.
         */
+       offset = 0;
+#endif
 
        /* Receive a single packet from the kernel */
 
        do {
                fromlen = sizeof(from);
                packet_len = recvfrom( 
-                       handle->fd, handle->buffer + handle->offset,
-                       handle->md.readlen, MSG_TRUNC, 
+                       handle->fd, handle->buffer + offset + handle->offset,
+                       handle->md.readlen - offset, MSG_TRUNC, 
                        (struct sockaddr *) &from, &fromlen);
        } while (packet_len == -1 && errno == EINTR);
 
@@ -342,6 +362,36 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
                return 0;
 #endif
 
+#ifdef HAVE_NETPACKET_PACKET_H
+       /*
+        * If this is a cooked device, fill in the fake packet header.
+        */
+       if (handle->md.cooked) {
+               /*
+                * Add the length of the fake header to the length
+                * of packet data we read.
+                */
+               packet_len += SLL_HDR_LEN;
+
+               hdrp = (struct sll_header *)handle->buffer;
+               hdrp->sll_pkttype = htons(from.sll_pkttype);
+               if (from.sll_protocol == ETH_P_802_2) {
+                       /*
+                        * This is an 802.3 packet; set the packet type
+                        * field to the length, in network byte order.
+                        */
+                       hdrp->sll_protocol = htons(packet_len);
+               } else
+                       hdrp->sll_protocol = from.sll_protocol;
+               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);
+       }
+#endif
+
        /*
         * XXX: According to the kernel source we should get the real 
         * packet len if calling recvfrom with MSG_TRUNC set. It does 
@@ -367,8 +417,11 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
         * the result that we don't get the real packet length. This 
         * is valid at least until kernel 2.2.17pre6. 
         *
-        * tcpdump is currently fixed by changing the BPF code generator
-        * to not truncate the received packet. 
+        * 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
+        * filter to the kernel.
         */
 
        caplen = packet_len;
@@ -421,6 +474,7 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
 {
 #ifdef SO_ATTACH_FILTER
        struct sock_fprog       fcode;
+       int                     can_filter_in_kernel;
 #endif
 
        if (!handle)
@@ -455,44 +509,89 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
        /* Install kernel level filter if possible */
 
 #ifdef SO_ATTACH_FILTER
-       /*
-        * Oh joy, the Linux kernel uses struct sock_fprog instead of 
-        * struct bpf_program and of course the length field is of 
-        * different size. Pointed out by Sebastian
-        */
-
-       fcode.filter    = (struct sock_filter *) handle->fcode.bf_insns;
-       fcode.len       = filter->bf_len;
 #ifdef USHRT_MAX
-       if (filter->bf_len > USHRT_MAX) {
+       if (handle->fcode.bf_len > USHRT_MAX) {
                /*
                 * fcode.len is an unsigned short for current kernel. 
-                * I have yet to see BPF-Code with that much instructions
-                * but still it is possible. So for the sake of 
-                * correctness I added this check.
+                * I have yet to see BPF-Code with that much
+                * instructions but still it is possible. So for the
+                * sake of correctness I added this check.
                 */
-               fprintf(stderr, "Warning: Filter to complex for kernel\n");
-       } 
-       else
-#endif
-        if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, 
-                      &fcode, sizeof(fcode)) == 0)
-       {
-               /* Installation succeded - using kernel filter. */
-               handle->md.use_bpf = 1;
-       } 
-       else
+               fprintf(stderr, "Warning: Filter too complex for kernel\n");
+               fcode.filter = NULL;
+               can_filter_in_kernel = 0;
+       } else
+#endif /* USHRT_MAX */
        {
-               /* 
-                * Print a warning if kernel filter available but a problem
-                * occured using it. 
+               /*
+                * Oh joy, the Linux kernel uses struct sock_fprog instead
+                * of struct bpf_program and of course the length field is
+                * 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, 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.
                 */
-               if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
-                       fprintf(stderr, "Warning: Kernel filter failed: %s\n", 
-                               pcap_strerror(errno));
+               switch (fix_program(handle, &fcode)) {
+
+               case -1:
+               default:
+                       /*
+                        * Fatal error; just quit.
+                        * (The "default" case shouldn't happen; we
+                        * return -1 for that reason.)
+                        */
+                       return -1;
+
+               case 0:
+                       /*
+                        * The program performed checks that we can't make
+                        * work in the kernel.
+                        */
+                       can_filter_in_kernel = 0;
+                       break;
+
+               case 1:
+                       /*
+                        * We have a filter that'll work in the kernel.
+                        */
+                       can_filter_in_kernel = 1;
+                       break;
+               }
+       }
+
+       if (can_filter_in_kernel) {
+               if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, 
+                              &fcode, sizeof(fcode)) == 0)
+               {
+                       /* Installation succeded - using kernel filter. */
+                       handle->md.use_bpf = 1;
+               }
+               else
+               {
+                       /* 
+                        * Print a warning if we weren't able to install
+                        * the filter for a reason other than "this kernel
+                        * isn't configured to support socket filters.
+                        */
+                       if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
+                               fprintf(stderr,
+                                   "Warning: Kernel filter failed: %s\n", 
+                                       pcap_strerror(errno));
+                       }
                }
        }
-#endif
+
+       /*
+        * Free up the copy of the filter that was made by "fix_program()".
+        */
+       if (fcode.filter != NULL)
+               free(fcode.filter);
+#endif /* SO_ATTACH_FILTER */
 
        return 0;
 }
@@ -503,7 +602,9 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
  *  function maps the ARPHRD_xxx constant to an appropriate
  *  DLT_xxx constant.
  *  
- *  Returns -1 if unable to map the type.
+ *  Returns -1 if unable to map the type; we print a message and,
+ *  if we're using PF_PACKET/SOCK_RAW rather than PF_INET/SOCK_PACKET,
+ *  we fall back on using PF_PACKET/SOCK_DGRAM.
  */
 static int map_arphrd_to_dlt(int arptype)
 {
@@ -594,14 +695,25 @@ live_open_new(pcap_t *handle, char *device, int promisc,
                 */
 
                if (device) {
+                       /* Assume for now we don't need cooked mode. */
+                       handle->md.cooked = 0;
+
                        arptype = iface_get_arptype(sock_fd, device, ebuf);
                        if (arptype == -1) 
                                break;
                        handle->linktype = map_arphrd_to_dlt(arptype);
-                       if (handle->linktype == -1) {
+                       if (handle->linktype == -1 ||
+                           (handle->linktype == DLT_EN10MB &&
+                            (strncmp("isdn", device, 4) == 0 ||
+                             strncmp("isdY", device, 4) == 0))) {
                                /*
-                                * Unknown interface type - reopen in cooked
-                                * mode.
+                                * Unknown interface type (-1), 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.
+                                *
+                                * XXX - do that with DLT_RAW as well?
                                 */
                                if (close(sock_fd) == -1) {
                                        snprintf(ebuf, PCAP_ERRBUF_SIZE,
@@ -615,13 +727,23 @@ live_open_new(pcap_t *handle, char *device, int promisc,
                                                 "socket: %s", pcap_strerror(errno));
                                        break;
                                }
+                               handle->md.cooked = 1;
 
-                               fprintf(stderr, 
-                                       "Warning: arptype %d not supported by "
-                                       "libpcap - falling back to cooked "
-                                       "socket\n",
-                                       arptype);
-                               handle->linktype = DLT_RAW;
+                               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.
+                                        */
+                                       fprintf(stderr, 
+                                               "Warning: arptype %d not "
+                                               "supported by libpcap - "
+                                               "falling back to cooked "
+                                               "socket\n",
+                                               arptype);
+                               }
+                               handle->linktype = DLT_LINUX_SLL;
                        }
 
                        device_id = iface_get_id(sock_fd, device, ebuf);
@@ -631,7 +753,11 @@ live_open_new(pcap_t *handle, char *device, int promisc,
                        if (iface_bind(sock_fd, device_id, ebuf) == -1)
                                break;
                } else {
-                       handle->linktype = DLT_RAW;
+                       /*
+                        * This is cooked mode.
+                        */
+                       handle->md.cooked = 1;
+                       handle->linktype = DLT_LINUX_SLL;
 
                        /*
                         * XXX - squelch GCC complaints about
@@ -886,6 +1012,9 @@ live_open_old(pcap_t *handle, char *device, int promisc,
                /* It worked - we are using the old interface */
                handle->md.sock_packet = 1;
 
+               /* ...which means we get the link-layer header. */
+               handle->md.cooked = 0;
+
                /* Bind to the given device */
 
                if (!device) {
@@ -968,6 +1097,17 @@ live_open_old(pcap_t *handle, char *device, int promisc,
                handle->fd       = sock_fd;
                handle->offset   = 0;
                handle->linktype = map_arphrd_to_dlt(arptype);
+               /*
+                * XXX - handle ISDN types here?  We can't fall back on
+                * cooked sockets, so we'd have to figure out from the
+                * device name what type of link-layer encapsulation
+                * it's using, and map that to an appropriate DLT_
+                * value, meaning we'd map "isdnN" devices to DLT_RAW
+                * (they supply raw IP packets with no link-layer
+                * header) and "isdY" devices to a new DLT_I4L_IP
+                * type that has only an Ethernet packet type as
+                * a link-layer header.
+                */
                if (handle->linktype == -1) {
                        snprintf(ebuf, PCAP_ERRBUF_SIZE,
                                 "interface type of %s not supported", device);
@@ -1098,3 +1238,129 @@ iface_get_arptype(int fd, const char *device, char *ebuf)
 
        return ifr.ifr_hwaddr.sa_family;
 }
+
+#ifdef HAVE_NETPACKET_PACKET_H
+static int
+fix_program(pcap_t *handle, struct sock_fprog *fcode)
+{
+       size_t prog_size;
+       register int i;
+       register struct bpf_insn *p;
+       struct bpf_insn *f;
+       int len;
+
+       /*
+        * Make a copy of the filter, and modify that copy if
+        * necessary.
+        */
+       prog_size = sizeof(*handle->fcode.bf_insns) * handle->fcode.bf_len;
+       len = handle->fcode.bf_len;
+       f = (struct bpf_insn *)malloc(prog_size);
+       if (f == NULL) {
+               snprintf(handle->errbuf, sizeof(handle->errbuf),
+                        "malloc: %s", pcap_strerror(errno));
+               return -1;
+       }
+       memcpy(f, handle->fcode.bf_insns, prog_size);
+       fcode->len = len;
+       fcode->filter = (struct sock_filter *) f;
+
+       for (i = 0; i < len; ++i) {
+               p = &f[i];
+               /*
+                * What type of instruction is this?
+                */
+               switch (BPF_CLASS(p->code)) {
+
+               case BPF_RET:
+                       /*
+                        * It's a return instruction; is the snapshot
+                        * length a constant, rather than the contents
+                        * of the accumulator?
+                        */
+                       if (BPF_MODE(p->code) == BPF_K) {
+                               /*
+                                * 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()",
+                                * 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.
+                                */
+                               if (p->k != 0)
+                                       p->k = 65535;
+                       }
+                       break;
+
+               case BPF_LD:
+               case BPF_LDX:
+                       /*
+                        * It's a load instruction; is it loading
+                        * from the packet?
+                        */
+                       switch (BPF_MODE(p->code)) {
+
+                       case BPF_ABS:
+                       case BPF_IND:
+                       case BPF_MSH:
+                               /*
+                                * Yes; are we in cooked mode?
+                                */
+                               if (handle->md.cooked) {
+                                       /*
+                                        * Yes, so we need to fix this
+                                        * instruction.
+                                        */
+                                       if (fix_offset(p) < 0) {
+                                               /*
+                                                * We failed to do so.
+                                                * Return 0, so our caller
+                                                * knows to punt to userland.
+                                                */
+                                               return 0;
+                                       }
+                               }
+                               break;
+                       }
+                       break;
+               }
+       }
+       return 1;       /* we succeeded */
+}
+
+static int
+fix_offset(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 == 2) {
+               /*
+                * 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 {
+               /*
+                * 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;
+}
+#endif
index cedd8d13442778d1dacfa6e09b678c886fee4111..97c9e02067c2f2886cf3afb4db3ab4f19f4da409 100644 (file)
@@ -30,7 +30,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.48 2000-12-16 22:19:12 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.49 2000-12-21 10:29:23 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -167,6 +167,8 @@ static const char rcsid[] =
 #define LINKTYPE_HIPPI         111             /* NetBSD HIPPI */
 #define LINKTYPE_HDLC          112             /* NetBSD HDLC framing */
 
+#define LINKTYPE_LINUX_SLL     113             /* Linux cooked socket capture */
+
 static struct linktype_map {
        int     dlt;
        int     linktype;
@@ -220,6 +222,9 @@ static struct linktype_map {
        /* OpenBSD loopback */
        { DLT_LOOP,             LINKTYPE_LOOP },
 
+       /* Linux cooked socket capture */
+       { DLT_LINUX_SLL,        LINKTYPE_LINUX_SLL },
+
        /*
         * Any platform that defines additional DLT_* codes should:
         *
diff --git a/sll.h b/sll.h
new file mode 100644 (file)
index 0000000..a62e8c0
--- /dev/null
+++ b/sll.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/Attic/sll.h,v 1.1 2000-12-21 10:29:24 guy Exp $ (LBL)
+ */
+
+/*
+ * For captures on Linux cooked sockets, we construct a fake header
+ * that includes:
+ *
+ *     a 2-byte "packet type" which is one of:
+ *
+ *             LINUX_SLL_HOST          packet was sent to us
+ *             LINUX_SLL_BROADCAST     packet was broadcast
+ *             LINUX_SLL_MULTICAST     packet was multicast
+ *             LINUX_SLL_OTHERHOST     packet was sent to somebody else
+ *             LINUX_SLL_OUTGOING      packet was sent *by* us;
+ *
+ *     a 2-byte Ethernet protocol field;
+ *
+ *     a 2-byte link-layer type;
+ *
+ *     a 2-byte link-layer address length;
+ *
+ *     an 8-byte link-layer address, whose actual length is specified
+ *     by the previous value.
+ *
+ * All fields except for the link-layer address are in network byte order.
+ */
+
+/*
+ * A DLT_LINUX_SLL fake link-layer header.
+ */
+#define SLL_HDR_LEN    16              /* total header length */
+#define SLL_ADDRLEN    8               /* length of address field */
+
+struct sll_header {
+       u_int16_t sll_pkttype;          /* packet type */
+       u_int16_t sll_protocol;         /* protocol */
+       u_int16_t sll_hatype;           /* link-layer address type */
+       u_int16_t sll_halen;            /* link-layer address length */
+       u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
+};
+
+/*
+ * The LINUX_SLL_ values; they are defined here so that they're available
+ * even on systems other than Linux, but they should be given the same
+ * values as the corresponding PACKET_ values on Linux.  (Let's hope
+ * those values never change.)
+ */
+#define LINUX_SLL_HOST         0
+#define LINUX_SLL_BROADCAST    1
+#define LINUX_SLL_MULTICAST    2
+#define LINUX_SLL_OTHERHOST    3
+#define LINUX_SLL_OUTGOING     4