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); }