xref: /freebsd/contrib/tcpdump/print-sl.c (revision b52b9d56d4e96089873a75f9e29062eec19fabba)
1 /*
2  * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * $FreeBSD$
22  */
23 
24 #ifndef lint
25 static const char rcsid[] =
26     "@(#) $Header: /tcpdump/master/tcpdump/print-sl.c,v 1.57 2001/07/05 18:54:17 guy Exp $ (LBL)";
27 #endif
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <sys/param.h>
34 #include <sys/time.h>
35 
36 #include <netinet/in.h>
37 
38 #include <ctype.h>
39 #include <netdb.h>
40 #include <pcap.h>
41 #include <stdio.h>
42 
43 #include "interface.h"
44 #include "addrtoname.h"
45 #include "extract.h"			/* must come after interface.h */
46 
47 #include "ip.h"
48 #include "tcp.h"
49 #include "slip.h"
50 #include "slcompress.h"
51 
52 static u_int lastlen[2][256];
53 static u_int lastconn = 255;
54 
55 static void sliplink_print(const u_char *, const struct ip *, u_int);
56 static void compressed_sl_print(const u_char *, const struct ip *, u_int, int);
57 
58 void
59 sl_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
60 {
61 	register u_int caplen = h->caplen;
62 	register u_int length = h->len;
63 	register const struct ip *ip;
64 
65 	++infodelay;
66 	ts_print(&h->ts);
67 
68 	if (caplen < SLIP_HDRLEN) {
69 		printf("[|slip]");
70 		goto out;
71 	}
72 	/*
73 	 * Some printers want to get back at the link level addresses,
74 	 * and/or check that they're not walking off the end of the packet.
75 	 * Rather than pass them all the way down, we set these globals.
76 	 */
77 	packetp = p;
78 	snapend = p + caplen;
79 
80 	length -= SLIP_HDRLEN;
81 
82 	ip = (struct ip *)(p + SLIP_HDRLEN);
83 
84 	if (eflag)
85 		sliplink_print(p, ip, length);
86 
87 	switch (IP_V(ip)) {
88 	case 4:
89 		ip_print((u_char *)ip, length);
90 		break;
91 #ifdef INET6
92 	case 6:
93 		ip6_print((u_char *)ip, length);
94 		break;
95 #endif
96 	default:
97 		printf ("ip v%d", IP_V(ip));
98 	}
99 
100 	if (xflag)
101 		default_print((u_char *)ip, caplen - SLIP_HDRLEN);
102  out:
103 	putchar('\n');
104 	--infodelay;
105 	if (infoprint)
106 		info(0);
107 }
108 
109 
110 void
111 sl_bsdos_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
112 {
113 	register u_int caplen = h->caplen;
114 	register u_int length = h->len;
115 	register const struct ip *ip;
116 
117 	++infodelay;
118 	ts_print(&h->ts);
119 
120 	if (caplen < SLIP_HDRLEN) {
121 		printf("[|slip]");
122 		goto out;
123 	}
124 	/*
125 	 * Some printers want to get back at the link level addresses,
126 	 * and/or check that they're not walking off the end of the packet.
127 	 * Rather than pass them all the way down, we set these globals.
128 	 */
129 	packetp = p;
130 	snapend = p + caplen;
131 
132 	length -= SLIP_HDRLEN;
133 
134 	ip = (struct ip *)(p + SLIP_HDRLEN);
135 
136 #ifdef notdef
137 	if (eflag)
138 		sliplink_print(p, ip, length);
139 #endif
140 
141 	ip_print((u_char *)ip, length);
142 
143 	if (xflag)
144 		default_print((u_char *)ip, caplen - SLIP_HDRLEN);
145  out:
146 	putchar('\n');
147 	--infodelay;
148 	if (infoprint)
149 		info(0);
150 }
151 
152 static void
153 sliplink_print(register const u_char *p, register const struct ip *ip,
154 	       register u_int length)
155 {
156 	int dir;
157 	u_int hlen;
158 
159 	dir = p[SLX_DIR];
160 	putchar(dir == SLIPDIR_IN ? 'I' : 'O');
161 	putchar(' ');
162 
163 	if (nflag) {
164 		/* XXX just dump the header */
165 		register int i;
166 
167 		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
168 			printf("%02x.", p[i]);
169 		printf("%02x: ", p[SLX_CHDR + CHDR_LEN - 1]);
170 		return;
171 	}
172 	switch (p[SLX_CHDR] & 0xf0) {
173 
174 	case TYPE_IP:
175 		printf("ip %d: ", length + SLIP_HDRLEN);
176 		break;
177 
178 	case TYPE_UNCOMPRESSED_TCP:
179 		/*
180 		 * The connection id is stored in the IP protocol field.
181 		 * Get it from the link layer since sl_uncompress_tcp()
182 		 * has restored the IP header copy to IPPROTO_TCP.
183 		 */
184 		lastconn = ((struct ip *)&p[SLX_CHDR])->ip_p;
185 		hlen = IP_HL(ip);
186 		hlen += TH_OFF((struct tcphdr *)&((int *)ip)[hlen]);
187 		lastlen[dir][lastconn] = length - (hlen << 2);
188 		printf("utcp %d: ", lastconn);
189 		break;
190 
191 	default:
192 		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
193 			compressed_sl_print(&p[SLX_CHDR], ip,
194 			    length, dir);
195 			printf(": ");
196 		} else
197 			printf("slip-%d!: ", p[SLX_CHDR]);
198 	}
199 }
200 
201 static const u_char *
202 print_sl_change(const char *str, register const u_char *cp)
203 {
204 	register u_int i;
205 
206 	if ((i = *cp++) == 0) {
207 		i = EXTRACT_16BITS(cp);
208 		cp += 2;
209 	}
210 	printf(" %s%d", str, i);
211 	return (cp);
212 }
213 
214 static const u_char *
215 print_sl_winchange(register const u_char *cp)
216 {
217 	register short i;
218 
219 	if ((i = *cp++) == 0) {
220 		i = EXTRACT_16BITS(cp);
221 		cp += 2;
222 	}
223 	if (i >= 0)
224 		printf(" W+%d", i);
225 	else
226 		printf(" W%d", i);
227 	return (cp);
228 }
229 
230 static void
231 compressed_sl_print(const u_char *chdr, const struct ip *ip,
232 		    u_int length, int dir)
233 {
234 	register const u_char *cp = chdr;
235 	register u_int flags, hlen;
236 
237 	flags = *cp++;
238 	if (flags & NEW_C) {
239 		lastconn = *cp++;
240 		printf("ctcp %d", lastconn);
241 	} else
242 		printf("ctcp *");
243 
244 	/* skip tcp checksum */
245 	cp += 2;
246 
247 	switch (flags & SPECIALS_MASK) {
248 	case SPECIAL_I:
249 		printf(" *SA+%d", lastlen[dir][lastconn]);
250 		break;
251 
252 	case SPECIAL_D:
253 		printf(" *S+%d", lastlen[dir][lastconn]);
254 		break;
255 
256 	default:
257 		if (flags & NEW_U)
258 			cp = print_sl_change("U=", cp);
259 		if (flags & NEW_W)
260 			cp = print_sl_winchange(cp);
261 		if (flags & NEW_A)
262 			cp = print_sl_change("A+", cp);
263 		if (flags & NEW_S)
264 			cp = print_sl_change("S+", cp);
265 		break;
266 	}
267 	if (flags & NEW_I)
268 		cp = print_sl_change("I+", cp);
269 
270 	/*
271 	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
272 	 * 'cp - chdr' is the length of the compressed header.
273 	 * 'length - hlen' is the amount of data in the packet.
274 	 */
275 	hlen = IP_HL(ip);
276 	hlen += TH_OFF((struct tcphdr *)&((int32_t *)ip)[hlen]);
277 	lastlen[dir][lastconn] = length - (hlen << 2);
278 	printf(" %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr));
279 }
280