This diff teaches tcpdump to recognize MPLS pseudowires with control
words only. This should not be a problem since the control words are
used by default unless configured otherwise (ldpd does this).

It also makes possible to print encapsulated ethernet packets with the
new ethernet print function ether_tryprint(). Ethernet packets
encapsulated in MPLS pseudowires with no control words won't be shown,
because, as discussed previously, we have to make a lot of guesses to
find that out.

ok?

Note:
this is actually an updated diff of an old email I sent last year, the
differences between that and this are:
 * Use 'extern' in interface.h so the prototype looks like the others;
 * Re ordered the variable definition sequence;
 * print-mpls.c now uses the kernel headers to obtain the pseudowire
   macro definitions like: CW_ZERO_MASK and CW_FRAG_MASK;


Index: interface.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v
retrieving revision 1.66
diff -u -p -r1.66 interface.h
--- interface.h 15 Nov 2015 20:35:36 -0000      1.66
+++ interface.h 7 Jul 2016 17:27:29 -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 *);
+extern void ether_tryprint(const u_char *, u_int, 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.30
diff -u -p -r1.30 print-ether.c
--- print-ether.c       16 Nov 2015 00:16:39 -0000      1.30
+++ print-ether.c       7 Jul 2016 17:27:29 -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, 1);
+}
+
+void
+ether_tryprint(const u_char *p, u_int length, int first_header)
+{
+       struct ether_header *ep;
+       u_int caplen = snapend - p;
+       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;
@@ -152,14 +157,15 @@ ether_if_print(u_char *user, const struc
                                default_print(p, caplen);
                }
        }
-       if (xflag) {
+       if (xflag && first_header) {
                if (eflag)
                        default_print(packetp, snapend - packetp);
                else
                        default_print(p, caplen);
        }
  out:
-       putchar('\n');
+       if (first_header)
+               putchar('\n');
 }
 
 /*
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        7 Jul 2016 17:27:29 -0000
@@ -26,15 +26,24 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netmpls/mpls.h>
+
 #include <stdio.h>
 
 #include "interface.h"
 #include "extract.h"               /* must come after interface.h */
 
+#define CW_SEQUENCE_MASK       (0x0000ffffU)
+
+int controlword_tryprint(const u_char **, u_int *);
+
 void
 mpls_print(const u_char *bp, u_int len)
 {
        u_int32_t tag, label, exp, bottom, ttl;
+       int has_cw;
 
  again:
        if (bp + sizeof(tag) > snapend)
@@ -56,6 +65,9 @@ mpls_print(const u_char *bp, u_int len)
        if (!bottom)
                goto again;
 
+       /* Handle pseudowire control word. */
+       has_cw = controlword_tryprint(&bp, &len);
+
        /*
         * guessing the underlying protocol is about all we can do if
         * it's not explicitly defined.
@@ -107,7 +119,34 @@ mpls_print(const u_char *bp, u_int len)
                }
        }
 
+       if (has_cw)
+               ether_tryprint(bp, len, 0);
+
        return;
 trunc:
        printf("[|mpls]");
+}
+
+/* Print control word if any and returns 1 on success. */
+int
+controlword_tryprint(const u_char **bp, u_int *lenp)
+{
+       uint32_t cw, frag, seq;
+
+       if (*lenp < 4)
+               return (0);
+
+       cw = EXTRACT_32BITS(*bp);
+       if (cw & CW_ZERO_MASK)
+               return (0);
+
+       *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);
+
+       return (1);
 }

Reply via email to