From: Vadim Kochan <[email protected]>

Use Linux "cooked" header for Netlink interface automatically
of as replavement of L2 header by specifiyng "--cooked" option.

    http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html

"cooked" header makes sense to use for default or nsec pcap types
which does not contain protocol info.

Added new LINKTYPE_LINUX_SLL which indicates pcap file with
Linux "cooked" header as L2 layer header.This pcap file is
compatible with Wireshark's "cooked" header & vice-versa.

Signed-off-by: Vadim Kochan <[email protected]>
---
 linktype.h    |   1 +
 netsniff-ng.8 |  16 ++-
 netsniff-ng.c |  25 +++-
 pcap_io.h     | 390 +++++++++++++++++++++++++++++++++++++++++-----------------
 pcap_mm.c     |  28 ++++-
 pcap_rw.c     |  30 ++++-
 pcap_sg.c     |  83 +++++++------
 sock.c        |  10 ++
 sock.h        |   1 +
 9 files changed, 418 insertions(+), 166 deletions(-)

diff --git a/linktype.h b/linktype.h
index a78f8be..80b5f2d 100644
--- a/linktype.h
+++ b/linktype.h
@@ -21,6 +21,7 @@
 #define LINKTYPE_C_HDLC                                104
 #define LINKTYPE_IEEE802_11                    105
 #define LINKTYPE_FRELAY                                107
+#define LINKTYPE_LINUX_SLL                     113
 #define LINKTYPE_ECONET                                115
 #define LINKTYPE_IEEE802_11_RADIOTAP           127
 #define LINKTYPE_ARCNET_LINUX                  129
diff --git a/netsniff-ng.8 b/netsniff-ng.8
index 677a78c..25d5edb 100644
--- a/netsniff-ng.8
+++ b/netsniff-ng.8
@@ -69,7 +69,9 @@ netsniff-ng can also be used to debug netlink traffic.
 Defines an input device. This can either be a networking device, a pcap file
 or stdin (\[lq]\-\[rq]). In case of a pcap file, the pcap type (\[lq]\-D\[rq]
 option) is determined automatically by the pcap file magic. In case of stdin,
-it is assumed that the input stream is a pcap file.
+it is assumed that the input stream is a pcap file. If the pcap link type is a
+Netlink and pcap type is default or nsec then each packet will be wrapped
+with pcap cooked header [2].
 .PP
 .SS -o <dev|pcap|dir|cfg|->, --out <dev|pcap|dir|cfg|->
 Defines the output device. This can either be a networking device, a pcap file,
@@ -84,7 +86,10 @@ input device is a pcap file. To specify a  pcap file as the 
output device, the
 file name must have \[lq].pcap\[rq] as its extension. If stdout is given as a
 device, then a trafgen configuration will be written to stdout if the input
 device is a pcap file, or a pcap file if the input device is a networking
-device.
+device. In case if the input device is a Netlink monitor device and pcap type
+is default or nsec then each packet will be wrapped with pcap cooked header [2]
+to keep Netlink family number (Kuznetzov's and netsniff-ng pcap types already
+contains family number in protocol number field).
 .PP
 .SS -C <id>, --fanout-group <id>
 If multiple netsniff-ng instances are being started that all have the same 
packet
@@ -254,6 +259,11 @@ possible addresses. Thus, to save bandwidth or for 
mirroring of Maxmind's
 databases (to bypass their traffic limit policy), different hosts or IP
 addresses can be placed into geoip.conf, separated by a newline.
 .PP
+.SS -w, --cooked
+Replace each frame link header with Linux "cooked" header [3] which keeps info
+about link type and protocol. It allows to dump and dissect frames captured
+from different link types when -i "any" was specified.
+.PP
 .SS -V, --verbose
 Be more verbose during startup i.e. show detailed ring setup information.
 .PP
@@ -588,6 +598,8 @@ in the payload itself as reported here. However, the 
filtering for VLANs works
 reliable if your NIC supports it. See bpfc(8) for an example.
 .PP
    [1] http://lkml.indiana.edu/hypermail/linux/kernel/0710.3/3816.html
+   [2] http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html
+   [3] http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
 .PP
 .SH LEGAL
 netsniff-ng is licensed under the GNU GPL version 2.0.
diff --git a/netsniff-ng.c b/netsniff-ng.c
index d3e9a13..34b3015 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -69,7 +69,8 @@ struct ctx {
 static volatile sig_atomic_t sigint = 0, sighup = 0;
 static volatile bool next_dump = false;
 
-static const char *short_options = 
"d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:";
+static const char *short_options =
+       "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:w";
 static const struct option long_options[] = {
        {"dev",                 required_argument,      NULL, 'd'},
        {"in",                  required_argument,      NULL, 'i'},
@@ -106,6 +107,7 @@ static const struct option long_options[] = {
        {"ascii",               no_argument,            NULL, 'l'},
        {"no-sock-mem",         no_argument,            NULL, 'A'},
        {"update",              no_argument,            NULL, 'U'},
+       {"cooked",              no_argument,            NULL, 'w'},
        {"verbose",             no_argument,            NULL, 'V'},
        {"version",             no_argument,            NULL, 'v'},
        {"help",                no_argument,            NULL, 'h'},
@@ -237,6 +239,8 @@ static void pcap_to_xmit(struct ctx *ctx)
        if (ret)
                panic("Error reading pcap header!\n");
 
+       pcap_pkthdr_init(&phdr, ctx->link_type);
+
        if (__pcap_io->prepare_access_pcap) {
                ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, 
ctx->jumbo);
                if (ret)
@@ -589,6 +593,8 @@ static void read_pcap(struct ctx *ctx)
        if (ret)
                panic("Error reading pcap header!\n");
 
+       pcap_pkthdr_init(&phdr, ctx->link_type);
+
        if (__pcap_io->prepare_access_pcap) {
                ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, 
ctx->jumbo);
                if (ret)
@@ -906,6 +912,8 @@ static void walk_t3_block(struct block_desc *pbd, struct 
ctx *ctx,
                uint8_t *packet = ((uint8_t *) hdr + hdr->tp_mac);
                pcap_pkthdr_t phdr;
 
+               pcap_pkthdr_init(&phdr, ctx->link_type);
+
                if (ctx->packet_type != -1)
                        if (ctx->packet_type != sll->sll_pkttype)
                                goto next;
@@ -956,7 +964,10 @@ static void recv_only_or_dump(struct ctx *ctx)
        struct timeval start, end, diff;
        unsigned long frame_count = 0;
 
-       sock = pf_socket();
+       if (ctx->link_type == LINKTYPE_LINUX_SLL)
+               sock = pf_socket_dgram();
+       else
+               sock = pf_socket();
 
        ifindex = device_ifindex(ctx->device_in);
 
@@ -1036,6 +1047,8 @@ static void recv_only_or_dump(struct ctx *ctx)
                        uint8_t *packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac;
                        pcap_pkthdr_t phdr;
 
+                       pcap_pkthdr_init(&phdr, ctx->link_type);
+
                        if (ctx->packet_type != -1)
                                if (ctx->packet_type != hdr->s_ll.sll_pkttype)
                                        goto next;
@@ -1138,6 +1151,7 @@ static void init_ctx(struct ctx *ctx)
        ctx->magic = ORIGINAL_TCPDUMP_MAGIC;
        ctx->print_mode = PRINT_NORM;
        ctx->pcap = PCAP_OPS_SG;
+       ctx->link_type = 0;
 
        ctx->dump_mode = DUMP_INTERVAL_TIME;
        ctx->dump_interval = 60;
@@ -1196,6 +1210,7 @@ static void __noreturn help(void)
             "  -X|--hex                       Print packet data in hex 
format\n"
             "  -l|--ascii                     Print human-readable packet 
data\n"
             "  -U|--update                    Update GeoIP databases\n"
+            "  -w|--cooked                    Use Linux sll \"cooked\" header 
instead of link header\n"
             "  -V|--verbose                   Be more verbose\n"
             "  -v|--version                   Show version and exit\n"
             "  -h|--help                      Guess what?!\n\n"
@@ -1441,6 +1456,9 @@ int main(int argc, char **argv)
                        update_geoip();
                        die();
                        break;
+               case 'w':
+                       ctx.link_type = LINKTYPE_LINUX_SLL;
+                       break;
                case 'v':
                        version();
                        break;
@@ -1512,7 +1530,8 @@ int main(int argc, char **argv)
                if (ctx.rfraw)
                        setup_rfmon_mac80211_dev(&ctx, &ctx.device_in);
 
-               ctx.link_type = pcap_devtype_to_linktype(ctx.device_in);
+               if (!ctx.link_type)
+                       ctx.link_type = pcap_dev_to_linktype(ctx.device_in);
 
                if (!ctx.device_out) {
                        ctx.dump = 0;
diff --git a/pcap_io.h b/pcap_io.h
index 35faa51..81f8ebd 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -90,12 +90,25 @@ struct pcap_pkthdr_bkm {
        uint8_t pkttype;
 };
 
-typedef union {
-       struct pcap_pkthdr      ppo;
-       struct pcap_pkthdr_ns   ppn;
-       struct pcap_pkthdr_kuz  ppk;
-       struct pcap_pkthdr_bkm  ppb;
-       uint8_t                 raw;
+/* DLT_LINUX_SLL - fake link-layer header */
+struct pcap_pkthdr_ll {
+       uint16_t pkttype;
+       uint16_t hatype;
+       uint16_t len;
+       uint8_t addr[8];
+       uint16_t protocol;
+};
+
+typedef struct {
+       union {
+               struct pcap_pkthdr      ppo;
+               struct pcap_pkthdr_ns   ppn;
+               struct pcap_pkthdr_kuz  ppk;
+               struct pcap_pkthdr_bkm  ppb;
+               uint8_t                 raw;
+       } h;
+       struct pcap_pkthdr_ll ll_hdr;
+       uint32_t link_type;
 } pcap_pkthdr_t;
 
 enum pcap_type {
@@ -150,9 +163,9 @@ static inline uint16_t tp_to_pcap_tsource(uint32_t status)
                return 0;
 }
 
-static inline int pcap_devtype_to_linktype(const char *ifname)
+static inline int pcap_devtype_to_linktype(int dev_type)
 {
-       switch (device_type(ifname)) {
+       switch (dev_type) {
        case ARPHRD_TUNNEL:
        case ARPHRD_TUNNEL6:
        case ARPHRD_LOOPBACK:
@@ -192,6 +205,11 @@ static inline int pcap_devtype_to_linktype(const char 
*ifname)
        }
 }
 
+static inline int pcap_dev_to_linktype(const char *ifname)
+{
+       return pcap_devtype_to_linktype(device_type(ifname));
+}
+
 static inline void pcap_check_magic(uint32_t magic)
 {
        switch (magic) {
@@ -232,8 +250,8 @@ static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum 
pcap_type type)
        switch (type) {
 #define CASE_RET_CAPLEN(what, member, swap) \
        case (what): \
-               return (swap ? ___constant_swab32(phdr->member.caplen) : \
-                       phdr->member.caplen)
+               return (swap ? ___constant_swab32(phdr->h.member.caplen) : \
+                       phdr->h.member.caplen)
 
        CASE_RET_CAPLEN(DEFAULT, ppo, 0);
        CASE_RET_CAPLEN(NSEC, ppn, 0);
@@ -255,7 +273,7 @@ static inline void pcap_set_length(pcap_pkthdr_t *phdr, 
enum pcap_type type, u32
        switch (type) {
 #define CASE_SET_CAPLEN(what, member, swap) \
        case (what): \
-               phdr->member.caplen = (swap ? ___constant_swab32(len) : len); \
+               phdr->h.member.caplen = (swap ? ___constant_swab32(len) : len); 
\
                break
 
        CASE_SET_CAPLEN(DEFAULT, ppo, 0);
@@ -278,7 +296,7 @@ static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, 
enum pcap_type type)
        switch (type) {
 #define CASE_RET_HDRLEN(what, member) \
        case (what): \
-               return sizeof(phdr->member)
+               return sizeof(phdr->h.member)
 
        CASE_RET_HDRLEN(DEFAULT, ppo);
        CASE_RET_HDRLEN(NSEC, ppn);
@@ -300,8 +318,8 @@ static inline u32 pcap_get_total_length(pcap_pkthdr_t 
*phdr, enum pcap_type type
        switch (type) {
 #define CASE_RET_TOTLEN(what, member, swap) \
        case (what): \
-               return ((swap ? ___constant_swab32(phdr->member.caplen) : \
-                        phdr->member.caplen) + sizeof(phdr->member))
+               return ((swap ? ___constant_swab32(phdr->h.member.caplen) : \
+                        phdr->h.member.caplen) + sizeof(phdr->h.member))
 
        CASE_RET_TOTLEN(DEFAULT, ppo, 0);
        CASE_RET_TOTLEN(NSEC, ppn, 0);
@@ -318,6 +336,103 @@ static inline u32 pcap_get_total_length(pcap_pkthdr_t 
*phdr, enum pcap_type type
        }
 }
 
+static inline void pcap_pkthdr_add_hdr(pcap_pkthdr_t *phdr,
+               enum pcap_type type, uint32_t len)
+{
+       switch (type) {
+#define CASE_ADD_TOTLEN(what, member, swap) \
+       case (what): \
+               phdr->h.member.caplen += swap ? ___constant_swab32(len) : len; \
+               phdr->h.member.len += swap ? ___constant_swab32(len) : len; \
+               break;
+
+       CASE_ADD_TOTLEN(DEFAULT, ppo, 0);
+       CASE_ADD_TOTLEN(NSEC, ppn, 0);
+       CASE_ADD_TOTLEN(KUZNETZOV, ppk, 0);
+       CASE_ADD_TOTLEN(BORKMANN, ppb, 0);
+
+       CASE_ADD_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
+       CASE_ADD_TOTLEN(NSEC_SWAPPED, ppn, 1);
+       CASE_ADD_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
+       CASE_ADD_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+
+       default:
+               bug();
+       }
+}
+
+static inline void pcap_pkthdr_sub_hdr(pcap_pkthdr_t *phdr,
+               enum pcap_type type, uint32_t len)
+{
+       switch (type) {
+#define CASE_SUB_TOTLEN(what, member, swap) \
+       case (what): \
+               phdr->h.member.caplen -= swap ? ___constant_swab32(len) : len; \
+               phdr->h.member.len -= swap ? ___constant_swab32(len) : len; \
+               break;
+
+       CASE_SUB_TOTLEN(DEFAULT, ppo, 0);
+       CASE_SUB_TOTLEN(NSEC, ppn, 0);
+       CASE_SUB_TOTLEN(KUZNETZOV, ppk, 0);
+       CASE_SUB_TOTLEN(BORKMANN, ppb, 0);
+
+       CASE_SUB_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
+       CASE_SUB_TOTLEN(NSEC_SWAPPED, ppn, 1);
+       CASE_SUB_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
+       CASE_SUB_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+
+       default:
+               bug();
+       }
+}
+
+static inline void sockaddr_to_pcap_ll(struct pcap_pkthdr_ll *pcap_ll,
+               struct sockaddr_ll *sll, enum pcap_type type)
+{
+       pcap_ll->protocol       = sll->sll_protocol;
+       pcap_ll->hatype         = cpu_to_be16(sll->sll_hatype);
+       pcap_ll->pkttype        = cpu_to_be16(sll->sll_pkttype);
+       pcap_ll->len            = cpu_to_be16(sll->sll_halen);
+       memcpy(pcap_ll->addr, sll->sll_addr, 8);
+}
+
+static inline void pcap_pkthdr_add_ll_hdr(pcap_pkthdr_t *phdr,
+               enum pcap_type type, struct sockaddr_ll *sll)
+{
+       pcap_pkthdr_add_hdr(phdr, type, sizeof(struct pcap_pkthdr_ll));
+       sockaddr_to_pcap_ll(&phdr->ll_hdr, sll, type);
+}
+
+static inline bool pcap_pkthdr_has_ll(pcap_pkthdr_t *phdr, enum pcap_type type)
+{
+       bool is_swapped = false;
+       int link_type;
+
+       switch (type) {
+       case DEFAULT_SWAPPED:
+       case NSEC_SWAPPED:
+               is_swapped = true;
+       case DEFAULT:
+       case NSEC:
+               if (is_swapped)
+                       link_type = ___constant_swab32(phdr->link_type);
+               else
+                       link_type = phdr->link_type;
+
+               if (link_type == LINKTYPE_NETLINK || link_type ==
+                               LINKTYPE_LINUX_SLL)
+                       return true;
+
+               return false;
+       case BORKMANN_SWAPPED:
+       case KUZNETZOV_SWAPPED:
+       case KUZNETZOV:
+       case BORKMANN:
+       default:
+               return false;
+       }
+}
+
 static inline void
 __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, uint32_t snaplen,
                             uint32_t len, uint32_t status,
@@ -326,80 +441,83 @@ __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, 
uint32_t snaplen,
 {
        switch (type) {
        case DEFAULT:
-               phdr->ppo.ts.tv_sec = sec;
-               phdr->ppo.ts.tv_usec = nsec / 1000;
-               phdr->ppo.caplen = snaplen;
-               phdr->ppo.len = len;
+               phdr->h.ppo.ts.tv_sec = sec;
+               phdr->h.ppo.ts.tv_usec = nsec / 1000;
+               phdr->h.ppo.caplen = snaplen;
+               phdr->h.ppo.len = len;
                break;
 
        case DEFAULT_SWAPPED:
-               phdr->ppo.ts.tv_sec = ___constant_swab32(sec);
-               phdr->ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
-               phdr->ppo.caplen = ___constant_swab32(snaplen);
-               phdr->ppo.len = ___constant_swab32(len);
+               phdr->h.ppo.ts.tv_sec = ___constant_swab32(sec);
+               phdr->h.ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
+               phdr->h.ppo.caplen = ___constant_swab32(snaplen);
+               phdr->h.ppo.len = ___constant_swab32(len);
                break;
 
        case NSEC:
-               phdr->ppn.ts.tv_sec = sec;
-               phdr->ppn.ts.tv_nsec = nsec;
-               phdr->ppn.caplen = snaplen;
-               phdr->ppn.len = len;
+               phdr->h.ppn.ts.tv_sec = sec;
+               phdr->h.ppn.ts.tv_nsec = nsec;
+               phdr->h.ppn.caplen = snaplen;
+               phdr->h.ppn.len = len;
                break;
 
        case NSEC_SWAPPED:
-               phdr->ppn.ts.tv_sec = ___constant_swab32(sec);
-               phdr->ppn.ts.tv_nsec = ___constant_swab32(nsec);
-               phdr->ppn.caplen = ___constant_swab32(snaplen);
-               phdr->ppn.len = ___constant_swab32(len);
+               phdr->h.ppn.ts.tv_sec = ___constant_swab32(sec);
+               phdr->h.ppn.ts.tv_nsec = ___constant_swab32(nsec);
+               phdr->h.ppn.caplen = ___constant_swab32(snaplen);
+               phdr->h.ppn.len = ___constant_swab32(len);
                break;
 
        case KUZNETZOV:
-               phdr->ppk.ts.tv_sec = sec;
-               phdr->ppk.ts.tv_usec = nsec / 1000;
-               phdr->ppk.caplen = snaplen;
-               phdr->ppk.len = len;
-               phdr->ppk.ifindex = sll->sll_ifindex;
-               phdr->ppk.protocol = sll->sll_protocol;
-               phdr->ppk.pkttype = sll->sll_pkttype;
+               phdr->h.ppk.ts.tv_sec = sec;
+               phdr->h.ppk.ts.tv_usec = nsec / 1000;
+               phdr->h.ppk.caplen = snaplen;
+               phdr->h.ppk.len = len;
+               phdr->h.ppk.ifindex = sll->sll_ifindex;
+               phdr->h.ppk.protocol = sll->sll_protocol;
+               phdr->h.ppk.pkttype = sll->sll_pkttype;
                break;
 
        case KUZNETZOV_SWAPPED:
-               phdr->ppk.ts.tv_sec = ___constant_swab32(sec);
-               phdr->ppk.ts.tv_usec = ___constant_swab32(nsec / 1000);
-               phdr->ppk.caplen = ___constant_swab32(snaplen);
-               phdr->ppk.len = ___constant_swab32(len);
-               phdr->ppk.ifindex = ___constant_swab32(sll->sll_ifindex);
-               phdr->ppk.protocol = ___constant_swab16(sll->sll_protocol);
-               phdr->ppk.pkttype = sll->sll_pkttype;
+               phdr->h.ppk.ts.tv_sec = ___constant_swab32(sec);
+               phdr->h.ppk.ts.tv_usec = ___constant_swab32(nsec / 1000);
+               phdr->h.ppk.caplen = ___constant_swab32(snaplen);
+               phdr->h.ppk.len = ___constant_swab32(len);
+               phdr->h.ppk.ifindex = ___constant_swab32(sll->sll_ifindex);
+               phdr->h.ppk.protocol = ___constant_swab16(sll->sll_protocol);
+               phdr->h.ppk.pkttype = sll->sll_pkttype;
                break;
 
        case BORKMANN:
-               phdr->ppb.ts.tv_sec = sec;
-               phdr->ppb.ts.tv_nsec = nsec;
-               phdr->ppb.caplen = snaplen;
-               phdr->ppb.len = len;
-               phdr->ppb.tsource = tp_to_pcap_tsource(status);
-               phdr->ppb.ifindex = (u16) sll->sll_ifindex;
-               phdr->ppb.protocol = sll->sll_protocol;
-               phdr->ppb.hatype = sll->sll_hatype;
-               phdr->ppb.pkttype = sll->sll_pkttype;
+               phdr->h.ppb.ts.tv_sec = sec;
+               phdr->h.ppb.ts.tv_nsec = nsec;
+               phdr->h.ppb.caplen = snaplen;
+               phdr->h.ppb.len = len;
+               phdr->h.ppb.tsource = tp_to_pcap_tsource(status);
+               phdr->h.ppb.ifindex = (u16) sll->sll_ifindex;
+               phdr->h.ppb.protocol = sll->sll_protocol;
+               phdr->h.ppb.hatype = sll->sll_hatype;
+               phdr->h.ppb.pkttype = sll->sll_pkttype;
                break;
 
        case BORKMANN_SWAPPED:
-               phdr->ppb.ts.tv_sec = ___constant_swab32(sec);
-               phdr->ppb.ts.tv_nsec = ___constant_swab32(nsec);
-               phdr->ppb.caplen = ___constant_swab32(snaplen);
-               phdr->ppb.len = ___constant_swab32(len);
-               phdr->ppb.tsource = 
___constant_swab16(tp_to_pcap_tsource(status));
-               phdr->ppb.ifindex = ___constant_swab16((u16) sll->sll_ifindex);
-               phdr->ppb.protocol = ___constant_swab16(sll->sll_protocol);
-               phdr->ppb.hatype = sll->sll_hatype;
-               phdr->ppb.pkttype = sll->sll_pkttype;
+               phdr->h.ppb.ts.tv_sec = ___constant_swab32(sec);
+               phdr->h.ppb.ts.tv_nsec = ___constant_swab32(nsec);
+               phdr->h.ppb.caplen = ___constant_swab32(snaplen);
+               phdr->h.ppb.len = ___constant_swab32(len);
+               phdr->h.ppb.tsource = 
___constant_swab16(tp_to_pcap_tsource(status));
+               phdr->h.ppb.ifindex = ___constant_swab16((u16) 
sll->sll_ifindex);
+               phdr->h.ppb.protocol = ___constant_swab16(sll->sll_protocol);
+               phdr->h.ppb.hatype = sll->sll_hatype;
+               phdr->h.ppb.pkttype = sll->sll_pkttype;
                break;
 
        default:
                bug();
        }
+
+       if (pcap_pkthdr_has_ll(phdr, type))
+               pcap_pkthdr_add_ll_hdr(phdr, type, sll);
 }
 
 /* We need to do this crap here since member offsets are not interleaved,
@@ -428,6 +546,47 @@ static inline void tpacket3_hdr_to_pcap_pkthdr(struct 
tpacket3_hdr *thdr,
 }
 #endif
 
+static inline void pcap_pkthdr_to_sockaddr(pcap_pkthdr_t *phdr,
+               struct sockaddr_ll *sll, enum pcap_type type)
+{
+       switch (type) {
+       case DEFAULT:
+       case DEFAULT_SWAPPED:
+       case NSEC:
+       case NSEC_SWAPPED:
+               if (pcap_pkthdr_has_ll(phdr, type)) {
+                       sll->sll_protocol = phdr->ll_hdr.protocol;
+                       sll->sll_hatype   = be16_to_cpu(phdr->ll_hdr.hatype);
+                       sll->sll_pkttype  = be16_to_cpu(phdr->ll_hdr.pkttype);
+                       sll->sll_halen    = be16_to_cpu(phdr->ll_hdr.len);
+                       memcpy(sll->sll_addr, phdr->ll_hdr.addr, 8);
+               }
+               break;
+       case KUZNETZOV:
+               sll->sll_ifindex = phdr->h.ppk.ifindex;
+               sll->sll_protocol = phdr->h.ppk.protocol;
+               sll->sll_pkttype = phdr->h.ppk.pkttype;
+               break;
+       case KUZNETZOV_SWAPPED:
+               sll->sll_ifindex = ___constant_swab32(phdr->h.ppk.ifindex);
+               sll->sll_protocol = ___constant_swab16(phdr->h.ppk.protocol);
+               sll->sll_pkttype = phdr->h.ppk.pkttype;
+               break;
+       case BORKMANN:
+               sll->sll_ifindex = phdr->h.ppb.ifindex;
+               sll->sll_protocol = phdr->h.ppb.protocol;
+               sll->sll_hatype = phdr->h.ppb.hatype;
+               sll->sll_pkttype = phdr->h.ppb.pkttype;
+               break;
+       case BORKMANN_SWAPPED:
+               sll->sll_ifindex = ___constant_swab16(phdr->h.ppb.ifindex);
+               sll->sll_protocol = ___constant_swab16(phdr->h.ppb.protocol);
+               sll->sll_hatype = phdr->h.ppb.hatype;
+               sll->sll_pkttype = phdr->h.ppb.pkttype;
+               break;
+       }
+}
+
 static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
                                              enum pcap_type type,
                                              struct tpacket2_hdr *thdr,
@@ -435,86 +594,84 @@ static inline void 
pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
 {
        switch (type) {
        case DEFAULT:
-               thdr->tp_sec = phdr->ppo.ts.tv_sec;
-               thdr->tp_nsec = phdr->ppo.ts.tv_usec * 1000;
-               thdr->tp_snaplen = phdr->ppo.caplen;
-               thdr->tp_len = phdr->ppo.len;
+               if (pcap_pkthdr_has_ll(phdr, type))
+                       pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+               thdr->tp_sec = phdr->h.ppo.ts.tv_sec;
+               thdr->tp_nsec = phdr->h.ppo.ts.tv_usec * 1000;
+               thdr->tp_snaplen = phdr->h.ppo.caplen;
+               thdr->tp_len = phdr->h.ppo.len;
                break;
 
        case DEFAULT_SWAPPED:
-               thdr->tp_sec = ___constant_swab32(phdr->ppo.ts.tv_sec);
-               thdr->tp_nsec = ___constant_swab32(phdr->ppo.ts.tv_usec) * 1000;
-               thdr->tp_snaplen = ___constant_swab32(phdr->ppo.caplen);
-               thdr->tp_len = ___constant_swab32(phdr->ppo.len);
+               if (pcap_pkthdr_has_ll(phdr, type))
+                       pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+               thdr->tp_sec = ___constant_swab32(phdr->h.ppo.ts.tv_sec);
+               thdr->tp_nsec = ___constant_swab32(phdr->h.ppo.ts.tv_usec) * 
1000;
+               thdr->tp_snaplen = ___constant_swab32(phdr->h.ppo.caplen);
+               thdr->tp_len = ___constant_swab32(phdr->h.ppo.len);
                break;
 
        case NSEC:
-               thdr->tp_sec = phdr->ppn.ts.tv_sec;
-               thdr->tp_nsec = phdr->ppn.ts.tv_nsec;
-               thdr->tp_snaplen = phdr->ppn.caplen;
-               thdr->tp_len = phdr->ppn.len;
+               if (pcap_pkthdr_has_ll(phdr, type))
+                       pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+               thdr->tp_sec = phdr->h.ppn.ts.tv_sec;
+               thdr->tp_nsec = phdr->h.ppn.ts.tv_nsec;
+               thdr->tp_snaplen = phdr->h.ppn.caplen;
+               thdr->tp_len = phdr->h.ppn.len;
                break;
 
        case NSEC_SWAPPED:
-               thdr->tp_sec = ___constant_swab32(phdr->ppn.ts.tv_sec);
-               thdr->tp_nsec = ___constant_swab32(phdr->ppn.ts.tv_nsec);
-               thdr->tp_snaplen = ___constant_swab32(phdr->ppn.caplen);
-               thdr->tp_len = ___constant_swab32(phdr->ppn.len);
+               if (pcap_pkthdr_has_ll(phdr, type))
+                       pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+               thdr->tp_sec = ___constant_swab32(phdr->h.ppn.ts.tv_sec);
+               thdr->tp_nsec = ___constant_swab32(phdr->h.ppn.ts.tv_nsec);
+               thdr->tp_snaplen = ___constant_swab32(phdr->h.ppn.caplen);
+               thdr->tp_len = ___constant_swab32(phdr->h.ppn.len);
                break;
 
        case KUZNETZOV:
-               thdr->tp_sec = phdr->ppk.ts.tv_sec;
-               thdr->tp_nsec = phdr->ppk.ts.tv_usec * 1000;
-               thdr->tp_snaplen = phdr->ppk.caplen;
-               thdr->tp_len = phdr->ppk.len;
-               if (sll) {
-                       sll->sll_ifindex = phdr->ppk.ifindex;
-                       sll->sll_protocol = phdr->ppk.protocol;
-                       sll->sll_pkttype = phdr->ppk.pkttype;
-               }
+               thdr->tp_sec = phdr->h.ppk.ts.tv_sec;
+               thdr->tp_nsec = phdr->h.ppk.ts.tv_usec * 1000;
+               thdr->tp_snaplen = phdr->h.ppk.caplen;
+               thdr->tp_len = phdr->h.ppk.len;
                break;
 
        case KUZNETZOV_SWAPPED:
-               thdr->tp_sec = ___constant_swab32(phdr->ppk.ts.tv_sec);
-               thdr->tp_nsec = ___constant_swab32(phdr->ppk.ts.tv_usec) * 1000;
-               thdr->tp_snaplen = ___constant_swab32(phdr->ppk.caplen);
-               thdr->tp_len = ___constant_swab32(phdr->ppk.len);
-               if (sll) {
-                       sll->sll_ifindex = 
___constant_swab32(phdr->ppk.ifindex);
-                       sll->sll_protocol = 
___constant_swab16(phdr->ppk.protocol);
-                       sll->sll_pkttype = phdr->ppk.pkttype;
-               }
+               thdr->tp_sec = ___constant_swab32(phdr->h.ppk.ts.tv_sec);
+               thdr->tp_nsec = ___constant_swab32(phdr->h.ppk.ts.tv_usec) * 
1000;
+               thdr->tp_snaplen = ___constant_swab32(phdr->h.ppk.caplen);
+               thdr->tp_len = ___constant_swab32(phdr->h.ppk.len);
                break;
 
        case BORKMANN:
-               thdr->tp_sec = phdr->ppb.ts.tv_sec;
-               thdr->tp_nsec = phdr->ppb.ts.tv_nsec;
-               thdr->tp_snaplen = phdr->ppb.caplen;
-               thdr->tp_len = phdr->ppb.len;
-               if (sll) {
-                       sll->sll_ifindex = phdr->ppb.ifindex;
-                       sll->sll_protocol = phdr->ppb.protocol;
-                       sll->sll_hatype = phdr->ppb.hatype;
-                       sll->sll_pkttype = phdr->ppb.pkttype;
-               }
+               thdr->tp_sec = phdr->h.ppb.ts.tv_sec;
+               thdr->tp_nsec = phdr->h.ppb.ts.tv_nsec;
+               thdr->tp_snaplen = phdr->h.ppb.caplen;
+               thdr->tp_len = phdr->h.ppb.len;
                break;
 
        case BORKMANN_SWAPPED:
-               thdr->tp_sec = ___constant_swab32(phdr->ppb.ts.tv_sec);
-               thdr->tp_nsec = ___constant_swab32(phdr->ppb.ts.tv_nsec);
-               thdr->tp_snaplen = ___constant_swab32(phdr->ppb.caplen);
-               thdr->tp_len = ___constant_swab32(phdr->ppb.len);
-               if (sll) {
-                       sll->sll_ifindex = 
___constant_swab16(phdr->ppb.ifindex);
-                       sll->sll_protocol = 
___constant_swab16(phdr->ppb.protocol);
-                       sll->sll_hatype = phdr->ppb.hatype;
-                       sll->sll_pkttype = phdr->ppb.pkttype;
-               }
+               thdr->tp_sec = ___constant_swab32(phdr->h.ppb.ts.tv_sec);
+               thdr->tp_nsec = ___constant_swab32(phdr->h.ppb.ts.tv_nsec);
+               thdr->tp_snaplen = ___constant_swab32(phdr->h.ppb.caplen);
+               thdr->tp_len = ___constant_swab32(phdr->h.ppb.len);
                break;
 
        default:
                bug();
        }
+
+       if (sll)
+               pcap_pkthdr_to_sockaddr(phdr, sll, type);
+}
+
+static inline void pcap_pkthdr_init(pcap_pkthdr_t *phdr, uint32_t link_type)
+{
+       phdr->link_type = link_type;
 }
 
 #define FEATURE_UNKNOWN                (0 << 0)
@@ -659,6 +816,7 @@ static const bool pcap_supported_linktypes[LINKTYPE_MAX] 
__maybe_unused = {
        [LINKTYPE_IEEE802_15_4_LINUX] = true,
        [LINKTYPE_INFINIBAND] = true,
        [LINKTYPE_NETLINK] = true,
+       [LINKTYPE_LINUX_SLL] = true,
 };
 
 static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
diff --git a/pcap_mm.c b/pcap_mm.c
index f7b248e..b4bbae4 100644
--- a/pcap_mm.c
+++ b/pcap_mm.c
@@ -56,8 +56,18 @@ static ssize_t pcap_mm_write(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
        if ((off_t) (ptr_va_curr - ptr_va_start) + hdrsize + len > map_size)
                __pcap_mmap_write_need_remap(fd);
 
-       fmemcpy(ptr_va_curr, &phdr->raw, hdrsize);
+       fmemcpy(ptr_va_curr, &phdr->h.raw, hdrsize);
        ptr_va_curr += hdrsize;
+
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               size_t ll_len = sizeof(struct pcap_pkthdr_ll);
+
+               fmemcpy(ptr_va_curr, &phdr->ll_hdr, ll_len);
+               ptr_va_curr     += ll_len;
+               len             -= ll_len;
+               hdrsize         += ll_len;
+       }
+
        fmemcpy(ptr_va_curr, packet, len);
        ptr_va_curr += len;
 
@@ -72,8 +82,22 @@ static ssize_t pcap_mm_read(int fd __maybe_unused, 
pcap_pkthdr_t *phdr,
        if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > (off_t) 
map_size))
                return -EIO;
 
-       fmemcpy(&phdr->raw, ptr_va_curr, hdrsize);
+       fmemcpy(&phdr->h.raw, ptr_va_curr, hdrsize);
        ptr_va_curr += hdrsize;
+
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               size_t ll_len = sizeof(struct pcap_pkthdr_ll);
+
+               if (unlikely((off_t) (ptr_va_curr + ll_len - ptr_va_start) >
+                                       (off_t) map_size))
+                       return -EIO;
+
+               fmemcpy(&phdr->ll_hdr, ptr_va_curr, ll_len);
+               ptr_va_curr     += hdrsize;
+               hdrsize         += ll_len;
+               len             -= ll_len;
+       }
+
        hdrlen = pcap_get_length(phdr, type);
 
        if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > (off_t) 
map_size))
diff --git a/pcap_rw.c b/pcap_rw.c
index b6be922..651cef7 100644
--- a/pcap_rw.c
+++ b/pcap_rw.c
@@ -21,12 +21,25 @@ static ssize_t pcap_rw_write(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
                             const uint8_t *packet, size_t len)
 {
        ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;
+       ssize_t ll_len = 0;
 
-       ret = write_or_die(fd, &phdr->raw, hdrsize);
+       ret = write_or_die(fd, &phdr->h.raw, hdrsize);
        if (unlikely(ret != hdrsize))
                panic("Failed to write pkt header!\n");
 
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               ll_len = sizeof(struct pcap_pkthdr_ll);
+               int ret_ll = write_or_die(fd, (uint8_t *)&phdr->ll_hdr, ll_len);
+
+               if (unlikely(ret_ll != sizeof(phdr->ll_hdr)))
+                       panic("Failed to write pkt header!\n");
+       }
+
        hdrlen = pcap_get_length(phdr, type);
+       hdrlen  -= ll_len;
+       len     -= ll_len;
+       hdrsize += ll_len;
+
        if (unlikely(hdrlen != (ssize_t) len))
                return -EINVAL;
 
@@ -41,12 +54,25 @@ static ssize_t pcap_rw_read(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
                            uint8_t *packet, size_t len)
 {
        ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;
+       ssize_t ll_len = 0;
 
-       ret = read_or_die(fd, &phdr->raw, hdrsize);
+       ret = read_or_die(fd, &phdr->h.raw, hdrsize);
        if (unlikely(ret != hdrsize))
                return -EIO;
 
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               ll_len = sizeof(struct pcap_pkthdr_ll);
+               int ret_ll = read(fd, &phdr->ll_hdr, ll_len);
+
+               if (unlikely(ret_ll != ll_len))
+                       return -EIO;
+       }
+
        hdrlen = pcap_get_length(phdr, type);
+       hdrlen  -= ll_len;
+       len     -= ll_len;
+       hdrsize += ll_len;
+
        if (unlikely(hdrlen == 0 || hdrlen > (ssize_t) len))
                 return -EINVAL;
 
diff --git a/pcap_sg.c b/pcap_sg.c
index 80c2c5d..fdfef9a 100644
--- a/pcap_sg.c
+++ b/pcap_sg.c
@@ -33,61 +33,40 @@ static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
                iov_slot = 0;
        }
 
-       fmemcpy(iov[iov_slot].iov_base, &phdr->raw, hdrsize);
+       fmemcpy(iov[iov_slot].iov_base, &phdr->h.raw, hdrsize);
        iov[iov_slot].iov_len = hdrsize;
 
-       fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
-       ret = (iov[iov_slot].iov_len += len);
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               ssize_t ll_hdrlen = sizeof(struct pcap_pkthdr_ll);
 
-       iov_slot++;
-       return ret;
-}
-
-static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr,
-                                           size_t hdrsize)
-{
-       int ret;
-       size_t offset = 0;
-       ssize_t remainder;
-
-       offset = iov[iov_slot].iov_len - iov_off_rd;
-       remainder = hdrsize - offset;
-       if (remainder < 0)
-               remainder = 0;
-
-       bug_on(offset + remainder != hdrsize);
-
-       fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
-       iov_off_rd = 0;
-       iov_slot++;
+               fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len,
+                               &phdr->ll_hdr, ll_hdrlen);
 
-       if (iov_slot == array_size(iov)) {
-               iov_slot = 0;
-               ret = readv(fd, iov, array_size(iov));
-               if (unlikely(ret <= 0))
-                       return -EIO;
+               ret = (iov[iov_slot].iov_len += ll_hdrlen);
+               len -= ll_hdrlen;
        }
 
-       fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, 
remainder);
-       iov_off_rd += remainder;
+       fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
+       ret = (iov[iov_slot].iov_len += len);
 
-       return hdrsize;
+       iov_slot++;
+       return ret;
 }
 
-static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t 
hdrlen)
+static ssize_t __pcap_sg_inter_iov_read(int fd, uint8_t *buf, size_t len)
 {
        int ret;
        size_t offset = 0;
        ssize_t remainder;
 
        offset = iov[iov_slot].iov_len - iov_off_rd;
-       remainder = hdrlen - offset;
+       remainder = len - offset;
        if (remainder < 0)
                remainder = 0;
 
-       bug_on(offset + remainder != hdrlen);
+       bug_on(offset + remainder != len);
 
-       fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset);
+       fmemcpy(buf, iov[iov_slot].iov_base + iov_off_rd, offset);
        iov_off_rd = 0;
        iov_slot++;
 
@@ -98,10 +77,10 @@ static ssize_t __pcap_sg_inter_iov_data_read(int fd, 
uint8_t *packet, size_t hdr
                        return -EIO;
        }
 
-       fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, 
remainder);
+       fmemcpy(buf + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
        iov_off_rd += remainder;
 
-       return hdrlen;
+       return len;
 }
 
 static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
@@ -109,17 +88,39 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
 {
        ssize_t ret = 0;
        size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
+       ssize_t ll_len = 0;
 
        if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
-               fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, 
hdrsize);
+               fmemcpy(&phdr->h.raw, iov[iov_slot].iov_base + iov_off_rd, 
hdrsize);
                iov_off_rd += hdrsize;
        } else {
-               ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, hdrsize);
+               ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)phdr, hdrsize);
                if (unlikely(ret < 0))
                        return ret;
        }
 
+       if (pcap_pkthdr_has_ll(phdr, type)) {
+               ll_len = sizeof(phdr->ll_hdr);
+
+               if (likely(iov[iov_slot].iov_len - iov_off_rd >= ll_len)) {
+                       fmemcpy((uint8_t *)&phdr->ll_hdr, 
iov[iov_slot].iov_base +
+                                       iov_off_rd, ll_len);
+
+                       iov_off_rd += ll_len;
+               } else {
+                       ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)phdr,
+                                       ll_len);
+
+                       if (unlikely(ret < 0))
+                               return ret;
+               }
+       }
+
        hdrlen = pcap_get_length(phdr, type);
+       len     -= ll_len;
+       hdrlen  -= ll_len;
+       hdrsize += ll_len;
+
        if (unlikely(hdrlen == 0 || hdrlen > len))
                return -EINVAL;
 
@@ -127,7 +128,7 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
                fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, hdrlen);
                iov_off_rd += hdrlen;
        } else {
-               ret = __pcap_sg_inter_iov_data_read(fd, packet, hdrlen);
+               ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)packet, hdrlen);
                if (unlikely(ret < 0))
                        return ret;
        }
diff --git a/sock.c b/sock.c
index 7cfa4a0..9c3d789 100644
--- a/sock.c
+++ b/sock.c
@@ -33,6 +33,16 @@ int pf_socket(void)
        return sock;
 }
 
+int pf_socket_dgram(void)
+{
+       int sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+       if (unlikely(sock < 0))
+               panic("Creation of PF dgram socket failed: %s\n",
+                               strerror(errno));
+
+       return sock;
+}
+
 /* Avail in kernel >= 3.14
  * in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option)
  */
diff --git a/sock.h b/sock.h
index 50f7102..e63cd32 100644
--- a/sock.h
+++ b/sock.h
@@ -3,6 +3,7 @@
 
 extern int af_socket(int af);
 extern int pf_socket(void);
+extern int pf_socket_dgram(void);
 extern void set_nonblocking(int fd);
 extern int set_nonblocking_sloppy(int fd);
 extern int set_reuseaddr(int fd);
-- 
2.4.2

-- 
You received this message because you are subscribed to the Google Groups 
"netsniff-ng" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to