xref: /freebsd/contrib/tcpdump/print-sl.c (revision 3340d77368116708ab5b5b95acf6c9c710528300)
14edb46e9SPaul Traina /*
2699fc314SBill Fenner  * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
204edb46e9SPaul Traina  */
214edb46e9SPaul Traina 
22*3340d773SGleb Smirnoff /* \summary: Compressed Serial Line Internet Protocol printer */
23*3340d773SGleb Smirnoff 
24a88113a8SBill Fenner #ifdef HAVE_CONFIG_H
25a88113a8SBill Fenner #include "config.h"
264edb46e9SPaul Traina #endif
274edb46e9SPaul Traina 
28*3340d773SGleb Smirnoff #include <netdissect-stdinc.h>
294edb46e9SPaul Traina 
30*3340d773SGleb Smirnoff #include "netdissect.h"
31*3340d773SGleb Smirnoff #include "extract.h"
324edb46e9SPaul Traina 
33943ee2b1SBill Fenner #include "ip.h"
34943ee2b1SBill Fenner #include "tcp.h"
35943ee2b1SBill Fenner #include "slcompress.h"
36943ee2b1SBill Fenner 
373c602fabSXin LI /*
383c602fabSXin LI  * definitions of the pseudo- link-level header attached to slip
393c602fabSXin LI  * packets grabbed by the packet filter (bpf) traffic monitor.
403c602fabSXin LI  */
413c602fabSXin LI #define SLIP_HDRLEN 16
423c602fabSXin LI 
433c602fabSXin LI #define SLX_DIR 0
443c602fabSXin LI #define SLX_CHDR 1
453c602fabSXin LI #define CHDR_LEN 15
463c602fabSXin LI 
473c602fabSXin LI #define SLIPDIR_IN 0
483c602fabSXin LI #define SLIPDIR_OUT 1
493c602fabSXin LI 
503c602fabSXin LI static const char tstr[] = "[|slip]";
513c602fabSXin LI 
524edb46e9SPaul Traina static u_int lastlen[2][256];
534edb46e9SPaul Traina static u_int lastconn = 255;
544edb46e9SPaul Traina 
553c602fabSXin LI static void sliplink_print(netdissect_options *, const u_char *, const struct ip *, u_int);
563c602fabSXin LI static void compressed_sl_print(netdissect_options *, const u_char *, const struct ip *, u_int, int);
574edb46e9SPaul Traina 
58cc391cceSBruce M Simpson u_int
593c602fabSXin LI sl_if_print(netdissect_options *ndo,
603c602fabSXin LI             const struct pcap_pkthdr *h, const u_char *p)
614edb46e9SPaul Traina {
624edb46e9SPaul Traina 	register u_int caplen = h->caplen;
634edb46e9SPaul Traina 	register u_int length = h->len;
644edb46e9SPaul Traina 	register const struct ip *ip;
654edb46e9SPaul Traina 
6620869109SPedro F. Giffuni 	if (caplen < SLIP_HDRLEN || length < SLIP_HDRLEN) {
673c602fabSXin LI 		ND_PRINT((ndo, "%s", tstr));
68cc391cceSBruce M Simpson 		return (caplen);
694edb46e9SPaul Traina 	}
704edb46e9SPaul Traina 
71*3340d773SGleb Smirnoff 	caplen -= SLIP_HDRLEN;
724edb46e9SPaul Traina 	length -= SLIP_HDRLEN;
734edb46e9SPaul Traina 
74*3340d773SGleb Smirnoff 	ip = (const struct ip *)(p + SLIP_HDRLEN);
754edb46e9SPaul Traina 
763c602fabSXin LI 	if (ndo->ndo_eflag)
773c602fabSXin LI 		sliplink_print(ndo, p, ip, length);
784edb46e9SPaul Traina 
79*3340d773SGleb Smirnoff 	if (caplen < 1 || length < 1) {
80*3340d773SGleb Smirnoff 		ND_PRINT((ndo, "%s", tstr));
81*3340d773SGleb Smirnoff 		return (caplen + SLIP_HDRLEN);
82*3340d773SGleb Smirnoff 	}
83*3340d773SGleb Smirnoff 
84943ee2b1SBill Fenner 	switch (IP_V(ip)) {
85a88113a8SBill Fenner 	case 4:
86*3340d773SGleb Smirnoff 	        ip_print(ndo, (const u_char *)ip, length);
87a88113a8SBill Fenner 		break;
88a88113a8SBill Fenner 	case 6:
89*3340d773SGleb Smirnoff 		ip6_print(ndo, (const u_char *)ip, length);
90a88113a8SBill Fenner 		break;
91a88113a8SBill Fenner 	default:
923c602fabSXin LI 		ND_PRINT((ndo, "ip v%d", IP_V(ip)));
93a88113a8SBill Fenner 	}
944edb46e9SPaul Traina 
95cc391cceSBruce M Simpson 	return (SLIP_HDRLEN);
964edb46e9SPaul Traina }
974edb46e9SPaul Traina 
98cc391cceSBruce M Simpson u_int
993c602fabSXin LI sl_bsdos_if_print(netdissect_options *ndo,
1003c602fabSXin LI                   const struct pcap_pkthdr *h, const u_char *p)
101699fc314SBill Fenner {
102699fc314SBill Fenner 	register u_int caplen = h->caplen;
103699fc314SBill Fenner 	register u_int length = h->len;
104699fc314SBill Fenner 	register const struct ip *ip;
105699fc314SBill Fenner 
106699fc314SBill Fenner 	if (caplen < SLIP_HDRLEN) {
1073c602fabSXin LI 		ND_PRINT((ndo, "%s", tstr));
108cc391cceSBruce M Simpson 		return (caplen);
109699fc314SBill Fenner 	}
110699fc314SBill Fenner 
111699fc314SBill Fenner 	length -= SLIP_HDRLEN;
112699fc314SBill Fenner 
113*3340d773SGleb Smirnoff 	ip = (const struct ip *)(p + SLIP_HDRLEN);
114699fc314SBill Fenner 
115699fc314SBill Fenner #ifdef notdef
1163c602fabSXin LI 	if (ndo->ndo_eflag)
1173c602fabSXin LI 		sliplink_print(ndo, p, ip, length);
118699fc314SBill Fenner #endif
119699fc314SBill Fenner 
120*3340d773SGleb Smirnoff 	ip_print(ndo, (const u_char *)ip, length);
121699fc314SBill Fenner 
122cc391cceSBruce M Simpson 	return (SLIP_HDRLEN);
123699fc314SBill Fenner }
124699fc314SBill Fenner 
1254edb46e9SPaul Traina static void
1263c602fabSXin LI sliplink_print(netdissect_options *ndo,
1273c602fabSXin LI                register const u_char *p, register const struct ip *ip,
1284edb46e9SPaul Traina                register u_int length)
1294edb46e9SPaul Traina {
1304edb46e9SPaul Traina 	int dir;
1314edb46e9SPaul Traina 	u_int hlen;
1324edb46e9SPaul Traina 
1334edb46e9SPaul Traina 	dir = p[SLX_DIR];
1343c602fabSXin LI 	ND_PRINT((ndo, dir == SLIPDIR_IN ? "I " : "O "));
1354edb46e9SPaul Traina 
1363c602fabSXin LI 	if (ndo->ndo_nflag) {
1374edb46e9SPaul Traina 		/* XXX just dump the header */
1384edb46e9SPaul Traina 		register int i;
1394edb46e9SPaul Traina 
1404edb46e9SPaul Traina 		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
1413c602fabSXin LI 			ND_PRINT((ndo, "%02x.", p[i]));
1423c602fabSXin LI 		ND_PRINT((ndo, "%02x: ", p[SLX_CHDR + CHDR_LEN - 1]));
1434edb46e9SPaul Traina 		return;
1444edb46e9SPaul Traina 	}
1454edb46e9SPaul Traina 	switch (p[SLX_CHDR] & 0xf0) {
1464edb46e9SPaul Traina 
1474edb46e9SPaul Traina 	case TYPE_IP:
1483c602fabSXin LI 		ND_PRINT((ndo, "ip %d: ", length + SLIP_HDRLEN));
1494edb46e9SPaul Traina 		break;
1504edb46e9SPaul Traina 
1514edb46e9SPaul Traina 	case TYPE_UNCOMPRESSED_TCP:
1524edb46e9SPaul Traina 		/*
1532ebf6c05SBill Fenner 		 * The connection id is stored in the IP protocol field.
1544edb46e9SPaul Traina 		 * Get it from the link layer since sl_uncompress_tcp()
1554edb46e9SPaul Traina 		 * has restored the IP header copy to IPPROTO_TCP.
1564edb46e9SPaul Traina 		 */
157*3340d773SGleb Smirnoff 		lastconn = ((const struct ip *)&p[SLX_CHDR])->ip_p;
158943ee2b1SBill Fenner 		hlen = IP_HL(ip);
159*3340d773SGleb Smirnoff 		hlen += TH_OFF((const struct tcphdr *)&((const int *)ip)[hlen]);
1604edb46e9SPaul Traina 		lastlen[dir][lastconn] = length - (hlen << 2);
1613c602fabSXin LI 		ND_PRINT((ndo, "utcp %d: ", lastconn));
1624edb46e9SPaul Traina 		break;
1634edb46e9SPaul Traina 
1644edb46e9SPaul Traina 	default:
1654edb46e9SPaul Traina 		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
1663c602fabSXin LI 			compressed_sl_print(ndo, &p[SLX_CHDR], ip,
1674edb46e9SPaul Traina 			    length, dir);
1683c602fabSXin LI 			ND_PRINT((ndo, ": "));
1694edb46e9SPaul Traina 		} else
1703c602fabSXin LI 			ND_PRINT((ndo, "slip-%d!: ", p[SLX_CHDR]));
1714edb46e9SPaul Traina 	}
1724edb46e9SPaul Traina }
1734edb46e9SPaul Traina 
1744edb46e9SPaul Traina static const u_char *
1753c602fabSXin LI print_sl_change(netdissect_options *ndo,
1763c602fabSXin LI                 const char *str, register const u_char *cp)
1774edb46e9SPaul Traina {
1784edb46e9SPaul Traina 	register u_int i;
1794edb46e9SPaul Traina 
1804edb46e9SPaul Traina 	if ((i = *cp++) == 0) {
1814edb46e9SPaul Traina 		i = EXTRACT_16BITS(cp);
1824edb46e9SPaul Traina 		cp += 2;
1834edb46e9SPaul Traina 	}
1843c602fabSXin LI 	ND_PRINT((ndo, " %s%d", str, i));
1854edb46e9SPaul Traina 	return (cp);
1864edb46e9SPaul Traina }
1874edb46e9SPaul Traina 
1884edb46e9SPaul Traina static const u_char *
1893c602fabSXin LI print_sl_winchange(netdissect_options *ndo,
1903c602fabSXin LI                    register const u_char *cp)
1914edb46e9SPaul Traina {
1924edb46e9SPaul Traina 	register short i;
1934edb46e9SPaul Traina 
1944edb46e9SPaul Traina 	if ((i = *cp++) == 0) {
1954edb46e9SPaul Traina 		i = EXTRACT_16BITS(cp);
1964edb46e9SPaul Traina 		cp += 2;
1974edb46e9SPaul Traina 	}
1984edb46e9SPaul Traina 	if (i >= 0)
1993c602fabSXin LI 		ND_PRINT((ndo, " W+%d", i));
2004edb46e9SPaul Traina 	else
2013c602fabSXin LI 		ND_PRINT((ndo, " W%d", i));
2024edb46e9SPaul Traina 	return (cp);
2034edb46e9SPaul Traina }
2044edb46e9SPaul Traina 
2054edb46e9SPaul Traina static void
2063c602fabSXin LI compressed_sl_print(netdissect_options *ndo,
2073c602fabSXin LI                     const u_char *chdr, const struct ip *ip,
2084edb46e9SPaul Traina                     u_int length, int dir)
2094edb46e9SPaul Traina {
2104edb46e9SPaul Traina 	register const u_char *cp = chdr;
2114edb46e9SPaul Traina 	register u_int flags, hlen;
2124edb46e9SPaul Traina 
2134edb46e9SPaul Traina 	flags = *cp++;
2144edb46e9SPaul Traina 	if (flags & NEW_C) {
2154edb46e9SPaul Traina 		lastconn = *cp++;
2163c602fabSXin LI 		ND_PRINT((ndo, "ctcp %d", lastconn));
2174edb46e9SPaul Traina 	} else
2183c602fabSXin LI 		ND_PRINT((ndo, "ctcp *"));
2194edb46e9SPaul Traina 
2204edb46e9SPaul Traina 	/* skip tcp checksum */
2214edb46e9SPaul Traina 	cp += 2;
2224edb46e9SPaul Traina 
2234edb46e9SPaul Traina 	switch (flags & SPECIALS_MASK) {
2244edb46e9SPaul Traina 	case SPECIAL_I:
2253c602fabSXin LI 		ND_PRINT((ndo, " *SA+%d", lastlen[dir][lastconn]));
2264edb46e9SPaul Traina 		break;
2274edb46e9SPaul Traina 
2284edb46e9SPaul Traina 	case SPECIAL_D:
2293c602fabSXin LI 		ND_PRINT((ndo, " *S+%d", lastlen[dir][lastconn]));
2304edb46e9SPaul Traina 		break;
2314edb46e9SPaul Traina 
2324edb46e9SPaul Traina 	default:
2334edb46e9SPaul Traina 		if (flags & NEW_U)
2343c602fabSXin LI 			cp = print_sl_change(ndo, "U=", cp);
2354edb46e9SPaul Traina 		if (flags & NEW_W)
2363c602fabSXin LI 			cp = print_sl_winchange(ndo, cp);
2374edb46e9SPaul Traina 		if (flags & NEW_A)
2383c602fabSXin LI 			cp = print_sl_change(ndo, "A+", cp);
2394edb46e9SPaul Traina 		if (flags & NEW_S)
2403c602fabSXin LI 			cp = print_sl_change(ndo, "S+", cp);
2414edb46e9SPaul Traina 		break;
2424edb46e9SPaul Traina 	}
2434edb46e9SPaul Traina 	if (flags & NEW_I)
2443c602fabSXin LI 		cp = print_sl_change(ndo, "I+", cp);
2454edb46e9SPaul Traina 
2464edb46e9SPaul Traina 	/*
2474edb46e9SPaul Traina 	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
2484edb46e9SPaul Traina 	 * 'cp - chdr' is the length of the compressed header.
2494edb46e9SPaul Traina 	 * 'length - hlen' is the amount of data in the packet.
2504edb46e9SPaul Traina 	 */
251943ee2b1SBill Fenner 	hlen = IP_HL(ip);
252*3340d773SGleb Smirnoff 	hlen += TH_OFF((const struct tcphdr *)&((const int32_t *)ip)[hlen]);
2534edb46e9SPaul Traina 	lastlen[dir][lastconn] = length - (hlen << 2);
2543c602fabSXin LI 	ND_PRINT((ndo, " %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr)));
2554edb46e9SPaul Traina }
256