144165Sjulian/*
244165Sjulian * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
344165Sjulian *	The Regents of the University of California.  All rights reserved.
444165Sjulian *
544165Sjulian * Redistribution and use in source and binary forms, with or without
644165Sjulian * modification, are permitted provided that: (1) source code distributions
744165Sjulian * retain the above copyright notice and this paragraph in its entirety, (2)
844165Sjulian * distributions including binary code include the above copyright notice and
944165Sjulian * this paragraph in its entirety in the documentation or other materials
1044165Sjulian * provided with the distribution, and (3) all advertising materials mentioning
1144165Sjulian * features or use of this software display the following acknowledgement:
1244165Sjulian * ``This product includes software developed by the University of California,
1344165Sjulian * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1444165Sjulian * the University nor the names of its contributors may be used to endorse
1544165Sjulian * or promote products derived from this software without specific prior
1644165Sjulian * written permission.
1744165Sjulian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1844165Sjulian * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1944165Sjulian * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2044165Sjulian *
2144165Sjulian * Hacked version of print-ether.c  Larry Lile <lile@stdio.com>
2256896Sfenner *
2398527Sfenner * Further tweaked to more closely resemble print-fddi.c
2498527Sfenner *	Guy Harris <guy@alum.mit.edu>
2544165Sjulian */
2644165Sjulian
27313537Sglebius/* \summary: Token Ring printer */
28313537Sglebius
2998527Sfenner#ifdef HAVE_CONFIG_H
3098527Sfenner#include "config.h"
3198527Sfenner#endif
3298527Sfenner
33313537Sglebius#include <netdissect-stdinc.h>
3444165Sjulian
3598527Sfenner#include <string.h>
3644165Sjulian
37313537Sglebius#include "netdissect.h"
38214478Srpaulo#include "extract.h"
3944165Sjulian#include "addrtoname.h"
4098527Sfenner#include "ether.h"
4144165Sjulian
42276788Sdelphij/*
43276788Sdelphij * Copyright (c) 1998, Larry Lile
44276788Sdelphij * All rights reserved.
45276788Sdelphij *
46276788Sdelphij * Redistribution and use in source and binary forms, with or without
47276788Sdelphij * modification, are permitted provided that the following conditions
48276788Sdelphij * are met:
49276788Sdelphij * 1. Redistributions of source code must retain the above copyright
50276788Sdelphij *    notice unmodified, this list of conditions, and the following
51276788Sdelphij *    disclaimer.
52276788Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
53276788Sdelphij *    notice, this list of conditions and the following disclaimer in the
54276788Sdelphij *    documentation and/or other materials provided with the distribution.
55276788Sdelphij *
56276788Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
57276788Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58276788Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59276788Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
60276788Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61276788Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62276788Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63276788Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64276788Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65276788Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66276788Sdelphij * SUCH DAMAGE.
67276788Sdelphij *
68276788Sdelphij */
69276788Sdelphij
70276788Sdelphij#define TOKEN_HDRLEN		14
71276788Sdelphij#define TOKEN_RING_MAC_LEN	6
72276788Sdelphij#define ROUTING_SEGMENT_MAX	16
73276788Sdelphij#define IS_SOURCE_ROUTED(trp)	((trp)->token_shost[0] & 0x80)
74276788Sdelphij#define FRAME_TYPE(trp)		(((trp)->token_fc & 0xC0) >> 6)
75276788Sdelphij#define TOKEN_FC_LLC		1
76276788Sdelphij
77276788Sdelphij#define BROADCAST(trp)		((EXTRACT_16BITS(&(trp)->token_rcf) & 0xE000) >> 13)
78276788Sdelphij#define RIF_LENGTH(trp)		((EXTRACT_16BITS(&(trp)->token_rcf) & 0x1f00) >> 8)
79276788Sdelphij#define DIRECTION(trp)		((EXTRACT_16BITS(&(trp)->token_rcf) & 0x0080) >> 7)
80276788Sdelphij#define LARGEST_FRAME(trp)	((EXTRACT_16BITS(&(trp)->token_rcf) & 0x0070) >> 4)
81276788Sdelphij#define RING_NUMBER(trp, x)	((EXTRACT_16BITS(&(trp)->token_rseg[x]) & 0xfff0) >> 4)
82276788Sdelphij#define BRIDGE_NUMBER(trp, x)	((EXTRACT_16BITS(&(trp)->token_rseg[x]) & 0x000f))
83276788Sdelphij#define SEGMENT_COUNT(trp)	((int)((RIF_LENGTH(trp) - 2) / 2))
84276788Sdelphij
85276788Sdelphijstruct token_header {
86276788Sdelphij	uint8_t  token_ac;
87276788Sdelphij	uint8_t  token_fc;
88276788Sdelphij	uint8_t  token_dhost[TOKEN_RING_MAC_LEN];
89276788Sdelphij	uint8_t  token_shost[TOKEN_RING_MAC_LEN];
90276788Sdelphij	uint16_t token_rcf;
91276788Sdelphij	uint16_t token_rseg[ROUTING_SEGMENT_MAX];
92276788Sdelphij};
93276788Sdelphij
94276788Sdelphijstatic const char tstr[] = "[|token-ring]";
95276788Sdelphij
9698527Sfenner/* Extract src, dst addresses */
9744165Sjulianstatic inline void
9898527Sfennerextract_token_addrs(const struct token_header *trp, char *fsrc, char *fdst)
9944165Sjulian{
10098527Sfenner	memcpy(fdst, (const char *)trp->token_dhost, 6);
10198527Sfenner	memcpy(fsrc, (const char *)trp->token_shost, 6);
10298527Sfenner}
10344165Sjulian
10498527Sfenner/*
10598527Sfenner * Print the TR MAC header
10698527Sfenner */
10798527Sfennerstatic inline void
108276788Sdelphijtoken_hdr_print(netdissect_options *ndo,
109276788Sdelphij                register const struct token_header *trp, register u_int length,
110276788Sdelphij                register const u_char *fsrc, register const u_char *fdst)
11198527Sfenner{
11298527Sfenner	const char *srcname, *dstname;
11350514Slile
114276788Sdelphij	srcname = etheraddr_string(ndo, fsrc);
115276788Sdelphij	dstname = etheraddr_string(ndo, fdst);
11644165Sjulian
117313537Sglebius	if (!ndo->ndo_qflag)
118313537Sglebius		ND_PRINT((ndo, "%02x %02x ",
11998527Sfenner		       trp->token_ac,
120313537Sglebius		       trp->token_fc));
121313537Sglebius	ND_PRINT((ndo, "%s > %s, length %u: ",
122313537Sglebius	       srcname, dstname,
123313537Sglebius	       length));
12444165Sjulian}
12544165Sjulian
12698527Sfennerstatic const char *broadcast_indicator[] = {
12798527Sfenner	"Non-Broadcast", "Non-Broadcast",
12898527Sfenner	"Non-Broadcast", "Non-Broadcast",
12998527Sfenner	"All-routes",    "All-routes",
13098527Sfenner	"Single-route",  "Single-route"
13198527Sfenner};
13298527Sfenner
13398527Sfennerstatic const char *direction[] = {
13498527Sfenner	"Forward", "Backward"
13598527Sfenner};
13698527Sfenner
13798527Sfennerstatic const char *largest_frame[] = {
13898527Sfenner	"516",
13998527Sfenner	"1500",
14098527Sfenner	"2052",
14198527Sfenner	"4472",
14298527Sfenner	"8144",
14398527Sfenner	"11407",
14498527Sfenner	"17800",
14598527Sfenner	"??"
14698527Sfenner};
14798527Sfenner
148127675Sbmsu_int
149276788Sdelphijtoken_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen)
15044165Sjulian{
15198527Sfenner	const struct token_header *trp;
152313537Sglebius	int llc_hdrlen;
15398527Sfenner	struct ether_header ehdr;
154313537Sglebius	struct lladdr_info src, dst;
155127675Sbms	u_int route_len = 0, hdr_len = TOKEN_HDRLEN;
156127675Sbms	int seg;
15744165Sjulian
15898527Sfenner	trp = (const struct token_header *)p;
15944165Sjulian
16098527Sfenner	if (caplen < TOKEN_HDRLEN) {
161276788Sdelphij		ND_PRINT((ndo, "%s", tstr));
162127675Sbms		return hdr_len;
16344165Sjulian	}
164127675Sbms
16544165Sjulian	/*
16698527Sfenner	 * Get the TR addresses into a canonical form
16798527Sfenner	 */
16898527Sfenner	extract_token_addrs(trp, (char*)ESRC(&ehdr), (char*)EDST(&ehdr));
16944165Sjulian
17098527Sfenner	/* Adjust for source routing information in the MAC header */
17198527Sfenner	if (IS_SOURCE_ROUTED(trp)) {
17298527Sfenner		/* Clear source-routed bit */
17398527Sfenner		*ESRC(&ehdr) &= 0x7f;
17450514Slile
175276788Sdelphij		if (ndo->ndo_eflag)
176276788Sdelphij			token_hdr_print(ndo, trp, length, ESRC(&ehdr), EDST(&ehdr));
17750514Slile
178214478Srpaulo		if (caplen < TOKEN_HDRLEN + 2) {
179276788Sdelphij			ND_PRINT((ndo, "%s", tstr));
180214478Srpaulo			return hdr_len;
181214478Srpaulo		}
18298527Sfenner		route_len = RIF_LENGTH(trp);
183214478Srpaulo		hdr_len += route_len;
184214478Srpaulo		if (caplen < hdr_len) {
185276788Sdelphij			ND_PRINT((ndo, "%s", tstr));
186214478Srpaulo			return hdr_len;
187214478Srpaulo		}
188276788Sdelphij		if (ndo->ndo_vflag) {
189276788Sdelphij			ND_PRINT((ndo, "%s ", broadcast_indicator[BROADCAST(trp)]));
190276788Sdelphij			ND_PRINT((ndo, "%s", direction[DIRECTION(trp)]));
191127675Sbms
19298527Sfenner			for (seg = 0; seg < SEGMENT_COUNT(trp); seg++)
193276788Sdelphij				ND_PRINT((ndo, " [%d:%d]", RING_NUMBER(trp, seg),
194276788Sdelphij				    BRIDGE_NUMBER(trp, seg)));
19598527Sfenner		} else {
196276788Sdelphij			ND_PRINT((ndo, "rt = %x", EXTRACT_16BITS(&trp->token_rcf)));
197127675Sbms
19898527Sfenner			for (seg = 0; seg < SEGMENT_COUNT(trp); seg++)
199276788Sdelphij				ND_PRINT((ndo, ":%x", EXTRACT_16BITS(&trp->token_rseg[seg])));
20098527Sfenner		}
201276788Sdelphij		ND_PRINT((ndo, " (%s) ", largest_frame[LARGEST_FRAME(trp)]));
20298527Sfenner	} else {
203276788Sdelphij		if (ndo->ndo_eflag)
204276788Sdelphij			token_hdr_print(ndo, trp, length, ESRC(&ehdr), EDST(&ehdr));
20598527Sfenner	}
20644165Sjulian
207313537Sglebius	src.addr = ESRC(&ehdr);
208313537Sglebius	src.addr_string = etheraddr_string;
209313537Sglebius	dst.addr = EDST(&ehdr);
210313537Sglebius	dst.addr_string = etheraddr_string;
211313537Sglebius
21298527Sfenner	/* Skip over token ring MAC header and routing information */
213127675Sbms	length -= hdr_len;
214127675Sbms	p += hdr_len;
215127675Sbms	caplen -= hdr_len;
21644165Sjulian
21798527Sfenner	/* Frame Control field determines interpretation of packet */
21898527Sfenner	if (FRAME_TYPE(trp) == TOKEN_FC_LLC) {
21998527Sfenner		/* Try to print the LLC-layer header & higher layers */
220313537Sglebius		llc_hdrlen = llc_print(ndo, p, length, caplen, &src, &dst);
221313537Sglebius		if (llc_hdrlen < 0) {
222313537Sglebius			/* packet type not known, print raw packet */
223276788Sdelphij			if (!ndo->ndo_suppress_default_print)
224276788Sdelphij				ND_DEFAULTPRINT(p, caplen);
225313537Sglebius			llc_hdrlen = -llc_hdrlen;
22698527Sfenner		}
227313537Sglebius		hdr_len += llc_hdrlen;
22898527Sfenner	} else {
22998527Sfenner		/* Some kinds of TR packet we cannot handle intelligently */
23098527Sfenner		/* XXX - dissect MAC packets if frame type is 0 */
231276788Sdelphij		if (!ndo->ndo_eflag)
232276788Sdelphij			token_hdr_print(ndo, trp, length + TOKEN_HDRLEN + route_len,
23398527Sfenner			    ESRC(&ehdr), EDST(&ehdr));
234276788Sdelphij		if (!ndo->ndo_suppress_default_print)
235276788Sdelphij			ND_DEFAULTPRINT(p, caplen);
23644165Sjulian	}
237127675Sbms	return (hdr_len);
23844165Sjulian}
239127675Sbms
240127675Sbms/*
241127675Sbms * This is the top level routine of the printer.  'p' points
242127675Sbms * to the TR header of the packet, 'h->ts' is the timestamp,
243146778Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
244127675Sbms * is the number of bytes actually captured.
245127675Sbms */
246127675Sbmsu_int
247276788Sdelphijtoken_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
248127675Sbms{
249276788Sdelphij	return (token_print(ndo, p, h->len, h->caplen));
250127675Sbms}
251