117680Spst/*
239300Sfenner * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056896Sfenner *
2156896Sfenner * $FreeBSD: releng/11.0/contrib/tcpdump/print-sl.c 285275 2015-07-08 16:19:32Z pkelsey $
2217680Spst */
2317680Spst
24276788Sdelphij#define NETDISSECT_REWORKED
2556896Sfenner#ifdef HAVE_CONFIG_H
2656896Sfenner#include "config.h"
2756896Sfenner#endif
2856896Sfenner
29127675Sbms#include <tcpdump-stdinc.h>
3017680Spst
3117680Spst#include "interface.h"
3217680Spst#include "extract.h"			/* must come after interface.h */
3317680Spst
3475118Sfenner#include "ip.h"
3575118Sfenner#include "tcp.h"
3675118Sfenner#include "slcompress.h"
3775118Sfenner
38276788Sdelphij/*
39276788Sdelphij * definitions of the pseudo- link-level header attached to slip
40276788Sdelphij * packets grabbed by the packet filter (bpf) traffic monitor.
41276788Sdelphij */
42276788Sdelphij#define SLIP_HDRLEN 16
43276788Sdelphij
44276788Sdelphij#define SLX_DIR 0
45276788Sdelphij#define SLX_CHDR 1
46276788Sdelphij#define CHDR_LEN 15
47276788Sdelphij
48276788Sdelphij#define SLIPDIR_IN 0
49276788Sdelphij#define SLIPDIR_OUT 1
50276788Sdelphij
51276788Sdelphijstatic const char tstr[] = "[|slip]";
52276788Sdelphij
5317680Spststatic u_int lastlen[2][256];
5417680Spststatic u_int lastconn = 255;
5517680Spst
56276788Sdelphijstatic void sliplink_print(netdissect_options *, const u_char *, const struct ip *, u_int);
57276788Sdelphijstatic void compressed_sl_print(netdissect_options *, const u_char *, const struct ip *, u_int, int);
5817680Spst
59127675Sbmsu_int
60276788Sdelphijsl_if_print(netdissect_options *ndo,
61276788Sdelphij            const struct pcap_pkthdr *h, const u_char *p)
6217680Spst{
6317680Spst	register u_int caplen = h->caplen;
6417680Spst	register u_int length = h->len;
6517680Spst	register const struct ip *ip;
6617680Spst
67277783Spfg	if (caplen < SLIP_HDRLEN || length < SLIP_HDRLEN) {
68276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
69127675Sbms		return (caplen);
7017680Spst	}
7117680Spst
7217680Spst	length -= SLIP_HDRLEN;
7317680Spst
7417680Spst	ip = (struct ip *)(p + SLIP_HDRLEN);
7517680Spst
76276788Sdelphij	if (ndo->ndo_eflag)
77276788Sdelphij		sliplink_print(ndo, p, ip, length);
7817680Spst
7975118Sfenner	switch (IP_V(ip)) {
8056896Sfenner	case 4:
81276788Sdelphij	        ip_print(ndo, (u_char *)ip, length);
8256896Sfenner		break;
8356896Sfenner	case 6:
84276788Sdelphij		ip6_print(ndo, (u_char *)ip, length);
8556896Sfenner		break;
8656896Sfenner	default:
87276788Sdelphij		ND_PRINT((ndo, "ip v%d", IP_V(ip)));
8856896Sfenner	}
8917680Spst
90127675Sbms	return (SLIP_HDRLEN);
9117680Spst}
9217680Spst
93127675Sbmsu_int
94276788Sdelphijsl_bsdos_if_print(netdissect_options *ndo,
95276788Sdelphij                  const struct pcap_pkthdr *h, const u_char *p)
9639300Sfenner{
9739300Sfenner	register u_int caplen = h->caplen;
9839300Sfenner	register u_int length = h->len;
9939300Sfenner	register const struct ip *ip;
10039300Sfenner
10139300Sfenner	if (caplen < SLIP_HDRLEN) {
102276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
103127675Sbms		return (caplen);
10439300Sfenner	}
10539300Sfenner
10639300Sfenner	length -= SLIP_HDRLEN;
10739300Sfenner
10839300Sfenner	ip = (struct ip *)(p + SLIP_HDRLEN);
10939300Sfenner
11039300Sfenner#ifdef notdef
111276788Sdelphij	if (ndo->ndo_eflag)
112276788Sdelphij		sliplink_print(ndo, p, ip, length);
11339300Sfenner#endif
11439300Sfenner
115276788Sdelphij	ip_print(ndo, (u_char *)ip, length);
11639300Sfenner
117127675Sbms	return (SLIP_HDRLEN);
11839300Sfenner}
11939300Sfenner
12017680Spststatic void
121276788Sdelphijsliplink_print(netdissect_options *ndo,
122276788Sdelphij               register const u_char *p, register const struct ip *ip,
123276788Sdelphij               register u_int length)
12417680Spst{
12517680Spst	int dir;
12617680Spst	u_int hlen;
12717680Spst
12817680Spst	dir = p[SLX_DIR];
129276788Sdelphij	ND_PRINT((ndo, dir == SLIPDIR_IN ? "I " : "O "));
13017680Spst
131276788Sdelphij	if (ndo->ndo_nflag) {
13217680Spst		/* XXX just dump the header */
13317680Spst		register int i;
13417680Spst
13517680Spst		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
136276788Sdelphij			ND_PRINT((ndo, "%02x.", p[i]));
137276788Sdelphij		ND_PRINT((ndo, "%02x: ", p[SLX_CHDR + CHDR_LEN - 1]));
13817680Spst		return;
13917680Spst	}
14017680Spst	switch (p[SLX_CHDR] & 0xf0) {
14117680Spst
14217680Spst	case TYPE_IP:
143276788Sdelphij		ND_PRINT((ndo, "ip %d: ", length + SLIP_HDRLEN));
14417680Spst		break;
14517680Spst
14617680Spst	case TYPE_UNCOMPRESSED_TCP:
14717680Spst		/*
14826183Sfenner		 * The connection id is stored in the IP protocol field.
14917680Spst		 * Get it from the link layer since sl_uncompress_tcp()
15017680Spst		 * has restored the IP header copy to IPPROTO_TCP.
15117680Spst		 */
15217680Spst		lastconn = ((struct ip *)&p[SLX_CHDR])->ip_p;
15375118Sfenner		hlen = IP_HL(ip);
15475118Sfenner		hlen += TH_OFF((struct tcphdr *)&((int *)ip)[hlen]);
15517680Spst		lastlen[dir][lastconn] = length - (hlen << 2);
156276788Sdelphij		ND_PRINT((ndo, "utcp %d: ", lastconn));
15717680Spst		break;
15817680Spst
15917680Spst	default:
16017680Spst		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
161276788Sdelphij			compressed_sl_print(ndo, &p[SLX_CHDR], ip,
16217680Spst			    length, dir);
163276788Sdelphij			ND_PRINT((ndo, ": "));
16417680Spst		} else
165276788Sdelphij			ND_PRINT((ndo, "slip-%d!: ", p[SLX_CHDR]));
16617680Spst	}
16717680Spst}
16817680Spst
16917680Spststatic const u_char *
170276788Sdelphijprint_sl_change(netdissect_options *ndo,
171276788Sdelphij                const char *str, register const u_char *cp)
17217680Spst{
17317680Spst	register u_int i;
17417680Spst
17517680Spst	if ((i = *cp++) == 0) {
17617680Spst		i = EXTRACT_16BITS(cp);
17717680Spst		cp += 2;
17817680Spst	}
179276788Sdelphij	ND_PRINT((ndo, " %s%d", str, i));
18017680Spst	return (cp);
18117680Spst}
18217680Spst
18317680Spststatic const u_char *
184276788Sdelphijprint_sl_winchange(netdissect_options *ndo,
185276788Sdelphij                   register const u_char *cp)
18617680Spst{
18717680Spst	register short i;
18817680Spst
18917680Spst	if ((i = *cp++) == 0) {
19017680Spst		i = EXTRACT_16BITS(cp);
19117680Spst		cp += 2;
19217680Spst	}
19317680Spst	if (i >= 0)
194276788Sdelphij		ND_PRINT((ndo, " W+%d", i));
19517680Spst	else
196276788Sdelphij		ND_PRINT((ndo, " W%d", i));
19717680Spst	return (cp);
19817680Spst}
19917680Spst
20017680Spststatic void
201276788Sdelphijcompressed_sl_print(netdissect_options *ndo,
202276788Sdelphij                    const u_char *chdr, const struct ip *ip,
203276788Sdelphij                    u_int length, int dir)
20417680Spst{
20517680Spst	register const u_char *cp = chdr;
20617680Spst	register u_int flags, hlen;
20717680Spst
20817680Spst	flags = *cp++;
20917680Spst	if (flags & NEW_C) {
21017680Spst		lastconn = *cp++;
211276788Sdelphij		ND_PRINT((ndo, "ctcp %d", lastconn));
21217680Spst	} else
213276788Sdelphij		ND_PRINT((ndo, "ctcp *"));
21417680Spst
21517680Spst	/* skip tcp checksum */
21617680Spst	cp += 2;
21717680Spst
21817680Spst	switch (flags & SPECIALS_MASK) {
21917680Spst	case SPECIAL_I:
220276788Sdelphij		ND_PRINT((ndo, " *SA+%d", lastlen[dir][lastconn]));
22117680Spst		break;
22217680Spst
22317680Spst	case SPECIAL_D:
224276788Sdelphij		ND_PRINT((ndo, " *S+%d", lastlen[dir][lastconn]));
22517680Spst		break;
22617680Spst
22717680Spst	default:
22817680Spst		if (flags & NEW_U)
229276788Sdelphij			cp = print_sl_change(ndo, "U=", cp);
23017680Spst		if (flags & NEW_W)
231276788Sdelphij			cp = print_sl_winchange(ndo, cp);
23217680Spst		if (flags & NEW_A)
233276788Sdelphij			cp = print_sl_change(ndo, "A+", cp);
23417680Spst		if (flags & NEW_S)
235276788Sdelphij			cp = print_sl_change(ndo, "S+", cp);
23617680Spst		break;
23717680Spst	}
23817680Spst	if (flags & NEW_I)
239276788Sdelphij		cp = print_sl_change(ndo, "I+", cp);
24017680Spst
24117680Spst	/*
24217680Spst	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
24317680Spst	 * 'cp - chdr' is the length of the compressed header.
24417680Spst	 * 'length - hlen' is the amount of data in the packet.
24517680Spst	 */
24675118Sfenner	hlen = IP_HL(ip);
24775118Sfenner	hlen += TH_OFF((struct tcphdr *)&((int32_t *)ip)[hlen]);
24817680Spst	lastlen[dir][lastconn] = length - (hlen << 2);
249276788Sdelphij	ND_PRINT((ndo, " %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr)));
25017680Spst}
251