This diff adds support for detection of pseudowires inside of MPLS tagged
packets. Basically it teaches MPLS to look for ethernet headers when there
is no sign of IP headers.

Index: interface.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v
retrieving revision 1.65
diff -u -p -r1.65 interface.h
--- interface.h 5 Apr 2015 17:02:57 -0000       1.65
+++ interface.h 17 Jul 2015 18:16:43 -0000
@@ -205,6 +205,7 @@ extern void pfsync_if_print(u_char *, co
 extern void pfsync_ip_print(const u_char *, u_int, const u_char *);
 extern void ether_if_print(u_char *, const struct pcap_pkthdr *,
        const u_char *);
+void ether_tryprint(const u_char *, u_int);
 extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char 
*);
 extern void ppp_ether_if_print(u_char *, const struct pcap_pkthdr *,
        const u_char *);
Index: print-ether.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v
retrieving revision 1.29
diff -u -p -r1.29 print-ether.c
--- print-ether.c       16 Jan 2015 06:40:21 -0000      1.29
+++ print-ether.c       17 Jul 2015 18:16:43 -0000
@@ -89,29 +89,34 @@ u_short extracted_ethertype;
 void
 ether_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
 {
-       u_int caplen = h->caplen;
-       u_int length = h->len;
-       struct ether_header *ep;
-       u_short ether_type;
-
        ts_print(&h->ts);
 
-       if (caplen < sizeof(struct ether_header)) {
-               printf("[|ether]");
-               goto out;
-       }
-
        /*
         * Some printers want to get back at the ethernet addresses,
         * and/or check that they're not walking off the end of the packet.
         * Rather than pass them all the way down, we set these globals.
         */
-       packetp = p;
-       snapend = p + caplen;
+       snapend = p + h->caplen;
+
+       ether_tryprint(p, h->len);
+}
+
+void
+ether_tryprint(const u_char *p, u_int length)
+{
+       u_int caplen = snapend - p;
+       struct ether_header *ep;
+       u_short ether_type;
+
+       if (caplen < sizeof(struct ether_header)) {
+               printf("[|ether]");
+               goto out;
+       }
 
        if (eflag)
                ether_print(p, length);
 
+       packetp = p;
        length -= sizeof(struct ether_header);
        caplen -= sizeof(struct ether_header);
        ep = (struct ether_header *)p;
Index: print-mpls.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-mpls.c,v
retrieving revision 1.2
diff -u -p -r1.2 print-mpls.c
--- print-mpls.c        30 Jun 2010 19:01:06 -0000      1.2
+++ print-mpls.c        17 Jul 2015 18:16:43 -0000
@@ -31,6 +31,12 @@
 #include "interface.h"
 #include "extract.h"               /* must come after interface.h */
 
+#define CW_ZERO_MASK           (0xf0000000U)
+#define CW_FRAG_MASK           (0x0fff0000U)
+#define CW_SEQUENCE_MASK       (0x0000ffffU)
+
+void controlword_print(const u_char **, u_int *);
+
 void
 mpls_print(const u_char *bp, u_int len)
 {
@@ -56,6 +62,9 @@ mpls_print(const u_char *bp, u_int len)
        if (!bottom)
                goto again;
 
+       /* Handle pseudowire control word if any. */
+       controlword_print(&bp, &len);
+
        /*
         * guessing the underlying protocol is about all we can do if
         * it's not explicitly defined.
@@ -99,15 +108,48 @@ mpls_print(const u_char *bp, u_int len)
 
                switch (bp[0] & 0xf0) {
                case 0x40:
+                       /*
+                        * IPv4 second nibble is the header length and its
+                        * value must be at least 5 bytes long.
+                        */
+                       if ((bp[0] & 0x0f) < 5) {
+                               ether_tryprint(bp, len);
+                               break;
+                       }
+
                        ip_print(bp, len);
                        break;
                case 0x60:
                        ip6_print(bp, len);
                        break;
+               default:
+                       ether_tryprint(bp, len);
+                       break;
                }
        }
 
        return;
 trunc:
        printf("[|mpls]");
+}
+
+void
+controlword_print(const u_char **bp, u_int *lenp)
+{
+       u_int32_t cw, frag, seq;
+
+       if (*lenp < 4)
+               return;
+
+       cw = EXTRACT_32BITS(*bp);
+       if (cw & CW_ZERO_MASK)
+               return;
+
+       *bp += sizeof(cw);
+       *lenp += sizeof(cw);
+
+       frag = (cw & CW_FRAG_MASK) >> 16;
+       seq = cw & CW_SEQUENCE_MASK;
+
+       printf("CW(frag %u, sequence %u) ", frag, seq);
 }

Reply via email to