From: Vadim Kochan <[email protected]>

Use Linux "cooked" header for Netlink interface automatically
or as replacement of L2 header if "--cooked" option is specified.

    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 |  12 +-
 netsniff-ng.c |  26 +++-
 pcap_io.h     | 400 ++++++++++++++++++++++++++++++++++++----------------------
 pcap_mm.c     |   5 +-
 pcap_rw.c     |   4 +-
 pcap_sg.c     |   8 +-
 sock.c        |  10 ++
 sock.h        |   1 +
 9 files changed, 305 insertions(+), 162 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..e7c50cd 100644
--- a/netsniff-ng.8
+++ b/netsniff-ng.8
@@ -84,7 +84,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 +257,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 +596,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..1f7c5a5 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -69,7 +69,9 @@ 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 +108,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 +240,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 +594,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 +913,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 +965,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 +1048,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 +1152,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 +1211,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 +1457,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 +1531,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_devtype_to_linktype(ctx.device_in);
 
                if (!ctx.device_out) {
                        ctx.dump = 0;
diff --git a/pcap_io.h b/pcap_io.h
index 35faa51..4c4ec95 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -58,16 +58,31 @@ struct pcap_timeval_ns {
        int32_t tv_nsec;
 };
 
+struct linux_sll {
+       uint16_t pkttype;
+       uint16_t hatype;
+       uint16_t len;
+       uint8_t addr[8];
+       uint16_t protocol;
+};
+#define LINUX_SLL_SIZE (sizeof(struct linux_sll))
+
 struct pcap_pkthdr {
        struct pcap_timeval ts;
        uint32_t caplen;
        uint32_t len;
+
+       /* depends on link type */
+       struct linux_sll sll;
 };
 
 struct pcap_pkthdr_ns {
        struct pcap_timeval_ns ts;
        uint32_t caplen;
        uint32_t len;
+
+       /* depends on link type */
+       struct linux_sll sll;
 };
 
 struct pcap_pkthdr_kuz {
@@ -90,12 +105,15 @@ 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;
+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;
+       uint32_t link_type;
 } pcap_pkthdr_t;
 
 enum pcap_type {
@@ -192,6 +210,20 @@ static inline int pcap_devtype_to_linktype(const char 
*ifname)
        }
 }
 
+static inline bool pcap_has_sll_hdr(pcap_pkthdr_t *phdr)
+{
+       switch (phdr->link_type) {
+       case LINKTYPE_NETLINK:
+       case ___constant_swab32(LINKTYPE_NETLINK):
+               return true;
+       case LINKTYPE_LINUX_SLL:
+       case ___constant_swab32(LINKTYPE_LINUX_SLL):
+               return true;
+       }
+
+       return false;
+}
+
 static inline void pcap_check_magic(uint32_t magic)
 {
        switch (magic) {
@@ -229,21 +261,27 @@ static inline bool pcap_magic_is_swapped(uint32_t magic)
 
 static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
 {
+       int caplen;
+
        switch (type) {
-#define CASE_RET_CAPLEN(what, member, swap) \
+#define CASE_RET_CAPLEN(what, member, swap, check_sll) \
        case (what): \
-               return (swap ? ___constant_swab32(phdr->member.caplen) : \
-                       phdr->member.caplen)
-
-       CASE_RET_CAPLEN(DEFAULT, ppo, 0);
-       CASE_RET_CAPLEN(NSEC, ppn, 0);
-       CASE_RET_CAPLEN(KUZNETZOV, ppk, 0);
-       CASE_RET_CAPLEN(BORKMANN, ppb, 0);
-
-       CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
-       CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1);
-       CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
-       CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
+               caplen = swap ? ___constant_swab32(phdr->h.member.caplen) : \
+                       phdr->h.member.caplen; \
+               if (check_sll && pcap_has_sll_hdr(phdr)) \
+                       caplen -= swap ? ___constant_swab32(LINUX_SLL_SIZE) : \
+                                       LINUX_SLL_SIZE; \
+               return caplen;
+
+       CASE_RET_CAPLEN(DEFAULT, ppo, 0, true);
+       CASE_RET_CAPLEN(NSEC, ppn, 0, true);
+       CASE_RET_CAPLEN(KUZNETZOV, ppk, 0, false);
+       CASE_RET_CAPLEN(BORKMANN, ppb, 0, false);
+
+       CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1, true);
+       CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1, true);
+       CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1, false);
+       CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1, false);
 
        default:
                bug();
@@ -252,21 +290,27 @@ static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, 
enum pcap_type type)
 
 static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, 
u32 len)
 {
+       int caplen;
+
        switch (type) {
-#define CASE_SET_CAPLEN(what, member, swap) \
+#define CASE_SET_CAPLEN(what, member, swap, check_sll) \
        case (what): \
-               phdr->member.caplen = (swap ? ___constant_swab32(len) : len); \
-               break
+               caplen = (swap ? ___constant_swab32(len) : len); \
+               if (check_sll && pcap_has_sll_hdr(phdr)) \
+                       caplen += swap ? ___constant_swab32(LINUX_SLL_SIZE) : \
+                               LINUX_SLL_SIZE; \
+               phdr->h.member.caplen = caplen; \
+               break;
 
-       CASE_SET_CAPLEN(DEFAULT, ppo, 0);
-       CASE_SET_CAPLEN(NSEC, ppn, 0);
-       CASE_SET_CAPLEN(KUZNETZOV, ppk, 0);
-       CASE_SET_CAPLEN(BORKMANN, ppb, 0);
+       CASE_SET_CAPLEN(DEFAULT, ppo, 0, true);
+       CASE_SET_CAPLEN(NSEC, ppn, 0, true);
+       CASE_SET_CAPLEN(KUZNETZOV, ppk, 0, false);
+       CASE_SET_CAPLEN(BORKMANN, ppb, 0, false);
 
-       CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
-       CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1);
-       CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
-       CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
+       CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1, true);
+       CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1, true);
+       CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1, false);
+       CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1, false);
 
        default:
                bug();
@@ -276,19 +320,21 @@ static inline void pcap_set_length(pcap_pkthdr_t *phdr, 
enum pcap_type type, u32
 static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)
 {
        switch (type) {
-#define CASE_RET_HDRLEN(what, member) \
+#define CASE_RET_HDRLEN(what, member, check_sll) \
        case (what): \
-               return sizeof(phdr->member)
+               if (check_sll && !pcap_has_sll_hdr(phdr)) \
+                       return sizeof(phdr->h.member) - LINUX_SLL_SIZE; \
+               return sizeof(phdr->h.member);
 
-       CASE_RET_HDRLEN(DEFAULT, ppo);
-       CASE_RET_HDRLEN(NSEC, ppn);
-       CASE_RET_HDRLEN(KUZNETZOV, ppk);
-       CASE_RET_HDRLEN(BORKMANN, ppb);
+       CASE_RET_HDRLEN(DEFAULT, ppo, true);
+       CASE_RET_HDRLEN(NSEC, ppn, true);
+       CASE_RET_HDRLEN(KUZNETZOV, ppk, false);
+       CASE_RET_HDRLEN(BORKMANN, ppb, false);
 
-       CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo);
-       CASE_RET_HDRLEN(NSEC_SWAPPED, ppn);
-       CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk);
-       CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb);
+       CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo, true);
+       CASE_RET_HDRLEN(NSEC_SWAPPED, ppn, true);
+       CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk, false);
+       CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb, false);
 
        default:
                bug();
@@ -297,25 +343,32 @@ static inline u32 pcap_get_hdr_length(pcap_pkthdr_t 
*phdr, enum pcap_type type)
 
 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 pcap_get_length(phdr, type) + pcap_get_hdr_length(phdr, type);
+}
 
-       CASE_RET_TOTLEN(DEFAULT, ppo, 0);
-       CASE_RET_TOTLEN(NSEC, ppn, 0);
-       CASE_RET_TOTLEN(KUZNETZOV, ppk, 0);
-       CASE_RET_TOTLEN(BORKMANN, ppb, 0);
+static inline void sockaddr_to_linux_sll(struct sockaddr_ll *sll,
+               struct linux_sll *ll)
+{
+       ll->protocol    = sll->sll_protocol;
+       ll->hatype      = cpu_to_be16(sll->sll_hatype);
+       ll->pkttype     = cpu_to_be16(sll->sll_pkttype);
+       ll->len         = cpu_to_be16(sll->sll_halen);
+       memcpy(ll->addr, sll->sll_addr, 8);
+}
 
-       CASE_RET_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
-       CASE_RET_TOTLEN(NSEC_SWAPPED, ppn, 1);
-       CASE_RET_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
-       CASE_RET_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+static inline void linux_sll_to_sockaddr(struct linux_sll *ll,
+               struct sockaddr_ll *sll)
+{
+       sll->sll_protocol = ll->protocol;
+       sll->sll_hatype   = be16_to_cpu(ll->hatype);
+       sll->sll_pkttype  = be16_to_cpu(ll->pkttype);
+       sll->sll_halen    = be16_to_cpu(ll->len);
+       memcpy(sll->sll_addr, ll->addr, 8);
+}
 
-       default:
-               bug();
-       }
+static inline void pcap_pkthdr_init(pcap_pkthdr_t *phdr, uint32_t link_type)
+{
+       phdr->link_type = link_type;
 }
 
 static inline void
@@ -324,77 +377,99 @@ __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, 
uint32_t snaplen,
                             struct sockaddr_ll *sll, pcap_pkthdr_t *phdr,
                             enum pcap_type type)
 {
+       int sll_len = 0;
+
        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;
+               if (pcap_has_sll_hdr(phdr)) {
+                       sockaddr_to_linux_sll(sll, &phdr->h.ppo.sll);
+                       sll_len = LINUX_SLL_SIZE;
+               }
+
+               phdr->h.ppo.ts.tv_sec = sec;
+               phdr->h.ppo.ts.tv_usec = nsec / 1000;
+               phdr->h.ppo.caplen = snaplen + sll_len;
+               phdr->h.ppo.len = len + sll_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);
+               if (pcap_has_sll_hdr(phdr)) {
+                       sockaddr_to_linux_sll(sll, &phdr->h.ppo.sll);
+                       sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+               }
+
+               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) + sll_len;
+               phdr->h.ppo.len = ___constant_swab32(len) + sll_len;
                break;
 
        case NSEC:
-               phdr->ppn.ts.tv_sec = sec;
-               phdr->ppn.ts.tv_nsec = nsec;
-               phdr->ppn.caplen = snaplen;
-               phdr->ppn.len = len;
+               if (pcap_has_sll_hdr(phdr)) {
+                       sockaddr_to_linux_sll(sll, &phdr->h.ppn.sll);
+                       sll_len = LINUX_SLL_SIZE;
+               }
+
+               phdr->h.ppn.ts.tv_sec = sec;
+               phdr->h.ppn.ts.tv_nsec = nsec;
+               phdr->h.ppn.caplen = snaplen + sll_len;
+               phdr->h.ppn.len = len + sll_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);
+               if (pcap_has_sll_hdr(phdr)) {
+                       sockaddr_to_linux_sll(sll, &phdr->h.ppn.sll);
+                       sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+               }
+
+               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) + sll_len;
+               phdr->h.ppn.len = ___constant_swab32(len) + sll_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:
@@ -433,82 +508,106 @@ static inline void 
pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
                                              struct tpacket2_hdr *thdr,
                                              struct sockaddr_ll *sll)
 {
+       int sll_len = 0;
+
        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_has_sll_hdr(phdr)) {
+                       linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+                       sll_len = LINUX_SLL_SIZE;
+               }
+
+               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 - sll_len;
+               thdr->tp_len = phdr->h.ppo.len - sll_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_has_sll_hdr(phdr)) {
+                       linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+                       sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+               }
+
+               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) -
+                       sll_len;
+               thdr->tp_len = ___constant_swab32(phdr->h.ppo.len) - sll_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_has_sll_hdr(phdr)) {
+                       linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+                       sll_len = LINUX_SLL_SIZE;
+               }
+
+               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 - sll_len;
+               thdr->tp_len = phdr->h.ppn.len - sll_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_has_sll_hdr(phdr)) {
+                       linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+                       sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+               }
+
+               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) -
+                       sll_len;
+               thdr->tp_len = ___constant_swab32(phdr->h.ppn.len) - sll_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;
+               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;
                if (sll) {
-                       sll->sll_ifindex = phdr->ppk.ifindex;
-                       sll->sll_protocol = phdr->ppk.protocol;
-                       sll->sll_pkttype = phdr->ppk.pkttype;
+                       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:
-               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);
+               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);
                if (sll) {
-                       sll->sll_ifindex = 
___constant_swab32(phdr->ppk.ifindex);
-                       sll->sll_protocol = 
___constant_swab16(phdr->ppk.protocol);
-                       sll->sll_pkttype = phdr->ppk.pkttype;
+                       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:
-               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;
+               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;
                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;
+                       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:
-               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);
+               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);
                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;
+                       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;
 
@@ -659,6 +758,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..b6a350d 100644
--- a/pcap_mm.c
+++ b/pcap_mm.c
@@ -56,7 +56,7 @@ 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;
        fmemcpy(ptr_va_curr, packet, len);
        ptr_va_curr += len;
@@ -72,8 +72,9 @@ 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;
+
        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..e6ebc94 100644
--- a/pcap_rw.c
+++ b/pcap_rw.c
@@ -22,7 +22,7 @@ static ssize_t pcap_rw_write(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
 {
        ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 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");
 
@@ -42,7 +42,7 @@ static ssize_t pcap_rw_read(int fd, pcap_pkthdr_t *phdr, enum 
pcap_type type,
 {
        ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;
 
-       ret = read_or_die(fd, &phdr->raw, hdrsize);
+       ret = read_or_die(fd, &phdr->h.raw, hdrsize);
        if (unlikely(ret != hdrsize))
                return -EIO;
 
diff --git a/pcap_sg.c b/pcap_sg.c
index 80c2c5d..00793fe 100644
--- a/pcap_sg.c
+++ b/pcap_sg.c
@@ -33,7 +33,7 @@ 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);
@@ -57,7 +57,7 @@ static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, 
pcap_pkthdr_t *phdr,
 
        bug_on(offset + remainder != hdrsize);
 
-       fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
+       fmemcpy(&phdr->h.raw, iov[iov_slot].iov_base + iov_off_rd, offset);
        iov_off_rd = 0;
        iov_slot++;
 
@@ -68,7 +68,7 @@ static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, 
pcap_pkthdr_t *phdr,
                        return -EIO;
        }
 
-       fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, 
remainder);
+       fmemcpy(&phdr->h.raw + offset, iov[iov_slot].iov_base + iov_off_rd, 
remainder);
        iov_off_rd += remainder;
 
        return hdrsize;
@@ -111,7 +111,7 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, 
enum pcap_type type,
        size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
 
        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);
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