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$
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-sl.c,v 1.65 2005-04-06 21:32:42 mcr Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2956896Sfenner#ifdef HAVE_CONFIG_H
3056896Sfenner#include "config.h"
3156896Sfenner#endif
3256896Sfenner
33127675Sbms#include <tcpdump-stdinc.h>
3417680Spst
3517680Spst#include <pcap.h>
3617680Spst#include <stdio.h>
3717680Spst
3817680Spst#include "interface.h"
3917680Spst#include "addrtoname.h"
4017680Spst#include "extract.h"			/* must come after interface.h */
4117680Spst
4275118Sfenner#include "ip.h"
4375118Sfenner#include "tcp.h"
4475118Sfenner#include "slip.h"
4575118Sfenner#include "slcompress.h"
4675118Sfenner
4717680Spststatic u_int lastlen[2][256];
4817680Spststatic u_int lastconn = 255;
4917680Spst
5017680Spststatic void sliplink_print(const u_char *, const struct ip *, u_int);
5117680Spststatic void compressed_sl_print(const u_char *, const struct ip *, u_int, int);
5217680Spst
53127675Sbmsu_int
54127675Sbmssl_if_print(const struct pcap_pkthdr *h, const u_char *p)
5517680Spst{
5617680Spst	register u_int caplen = h->caplen;
5717680Spst	register u_int length = h->len;
5817680Spst	register const struct ip *ip;
5917680Spst
6017680Spst	if (caplen < SLIP_HDRLEN) {
6117680Spst		printf("[|slip]");
62127675Sbms		return (caplen);
6317680Spst	}
6417680Spst
6517680Spst	length -= SLIP_HDRLEN;
6617680Spst
6717680Spst	ip = (struct ip *)(p + SLIP_HDRLEN);
6817680Spst
6917680Spst	if (eflag)
7017680Spst		sliplink_print(p, ip, length);
7117680Spst
7275118Sfenner	switch (IP_V(ip)) {
7356896Sfenner	case 4:
74146778Ssam	        ip_print(gndo, (u_char *)ip, length);
7556896Sfenner		break;
7656896Sfenner#ifdef INET6
7756896Sfenner	case 6:
78235530Sdelphij		ip6_print(gndo, (u_char *)ip, length);
7956896Sfenner		break;
8056896Sfenner#endif
8156896Sfenner	default:
8275118Sfenner		printf ("ip v%d", IP_V(ip));
8356896Sfenner	}
8417680Spst
85127675Sbms	return (SLIP_HDRLEN);
8617680Spst}
8717680Spst
88127675Sbmsu_int
89127675Sbmssl_bsdos_if_print(const struct pcap_pkthdr *h, const u_char *p)
9039300Sfenner{
9139300Sfenner	register u_int caplen = h->caplen;
9239300Sfenner	register u_int length = h->len;
9339300Sfenner	register const struct ip *ip;
9439300Sfenner
9539300Sfenner	if (caplen < SLIP_HDRLEN) {
9639300Sfenner		printf("[|slip]");
97127675Sbms		return (caplen);
9839300Sfenner	}
9939300Sfenner
10039300Sfenner	length -= SLIP_HDRLEN;
10139300Sfenner
10239300Sfenner	ip = (struct ip *)(p + SLIP_HDRLEN);
10339300Sfenner
10439300Sfenner#ifdef notdef
10539300Sfenner	if (eflag)
10639300Sfenner		sliplink_print(p, ip, length);
10739300Sfenner#endif
10839300Sfenner
109146778Ssam	ip_print(gndo, (u_char *)ip, length);
11039300Sfenner
111127675Sbms	return (SLIP_HDRLEN);
11239300Sfenner}
11339300Sfenner
11417680Spststatic void
11517680Spstsliplink_print(register const u_char *p, register const struct ip *ip,
11617680Spst	       register u_int length)
11717680Spst{
11817680Spst	int dir;
11917680Spst	u_int hlen;
12017680Spst
12117680Spst	dir = p[SLX_DIR];
12217680Spst	putchar(dir == SLIPDIR_IN ? 'I' : 'O');
12317680Spst	putchar(' ');
12417680Spst
12517680Spst	if (nflag) {
12617680Spst		/* XXX just dump the header */
12717680Spst		register int i;
12817680Spst
12917680Spst		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
13017680Spst			printf("%02x.", p[i]);
13117680Spst		printf("%02x: ", p[SLX_CHDR + CHDR_LEN - 1]);
13217680Spst		return;
13317680Spst	}
13417680Spst	switch (p[SLX_CHDR] & 0xf0) {
13517680Spst
13617680Spst	case TYPE_IP:
13717680Spst		printf("ip %d: ", length + SLIP_HDRLEN);
13817680Spst		break;
13917680Spst
14017680Spst	case TYPE_UNCOMPRESSED_TCP:
14117680Spst		/*
14226183Sfenner		 * The connection id is stored in the IP protocol field.
14317680Spst		 * Get it from the link layer since sl_uncompress_tcp()
14417680Spst		 * has restored the IP header copy to IPPROTO_TCP.
14517680Spst		 */
14617680Spst		lastconn = ((struct ip *)&p[SLX_CHDR])->ip_p;
14775118Sfenner		hlen = IP_HL(ip);
14875118Sfenner		hlen += TH_OFF((struct tcphdr *)&((int *)ip)[hlen]);
14917680Spst		lastlen[dir][lastconn] = length - (hlen << 2);
15017680Spst		printf("utcp %d: ", lastconn);
15117680Spst		break;
15217680Spst
15317680Spst	default:
15417680Spst		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
15517680Spst			compressed_sl_print(&p[SLX_CHDR], ip,
15617680Spst			    length, dir);
15717680Spst			printf(": ");
15817680Spst		} else
15917680Spst			printf("slip-%d!: ", p[SLX_CHDR]);
16017680Spst	}
16117680Spst}
16217680Spst
16317680Spststatic const u_char *
16417680Spstprint_sl_change(const char *str, register const u_char *cp)
16517680Spst{
16617680Spst	register u_int i;
16717680Spst
16817680Spst	if ((i = *cp++) == 0) {
16917680Spst		i = EXTRACT_16BITS(cp);
17017680Spst		cp += 2;
17117680Spst	}
17217680Spst	printf(" %s%d", str, i);
17317680Spst	return (cp);
17417680Spst}
17517680Spst
17617680Spststatic const u_char *
17717680Spstprint_sl_winchange(register const u_char *cp)
17817680Spst{
17917680Spst	register short i;
18017680Spst
18117680Spst	if ((i = *cp++) == 0) {
18217680Spst		i = EXTRACT_16BITS(cp);
18317680Spst		cp += 2;
18417680Spst	}
18517680Spst	if (i >= 0)
18617680Spst		printf(" W+%d", i);
18717680Spst	else
18817680Spst		printf(" W%d", i);
18917680Spst	return (cp);
19017680Spst}
19117680Spst
19217680Spststatic void
19317680Spstcompressed_sl_print(const u_char *chdr, const struct ip *ip,
19417680Spst		    u_int length, int dir)
19517680Spst{
19617680Spst	register const u_char *cp = chdr;
19717680Spst	register u_int flags, hlen;
19817680Spst
19917680Spst	flags = *cp++;
20017680Spst	if (flags & NEW_C) {
20117680Spst		lastconn = *cp++;
20217680Spst		printf("ctcp %d", lastconn);
20317680Spst	} else
20417680Spst		printf("ctcp *");
20517680Spst
20617680Spst	/* skip tcp checksum */
20717680Spst	cp += 2;
20817680Spst
20917680Spst	switch (flags & SPECIALS_MASK) {
21017680Spst	case SPECIAL_I:
21117680Spst		printf(" *SA+%d", lastlen[dir][lastconn]);
21217680Spst		break;
21317680Spst
21417680Spst	case SPECIAL_D:
21517680Spst		printf(" *S+%d", lastlen[dir][lastconn]);
21617680Spst		break;
21717680Spst
21817680Spst	default:
21917680Spst		if (flags & NEW_U)
22017680Spst			cp = print_sl_change("U=", cp);
22117680Spst		if (flags & NEW_W)
22217680Spst			cp = print_sl_winchange(cp);
22317680Spst		if (flags & NEW_A)
22417680Spst			cp = print_sl_change("A+", cp);
22517680Spst		if (flags & NEW_S)
22617680Spst			cp = print_sl_change("S+", cp);
22717680Spst		break;
22817680Spst	}
22917680Spst	if (flags & NEW_I)
23017680Spst		cp = print_sl_change("I+", cp);
23117680Spst
23217680Spst	/*
23317680Spst	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
23417680Spst	 * 'cp - chdr' is the length of the compressed header.
23517680Spst	 * 'length - hlen' is the amount of data in the packet.
23617680Spst	 */
23775118Sfenner	hlen = IP_HL(ip);
23875118Sfenner	hlen += TH_OFF((struct tcphdr *)&((int32_t *)ip)[hlen]);
23917680Spst	lastlen[dir][lastconn] = length - (hlen << 2);
24075118Sfenner	printf(" %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr));
24117680Spst}
242