]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add support for DSA link-layer types 796/head
authorFlorian Fainelli <[email protected]>
Fri, 18 Jan 2019 23:26:52 +0000 (15:26 -0800)
committerFlorian Fainelli <[email protected]>
Thu, 24 Jan 2019 00:29:23 +0000 (16:29 -0800)
Linux kernel 4.20 and greater can report what type of Distributed Switch
Architecture tagging protocol is used on the DSA master/management
interface. We need to map the protocol to a specific DLT and linktype
value in the pcap file because these protocols typically cannot be
decoded simply by making use of heuristics. The sysfs attribute that is
being checked and parsed is documented in this commit:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a3d7e01da06013dc580641a1da57c3b482d58157

For now, the description of the Broadcom 4 byte Ethernet switch tagging
protocol is provided and more tags can be added in the future using the
same infrastructure.

pcap-common.c
pcap-linux.c
pcap.c
pcap/dlt.h

index c7d6f60cff4b5b70286b6cfafb6ddf2b2a872160..e2bfbb2f704523dfdf6f4c981a25a70342ba7613 100644 (file)
  */
 #define LINKTYPE_VPP_DISPATCH  280
 
-#define LINKTYPE_MATCHING_MAX  280             /* highest value in the "matching" range */
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_BRCM  281
+#define LINKTYPE_DSA_TAG_BRCM_PREPEND  282
+
+#define LINKTYPE_MATCHING_MAX  282             /* highest value in the "matching" range */
 
 /*
  * The DLT_ and LINKTYPE_ values in the "matching" range should be the
index 19bd86592215e18fb1dbd9ec4aae5f8da475fe29..f7c456ffbd4587a40ef939ef0db15cdb180289c1 100644 (file)
@@ -332,7 +332,6 @@ struct pcap_linux {
 #ifdef HAVE_SYS_EVENTFD_H
        int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */
 #endif
-
 };
 
 /*
@@ -506,6 +505,9 @@ static struct sock_fprog    total_fcode
        = { 1, &total_insn };
 #endif /* SO_ATTACH_FILTER */
 
+static int     iface_dsa_get_proto_info(const char *device, pcap_t *handle,
+    char *ebuf);
+
 pcap_t *
 pcap_create_interface(const char *device, char *ebuf)
 {
@@ -3298,6 +3300,28 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
                 * others?
                 */
                if (!is_wifi(sock_fd, device)) {
+                       int ret;
+
+                       /*
+                        * This is not a Wi-Fi device but it could be
+                        * a DSA master/management network device.
+                        */
+                       ret = iface_dsa_get_proto_info(device, handle,
+                                                      handle->errbuf);
+                       if (ret < 0)
+                               return;
+
+                       if (ret == 1) {
+                               /*
+                                * This is a DSA master/management network
+                                * device linktype is already set by
+                                * iface_dsa_get_proto_info() set an
+                                * appropriate offset here.
+                                */
+                               handle->offset = 2;
+                               break;
+                       }
+
                        /*
                         * It's not a Wi-Fi device; offer DOCSIS.
                         */
@@ -6900,6 +6924,78 @@ iface_get_offload(pcap_t *handle _U_)
 
 #endif /* HAVE_PF_PACKET_SOCKETS */
 
+static struct dsa_proto {
+       const char *name;
+       bpf_u_int32 linktype;
+} dsa_protos[] = {
+       /*
+        * None is special and indicates that the interface does not have
+        * any tagging protocol configured, and is therefore a standard
+        * Ethernet interface.
+        */
+       { "none", DLT_EN10MB },
+       { "brcm", DLT_DSA_TAG_BRCM },
+       { "brcm-prepend", DLT_DSA_TAG_BRCM_PREPEND },
+};
+
+static int     iface_dsa_get_proto_info(const char *device, pcap_t *handle,
+    char *ebuf)
+{
+       char *pathstr;
+       unsigned int i;
+       char buf[256];
+       ssize_t r;
+       int fd;
+
+       fd = asprintf(&pathstr, "/sys/class/net/%s/dsa/tagging", device);
+       if (fd < 0) {
+               pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                         fd, "asprintf");
+               return PCAP_ERROR;
+       }
+
+       fd = open(pathstr, O_RDONLY);
+       free(pathstr);
+       /*
+        * This is not fatal, kernel >= 4.20 *might* expose this attribute
+        */
+       if (fd < 0)
+               return 0;
+
+       r = read(fd, buf, sizeof(buf) - 1);
+       close(fd);
+       if (r <= 0) {
+               pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                         r, "read");
+               return PCAP_ERROR;
+       }
+
+       /*
+        * Buffer should be LF terminated.
+        */
+       if (buf[r - 1] == '\n')
+               r--;
+       buf[r] = '\0';
+
+       for (i = 0; i < sizeof(dsa_protos) / sizeof(dsa_protos[0]); i++) {
+               if (strlen(dsa_protos[i].name) == r &&
+                   !strcmp(buf, dsa_protos[i].name)) {
+                       handle->linktype = dsa_protos[i].linktype;
+                       switch (dsa_protos[i].linktype) {
+                       case DLT_EN10MB:
+                               return 0;
+                       default:
+                               return 1;
+                       }
+               }
+       }
+
+       pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                     "unsupported DSA tag: %s", buf);
+
+       return PCAP_ERROR;
+}
+
 /* ===== Functions to interface to the older kernels ================== */
 
 /*
diff --git a/pcap.c b/pcap.c
index 84dbe9a881f89c47ee7bfd423f4b7945b0a9cabc..c410ca5a5a946e6651e0196280ca1d9b8367bb2e 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -3002,6 +3002,8 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
        DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
        DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+       DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+       DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
        DLT_CHOICE_SENTINEL
 };
 
index 028da2f5bfba5d6803e5623276c2110ca20b8dc3..de01888f9e0f1fa634f3846b67ecf6db94c548d8 100644 (file)
  */
 #define DLT_VPP_DISPATCH       280
 
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define DLT_DSA_TAG_BRCM       281
+#define DLT_DSA_TAG_BRCM_PREPEND       282
+
 /*
  * In case the code that includes this file (directly or indirectly)
  * has also included OS files that happen to define DLT_MATCHING_MAX,
 #ifdef DLT_MATCHING_MAX
 #undef DLT_MATCHING_MAX
 #endif
-#define DLT_MATCHING_MAX       280     /* highest value in the "matching" range */
+#define DLT_MATCHING_MAX       282     /* highest value in the "matching" range */
 
 /*
  * DLT and savefile link type values are split into a class and