aboutsummaryrefslogtreecommitdiff
path: root/pcap-linux.c
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2019-01-18 15:26:52 -0800
committerFlorian Fainelli <f.fainelli@gmail.com>2019-01-23 16:29:23 -0800
commit993db3800d7d39791a67bcaa671d1b87309f216e (patch)
treef9ad697b58a5bbc981f55485ae3b373e8a1df22f /pcap-linux.c
parentc83e81ea443de5a1250ad5f8977e175ddae7a05c (diff)
Add support for DSA link-layer types
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.
Diffstat (limited to 'pcap-linux.c')
-rw-r--r--pcap-linux.c98
1 files changed, 97 insertions, 1 deletions
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 ================== */
/*