print-llc.c revision 98527
121308Sache/*
221308Sache * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
3136644Sache *	The Regents of the University of California.  All rights reserved.
421308Sache *
521308Sache * Redistribution and use in source and binary forms, with or without
621308Sache * modification, are permitted provided that: (1) source code distributions
721308Sache * retain the above copyright notice and this paragraph in its entirety, (2)
821308Sache * distributions including binary code include the above copyright notice and
921308Sache * this paragraph in its entirety in the documentation or other materials
1058310Sache * provided with the distribution, and (3) all advertising materials mentioning
1121308Sache * features or use of this software display the following acknowledgement:
1221308Sache * ``This product includes software developed by the University of California,
1321308Sache * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1421308Sache * the University nor the names of its contributors may be used to endorse
1521308Sache * or promote products derived from this software without specific prior
1621308Sache * written permission.
1721308Sache * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1821308Sache * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1921308Sache * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2021308Sache *
2158310Sache * Code by Matt Thomas, Digital Equipment Corporation
2221308Sache *	with an awful lot of hacking by Jeffrey Mogul, DECWRL
2321308Sache *
2421308Sache * $FreeBSD: head/contrib/tcpdump/print-llc.c 98527 2002-06-21 00:49:02Z fenner $
2521308Sache */
26136644Sache
2721308Sache#ifndef lint
2821308Sachestatic const char rcsid[] =
29136644Sache    "@(#) $Header: /tcpdump/master/tcpdump/print-llc.c,v 1.43 2001/10/08 21:25:22 fenner Exp $";
30136644Sache#endif
31136644Sache
32136644Sache#ifdef HAVE_CONFIG_H
3321308Sache#include "config.h"
3421308Sache#endif
3521308Sache
3621308Sache#include <sys/param.h>
3721308Sache#include <sys/time.h>
3821308Sache
3921308Sache#include <netinet/in.h>
40136644Sache
4135486Sache#include <ctype.h>
4235486Sache#include <netdb.h>
4358310Sache#include <stdio.h>
4421308Sache#include <string.h>
4521308Sache
4621308Sache#include "interface.h"
4721308Sache#include "addrtoname.h"
4821308Sache#include "extract.h"			/* must come after interface.h */
4921308Sache
5021308Sache#include "llc.h"
5121308Sache#include "ethertype.h"
5221308Sache
5321308Sachestatic struct tok cmd2str[] = {
5421308Sache	{ LLC_UI,	"ui" },
5521308Sache	{ LLC_TEST,	"test" },
56119610Sache	{ LLC_XID,	"xid" },
57119610Sache	{ LLC_UA,	"ua" },
58119610Sache	{ LLC_DISC,	"disc" },
5921308Sache	{ LLC_DM,	"dm" },
60136644Sache	{ LLC_SABME,	"sabme" },
61119610Sache	{ LLC_FRMR,	"frmr" },
6258310Sache	{ 0,		NULL }
63119610Sache};
64119610Sache
65119610Sache/*
66119610Sache * Returns non-zero IFF it succeeds in printing the header
67119610Sache */
68119610Sacheint
69119610Sachellc_print(const u_char *p, u_int length, u_int caplen,
70119610Sache	  const u_char *esrc, const u_char *edst, u_short *extracted_ethertype)
71119610Sache{
72119610Sache	struct llc llc;
73119610Sache	register u_short et;
74119610Sache	u_int16_t control;
75136644Sache	register int ret;
76119610Sache
7758310Sache	if (caplen < 3) {
7858310Sache		(void)printf("[|llc]");
7958310Sache		default_print((u_char *)p, caplen);
8058310Sache		return(0);
8158310Sache	}
8226497Sache
8326497Sache	/* Watch out for possible alignment problems */
8426497Sache	memcpy((char *)&llc, (char *)p, min(caplen, sizeof(llc)));
8558310Sache
8626497Sache	if (llc.ssap == LLCSAP_GLOBAL && llc.dsap == LLCSAP_GLOBAL) {
8726497Sache		/*
8858310Sache		 * This is an Ethernet_802.3 IPX frame; it has an
8926497Sache		 * 802.3 header (i.e., an Ethernet header where the
9021308Sache		 * type/length field is <= ETHERMTU, i.e. it's a length
9121308Sache		 * field, not a type field), but has no 802.2 header -
9221308Sache		 * the IPX packet starts right after the Ethernet header,
9321308Sache		 * with a signature of two bytes of 0xFF (which is
9421308Sache		 * LLCSAP_GLOBAL).
9521308Sache		 *
9621308Sache		 * (It might also have been an Ethernet_802.3 IPX at
9721308Sache		 * one time, but got bridged onto another network,
9858310Sache		 * such as an 802.11 network; this has appeared in at
9958310Sache		 * least one capture file.)
10026497Sache		 */
101136644Sache		ipx_print(p, length);
102136644Sache		return (1);
103136644Sache	}
104136644Sache
105136644Sache	if (llc.ssap == LLCSAP_8021D && llc.dsap == LLCSAP_8021D) {
106136644Sache		stp_print(p, length);
107136644Sache		return (1);
10821308Sache	}
10921308Sache
11021308Sache	if (llc.ssap == LLCSAP_IPX && llc.dsap == LLCSAP_IPX &&
11121308Sache	    llc.llcui == LLC_UI) {
11221308Sache		/*
11375406Sache		 * This is an Ethernet_802.2 IPX frame, with an 802.3
11421308Sache		 * header and an 802.2 LLC header with the source and
11575406Sache		 * destination SAPs being the IPX SAP.
11675406Sache		 *
11721308Sache		 * Skip DSAP, LSAP, and control field.
11821308Sache		 */
11921308Sache		p += 3;
12021308Sache		length -= 3;
12121308Sache		caplen -= 3;
12221308Sache		ipx_print(p, length);
12321308Sache		return (1);
12475406Sache	}
12521308Sache
12621308Sache#ifdef TCPDUMP_DO_SMB
12721308Sache	if (llc.ssap == LLCSAP_NETBEUI && llc.dsap == LLCSAP_NETBEUI
12821308Sache	    && (!(llc.llcu & LLC_S_FMT) || llc.llcu == LLC_U_FMT)) {
12921308Sache		/*
13021308Sache		 * we don't actually have a full netbeui parser yet, but the
13121308Sache		 * smb parser can handle many smb-in-netbeui packets, which
13221308Sache		 * is very useful, so we call that
13321308Sache		 *
134119610Sache		 * We don't call it for S frames, however, just I frames
13521308Sache		 * (which are frames that don't have the low-order bit,
13621308Sache		 * LLC_S_FMT, set in the first byte of the control field)
13758310Sache		 * and UI frames (whose control field is just 3, LLC_U_FMT).
13858310Sache		 */
13958310Sache
14021308Sache		/*
14158310Sache		 * Skip the DSAP and LSAP.
14221308Sache		 */
14321308Sache		p += 2;
14421308Sache		length -= 2;
14521308Sache		caplen -= 2;
14621308Sache
14721308Sache		/*
14821308Sache		 * OK, what type of LLC frame is this?  The length
14921308Sache		 * of the control field depends on that - I frames
15021308Sache		 * have a two-byte control field, and U frames have
15175406Sache		 * a one-byte control field.
15221308Sache		 */
15321308Sache		if (llc.llcu == LLC_U_FMT) {
15421308Sache			control = llc.llcu;
15521308Sache			p += 1;
15621308Sache			length -= 1;
15721308Sache			caplen -= 1;
15821308Sache		} else {
15921308Sache			/*
16021308Sache			 * The control field in I and S frames is
16121308Sache			 * little-endian.
16221308Sache			 */
16375406Sache			control = EXTRACT_LE_16BITS(&llc.llcu);
16421308Sache			p += 2;
16521308Sache			length -= 2;
166136644Sache			caplen -= 2;
167136644Sache		}
16858310Sache		netbeui_print(control, p, length);
16921308Sache		return (1);
17035486Sache	}
171136644Sache#endif
172136644Sache	if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
173136644Sache	    && llc.llcui == LLC_UI) {
174136644Sache		isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
175136644Sache		return (1);
176136644Sache	}
177136644Sache
17821308Sache	if (llc.ssap == LLCSAP_SNAP && llc.dsap == LLCSAP_SNAP
179136644Sache	    && llc.llcui == LLC_UI) {
18021308Sache		u_int32_t orgcode;
18126497Sache
18221308Sache		if (caplen < sizeof(llc)) {
18321308Sache			(void)printf("[|llc-snap]");
18421308Sache			default_print((u_char *)p, caplen);
18521308Sache			return (0);
18635486Sache		}
18721308Sache		if (vflag)
18835486Sache			(void)printf("snap %s ", protoid_string(llc.llcpi));
18935486Sache
19021308Sache		caplen -= sizeof(llc);
191136644Sache		length -= sizeof(llc);
19235486Sache		p += sizeof(llc);
19335486Sache
19435486Sache		orgcode = EXTRACT_24BITS(&llc.llc_orgcode[0]);
195136644Sache		et = EXTRACT_16BITS(&llc.llc_ethertype[0]);
196119610Sache		switch (orgcode) {
197119610Sache		case OUI_ENCAP_ETHER:
198119610Sache		case OUI_CISCO_90:
199119610Sache			/*
200136644Sache			 * This is an encapsulated Ethernet packet,
201136644Sache			 * or a packet bridged by some piece of
202136644Sache			 * Cisco hardware; the protocol ID is
203136644Sache			 * an Ethernet protocol type.
204119610Sache			 */
205119610Sache			ret = ether_encap_print(et, p, length, caplen,
206119610Sache			    extracted_ethertype);
207119610Sache			if (ret)
208136644Sache				return (ret);
209136644Sache			break;
210136644Sache
211136644Sache		case OUI_APPLETALK:
21258310Sache			if (et == ETHERTYPE_ATALK) {
21358310Sache				/*
214119610Sache				 * No, I have no idea why Apple used one
21558310Sache				 * of their own OUIs, rather than
21635486Sache				 * 0x000000, and an Ethernet packet
21721308Sache				 * type, for Appletalk data packets,
218136644Sache				 * but used 0x000000 and an Ethernet
219136644Sache				 * packet type for AARP packets.
220136644Sache				 */
221136644Sache				ret = ether_encap_print(et, p, length, caplen,
22221308Sache				    extracted_ethertype);
22321308Sache				if (ret)
22421308Sache					return (ret);
22521308Sache			}
226136644Sache			break;
22721308Sache
228119610Sache		case OUI_CISCO:
22921308Sache			if (et == ETHERTYPE_CISCO_CDP) {
230119610Sache				cdp_print(p, length, caplen, esrc, edst);
23121308Sache				return 1;
23221308Sache			}
23321308Sache			break;
23421308Sache		}
23521308Sache	}
23621308Sache
23758310Sache	if ((llc.ssap & ~LLC_GSAP) == llc.dsap) {
23821308Sache		if (eflag || esrc == NULL || edst == NULL)
23921308Sache			(void)printf("%s ", llcsap_string(llc.dsap));
240119610Sache		else
241119610Sache			(void)printf("%s > %s %s ",
24221308Sache					etheraddr_string(esrc),
24321308Sache					etheraddr_string(edst),
244119610Sache					llcsap_string(llc.dsap));
245119610Sache	} else {
246119610Sache		if (eflag || esrc == NULL || edst == NULL)
247136644Sache			(void)printf("%s > %s ",
248136644Sache				llcsap_string(llc.ssap & ~LLC_GSAP),
249136644Sache				llcsap_string(llc.dsap));
250136644Sache		else
251136644Sache			(void)printf("%s %s > %s %s ",
252136644Sache				etheraddr_string(esrc),
253119610Sache				llcsap_string(llc.ssap & ~LLC_GSAP),
25421308Sache				etheraddr_string(edst),
25521308Sache				llcsap_string(llc.dsap));
256119610Sache	}
257119610Sache
25821308Sache	if ((llc.llcu & LLC_U_FMT) == LLC_U_FMT) {
259165670Sache		u_int16_t cmd;
260165670Sache		const char *m;
261165670Sache		char f;
262165670Sache
263165670Sache		cmd = LLC_U_CMD(llc.llcu);
26421308Sache		m = tok2str(cmd2str, "%02x", cmd);
265119610Sache		switch ((llc.ssap & LLC_GSAP) | (llc.llcu & LLC_U_POLL)) {
266136644Sache			case 0:			f = 'C'; break;
267136644Sache			case LLC_GSAP:		f = 'R'; break;
268136644Sache			case LLC_U_POLL:	f = 'P'; break;
269136644Sache			case LLC_GSAP|LLC_U_POLL: f = 'F'; break;
270136644Sache			default:		f = '?'; break;
271136644Sache		}
272136644Sache
273136644Sache		printf("%s/%c", m, f);
274136644Sache
275136644Sache		p += 3;
276136644Sache		length -= 3;
277136644Sache		caplen -= 3;
278136644Sache
279136644Sache		if ((llc.llcu & ~LLC_U_POLL) == LLC_XID) {
280136644Sache			if (*p == LLC_XID_FI) {
281136644Sache				printf(": %02x %02x", p[1], p[2]);
28221308Sache				p += 3;
28321308Sache				length -= 3;
28421308Sache				caplen -= 3;
28521308Sache			}
28621308Sache		}
28721308Sache	} else {
28821308Sache		char f;
28921308Sache
29021308Sache		/*
29121308Sache		 * The control field in I and S frames is little-endian.
292136644Sache		 */
29321308Sache		control = EXTRACT_LE_16BITS(&llc.llcu);
294119610Sache		switch ((llc.ssap & LLC_GSAP) | (control & LLC_IS_POLL)) {
295119610Sache			case 0:			f = 'C'; break;
296119610Sache			case LLC_GSAP:		f = 'R'; break;
29721308Sache			case LLC_IS_POLL:	f = 'P'; break;
29821308Sache			case LLC_GSAP|LLC_IS_POLL: f = 'F'; break;
29921308Sache			default:		f = '?'; break;
30021308Sache		}
30121308Sache
30275406Sache		if ((control & LLC_S_FMT) == LLC_S_FMT) {
30375406Sache			static char *llc_s[] = { "rr", "rej", "rnr", "03" };
30421308Sache			(void)printf("%s (r=%d,%c)",
30521308Sache				llc_s[LLC_S_CMD(control)],
30675406Sache				LLC_IS_NR(control),
30747558Sache				f);
30821308Sache		} else {
309136644Sache			(void)printf("I (s=%d,r=%d,%c)",
31075406Sache				LLC_I_NS(control),
31121308Sache				LLC_IS_NR(control),
31235486Sache				f);
31321308Sache		}
31426497Sache		p += 4;
31521308Sache		length -= 4;
31626497Sache		caplen -= 4;
31775406Sache	}
31821308Sache	(void)printf(" len=%d", length);
31975406Sache	if (caplen > 0 && !qflag) {
32021308Sache		default_print_unaligned(p, caplen);
32175406Sache	}
32275406Sache	return(1);
32375406Sache}
32475406Sache