[ovs-dev] [PATCH] pcap-file: Add support for Linux SLL formatted PCAP files.

Ben Pfaff blp at ovn.org
Sun Nov 11 23:41:08 UTC 2018


Someone sent me one of these and OVS couldn't read it.  This fixes the
problem.

Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 lib/pcap-file.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/lib/pcap-file.c b/lib/pcap-file.c
index 81a094c2a01f..0f34c5e83cda 100644
--- a/lib/pcap-file.c
+++ b/lib/pcap-file.c
@@ -39,9 +39,15 @@ enum ts_resolution {
     PCAP_NSEC,
 };
 
+enum network_type {
+    PCAP_ETHERNET = 0,
+    PCAP_LINUX_SLL = 0x71
+};
+
 struct pcap_file {
     FILE *file;
     enum ts_resolution resolution;
+    enum network_type network;
 };
 
 struct pcap_hdr {
@@ -130,10 +136,13 @@ ovs_pcap_read_header(struct pcap_file *p_file)
         VLOG_WARN("failed to read pcap header: %s", ovs_retval_to_string(error));
         return error;
     }
+    bool byte_swap;
     if (ph.magic_number == 0xa1b2c3d4 || ph.magic_number == 0xd4c3b2a1) {
+        byte_swap = ph.magic_number == 0xd4c3b2a1;
         p_file->resolution = PCAP_USEC;
     } else if (ph.magic_number == 0xa1b23c4d ||
                ph.magic_number == 0x4d3cb2a1) {
+        byte_swap = ph.magic_number == 0x4d3cb2a1;
         p_file->resolution = PCAP_NSEC;
     } else {
         VLOG_WARN("bad magic 0x%08"PRIx32" reading pcap file "
@@ -141,6 +150,13 @@ ovs_pcap_read_header(struct pcap_file *p_file)
                   "or 0x4d3cb2a1)", ph.magic_number);
         return EPROTO;
     }
+    p_file->network = byte_swap ? uint32_byteswap(ph.network) : ph.network;
+    if (p_file->network != PCAP_ETHERNET &&
+        p_file->network != PCAP_LINUX_SLL) {
+        VLOG_WARN("unknown network type %"PRIu16" reading pcap file",
+                  p_file->network);
+        return EPROTO;
+    }
     return 0;
 }
 
@@ -218,6 +234,44 @@ ovs_pcap_read(struct pcap_file *p_file, struct dp_packet **bufp,
         dp_packet_delete(buf);
         return error;
     }
+
+    if (p_file->network == PCAP_LINUX_SLL) {
+        /* This format doesn't include the destination Ethernet address, which
+         * is weird. */
+
+        struct sll_header {
+            ovs_be16 packet_type;
+            ovs_be16 arp_hrd;
+            ovs_be16 lla_len;
+            struct eth_addr dl_src;
+            ovs_be16 reserved;
+            ovs_be16 protocol;
+        };
+        const struct sll_header *sll;
+        if (len < sizeof *sll) {
+            VLOG_WARN("pcap packet too short for SLL header");
+            dp_packet_delete(buf);
+            return EPROTO;
+        }
+
+        /* Pull Linux SLL header. */
+        sll = dp_packet_pull(buf, sizeof *sll);
+        if (sll->lla_len != htons(6)) {
+            ovs_hex_dump(stdout, sll, sizeof *sll, 0, false);
+            VLOG_WARN("bad SLL header");
+            dp_packet_delete(buf);
+            return EPROTO;
+        }
+
+        /* Push Ethernet header. */
+        struct eth_header eth = {
+            /* eth_dst is all zeros because the format doesn't include it. */
+            .eth_src = sll->dl_src,
+            .eth_type = sll->protocol,
+        };
+        dp_packet_push(buf, &eth, sizeof eth);
+    }
+
     *bufp = buf;
     return 0;
 }
-- 
2.16.1



More information about the dev mailing list