summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pcap-common.c8
-rw-r--r--pcap-linux.c98
-rw-r--r--pcap.c2
-rw-r--r--pcap/dlt.h8
4 files changed, 113 insertions, 3 deletions
diff --git a/pcap-common.c b/pcap-common.c
index 84c90e2b..5b45f58d 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -1141,7 +1141,13 @@
*/
#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
diff --git a/pcap-linux.c b/pcap-linux.c
index 19bd8659..f7c456ff 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -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 84dbe9a8..c410ca5a 100644
--- 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
};
diff --git a/pcap/dlt.h b/pcap/dlt.h
index 028da2f5..de01888f 100644
--- a/pcap/dlt.h
+++ b/pcap/dlt.h
@@ -1427,6 +1427,12 @@
#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,
* with a different value (perhaps because that OS hasn't picked up
@@ -1436,7 +1442,7 @@
#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