198524Sfenner/*
298524Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
398524Sfenner *	The Regents of the University of California.  All rights reserved.
498524Sfenner *
598524Sfenner * Redistribution and use in source and binary forms, with or without
698524Sfenner * modification, are permitted provided that: (1) source code distributions
798524Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
898524Sfenner * distributions including binary code include the above copyright notice and
998524Sfenner * this paragraph in its entirety in the documentation or other materials
1098524Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1198524Sfenner * features or use of this software display the following acknowledgement:
1298524Sfenner * ``This product includes software developed by the University of California,
1398524Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1498524Sfenner * the University nor the names of its contributors may be used to endorse
1598524Sfenner * or promote products derived from this software without specific prior
1698524Sfenner * written permission.
1798524Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1898524Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1998524Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20127668Sbms *
2198524Sfenner * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp
2298524Sfenner */
2398524Sfenner#ifndef lint
24127668Sbmsstatic const char rcsid[] _U_ =
25190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-arcnet.c,v 1.20 2005-04-06 21:32:38 mcr Exp $ (LBL)";
2698524Sfenner#endif
2798524Sfenner
2898524Sfenner#ifdef HAVE_CONFIG_H
2998524Sfenner#include "config.h"
3098524Sfenner#endif
3198524Sfenner
32127668Sbms#include <tcpdump-stdinc.h>
3398524Sfenner
3498524Sfenner#include <stdio.h>
3598524Sfenner#include <pcap.h>
3698524Sfenner
3798524Sfenner#include "interface.h"
38214478Srpaulo#include "extract.h"
3998524Sfenner#include "arcnet.h"
4098524Sfenner
41127668Sbmsstatic int arcnet_encap_print(u_char arctype, const u_char *p,
4298524Sfenner    u_int length, u_int caplen);
4398524Sfenner
4498524Sfennerstruct tok arctypemap[] = {
4598524Sfenner	{ ARCTYPE_IP_OLD,	"oldip" },
4698524Sfenner	{ ARCTYPE_ARP_OLD,	"oldarp" },
4798524Sfenner	{ ARCTYPE_IP,		"ip" },
4898524Sfenner	{ ARCTYPE_ARP,		"arp" },
4998524Sfenner	{ ARCTYPE_REVARP,	"rarp" },
5098524Sfenner	{ ARCTYPE_ATALK,	"atalk" },
5198524Sfenner	{ ARCTYPE_BANIAN,	"banyan" },
5298524Sfenner	{ ARCTYPE_IPX,		"ipx" },
5398524Sfenner	{ ARCTYPE_INET6,	"ipv6" },
5498524Sfenner	{ ARCTYPE_DIAGNOSE,	"diag" },
5598524Sfenner	{ 0, 0 }
5698524Sfenner};
5798524Sfenner
5898524Sfennerstatic inline void
5998524Sfennerarcnet_print(const u_char *bp, u_int length, int phds, int flag, u_int seqid)
6098524Sfenner{
6198524Sfenner	const struct arc_header *ap;
6298524Sfenner	const char *arctypename;
6398524Sfenner
6498524Sfenner
6598524Sfenner	ap = (const struct arc_header *)bp;
6698524Sfenner
6798524Sfenner
6898524Sfenner	if (qflag) {
6998524Sfenner		(void)printf("%02x %02x %d: ",
7098524Sfenner			     ap->arc_shost,
7198524Sfenner			     ap->arc_dhost,
7298524Sfenner			     length);
7398524Sfenner		return;
7498524Sfenner	}
7598524Sfenner
7698524Sfenner	arctypename = tok2str(arctypemap, "%02x", ap->arc_type);
7798524Sfenner
7898524Sfenner	if (!phds) {
7998524Sfenner		(void)printf("%02x %02x %s %d: ",
8098524Sfenner			     ap->arc_shost, ap->arc_dhost, arctypename,
8198524Sfenner			     length);
8298524Sfenner			     return;
8398524Sfenner	}
8498524Sfenner
8598524Sfenner	if (flag == 0) {
8698524Sfenner		(void)printf("%02x %02x %s seqid %04x %d: ",
8798524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
8898524Sfenner			length);
8998524Sfenner			return;
9098524Sfenner	}
9198524Sfenner
9298524Sfenner	if (flag & 1)
9398524Sfenner		(void)printf("%02x %02x %s seqid %04x "
9498524Sfenner			"(first of %d fragments) %d: ",
9598524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
9698524Sfenner			(flag + 3) / 2, length);
9798524Sfenner	else
9898524Sfenner		(void)printf("%02x %02x %s seqid %04x "
9998524Sfenner			"(fragment %d) %d: ",
10098524Sfenner			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
10198524Sfenner			flag/2 + 1, length);
10298524Sfenner}
10398524Sfenner
10498524Sfenner/*
105127668Sbms * This is the top level routine of the printer.  'p' points
106127668Sbms * to the ARCNET header of the packet, 'h->ts' is the timestamp,
107146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
10898524Sfenner * is the number of bytes actually captured.
10998524Sfenner */
110127668Sbmsu_int
111127668Sbmsarcnet_if_print(const struct pcap_pkthdr *h, const u_char *p)
11298524Sfenner{
11398524Sfenner	u_int caplen = h->caplen;
11498524Sfenner	u_int length = h->len;
11598524Sfenner	const struct arc_header *ap;
11698524Sfenner
11798524Sfenner	int phds, flag = 0, archdrlen = 0;
11898524Sfenner	u_int seqid = 0;
11998524Sfenner	u_char arc_type;
12098524Sfenner
12198524Sfenner	if (caplen < ARC_HDRLEN) {
12298524Sfenner		printf("[|arcnet]");
123127668Sbms		return (caplen);
12498524Sfenner	}
12598524Sfenner
12698524Sfenner	ap = (const struct arc_header *)p;
12798524Sfenner	arc_type = ap->arc_type;
12898524Sfenner
12998524Sfenner	switch (arc_type) {
13098524Sfenner	default:
13198524Sfenner		phds = 1;
13298524Sfenner		break;
13398524Sfenner	case ARCTYPE_IP_OLD:
13498524Sfenner	case ARCTYPE_ARP_OLD:
13598524Sfenner	case ARCTYPE_DIAGNOSE:
13698524Sfenner		phds = 0;
13798524Sfenner		archdrlen = ARC_HDRLEN;
13898524Sfenner		break;
13998524Sfenner	}
14098524Sfenner
14198524Sfenner	if (phds) {
14298524Sfenner		if (caplen < ARC_HDRNEWLEN) {
14398524Sfenner			arcnet_print(p, length, 0, 0, 0);
14498524Sfenner			printf("[|phds]");
145127668Sbms			return (caplen);
14698524Sfenner		}
14798524Sfenner
14898524Sfenner		if (ap->arc_flag == 0xff) {
14998524Sfenner			if (caplen < ARC_HDRNEWLEN_EXC) {
15098524Sfenner				arcnet_print(p, length, 0, 0, 0);
15198524Sfenner				printf("[|phds extended]");
152127668Sbms				return (caplen);
15398524Sfenner			}
15498524Sfenner			flag = ap->arc_flag2;
155214478Srpaulo			seqid = EXTRACT_16BITS(&ap->arc_seqid2);
15698524Sfenner			archdrlen = ARC_HDRNEWLEN_EXC;
15798524Sfenner		} else {
15898524Sfenner			flag = ap->arc_flag;
159214478Srpaulo			seqid = EXTRACT_16BITS(&ap->arc_seqid);
16098524Sfenner			archdrlen = ARC_HDRNEWLEN;
16198524Sfenner		}
16298524Sfenner	}
16398524Sfenner
16498524Sfenner
16598524Sfenner	if (eflag)
16698524Sfenner		arcnet_print(p, length, phds, flag, seqid);
16798524Sfenner
16898524Sfenner	/*
169127668Sbms	 * Go past the ARCNET header.
17098524Sfenner	 */
17198524Sfenner	length -= archdrlen;
17298524Sfenner	caplen -= archdrlen;
17398524Sfenner	p += archdrlen;
17498524Sfenner
175127668Sbms	if (phds && flag && (flag & 1) == 0) {
176127668Sbms		/*
177127668Sbms		 * This is a middle fragment.
178127668Sbms		 */
179127668Sbms		return (archdrlen);
180127668Sbms	}
18198524Sfenner
182127668Sbms	if (!arcnet_encap_print(arc_type, p, length, caplen))
18398524Sfenner		default_print(p, caplen);
184127668Sbms
185127668Sbms	return (archdrlen);
186127668Sbms}
187127668Sbms
188127668Sbms/*
189127668Sbms * This is the top level routine of the printer.  'p' points
190127668Sbms * to the ARCNET header of the packet, 'h->ts' is the timestamp,
191146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen'
192127668Sbms * is the number of bytes actually captured.  It is quite similar
193127668Sbms * to the non-Linux style printer except that Linux doesn't ever
194127668Sbms * supply packets that look like exception frames, it always supplies
195127668Sbms * reassembled packets rather than raw frames, and headers have an
196127668Sbms * extra "offset" field between the src/dest and packet type.
197127668Sbms */
198127668Sbmsu_int
199127668Sbmsarcnet_linux_if_print(const struct pcap_pkthdr *h, const u_char *p)
200127668Sbms{
201127668Sbms	u_int caplen = h->caplen;
202127668Sbms	u_int length = h->len;
203127668Sbms	const struct arc_linux_header *ap;
204127668Sbms
205127668Sbms	int archdrlen = 0;
206127668Sbms	u_char arc_type;
207127668Sbms
208127668Sbms	if (caplen < ARC_LINUX_HDRLEN) {
209127668Sbms		printf("[|arcnet]");
210127668Sbms		return (caplen);
21198524Sfenner	}
21298524Sfenner
213127668Sbms	ap = (const struct arc_linux_header *)p;
214127668Sbms	arc_type = ap->arc_type;
215127668Sbms
216127668Sbms	switch (arc_type) {
217127668Sbms	default:
218127668Sbms		archdrlen = ARC_LINUX_HDRNEWLEN;
219127668Sbms		if (caplen < ARC_LINUX_HDRNEWLEN) {
220127668Sbms			printf("[|arcnet]");
221127668Sbms			return (caplen);
222127668Sbms		}
223127668Sbms		break;
224127668Sbms	case ARCTYPE_IP_OLD:
225127668Sbms	case ARCTYPE_ARP_OLD:
226127668Sbms	case ARCTYPE_DIAGNOSE:
227127668Sbms		archdrlen = ARC_LINUX_HDRLEN;
228127668Sbms		break;
229127668Sbms	}
230127668Sbms
231127668Sbms	if (eflag)
232127668Sbms		arcnet_print(p, length, 0, 0, 0);
233127668Sbms
234127668Sbms	/*
235127668Sbms	 * Go past the ARCNET header.
236127668Sbms	 */
237127668Sbms	length -= archdrlen;
238127668Sbms	caplen -= archdrlen;
239127668Sbms	p += archdrlen;
240127668Sbms
241127668Sbms	if (!arcnet_encap_print(arc_type, p, length, caplen))
24298524Sfenner		default_print(p, caplen);
24398524Sfenner
244127668Sbms	return (archdrlen);
24598524Sfenner}
24698524Sfenner
24798524Sfenner/*
24898524Sfenner * Prints the packet encapsulated in an ARCnet data field,
24998524Sfenner * given the ARCnet system code.
25098524Sfenner *
25198524Sfenner * Returns non-zero if it can do so, zero if the system code is unknown.
25298524Sfenner */
25398524Sfenner
25498524Sfenner
255127668Sbmsstatic int
25698524Sfennerarcnet_encap_print(u_char arctype, const u_char *p,
25798524Sfenner    u_int length, u_int caplen)
25898524Sfenner{
25998524Sfenner	switch (arctype) {
26098524Sfenner
26198524Sfenner	case ARCTYPE_IP_OLD:
26298524Sfenner	case ARCTYPE_IP:
263146773Ssam	        ip_print(gndo, p, length);
26498524Sfenner		return (1);
26598524Sfenner
26698524Sfenner#ifdef INET6
26798524Sfenner	case ARCTYPE_INET6:
268235530Sdelphij		ip6_print(gndo, p, length);
26998524Sfenner		return (1);
27098524Sfenner#endif /*INET6*/
27198524Sfenner
27298524Sfenner	case ARCTYPE_ARP_OLD:
27398524Sfenner	case ARCTYPE_ARP:
27498524Sfenner	case ARCTYPE_REVARP:
275235530Sdelphij		arp_print(gndo, p, length, caplen);
27698524Sfenner		return (1);
27798524Sfenner
27898524Sfenner	case ARCTYPE_ATALK:	/* XXX was this ever used? */
27998524Sfenner		if (vflag)
28098524Sfenner			fputs("et1 ", stdout);
28198524Sfenner		atalk_print(p, length);
28298524Sfenner		return (1);
28398524Sfenner
284127668Sbms	case ARCTYPE_IPX:
285127668Sbms		ipx_print(p, length);
286127668Sbms		return (1);
287127668Sbms
28898524Sfenner	default:
28998524Sfenner		return (0);
29098524Sfenner	}
29198524Sfenner}
292146773Ssam
293146773Ssam/*
294146773Ssam * Local Variables:
295146773Ssam * c-style: bsd
296146773Ssam * End:
297146773Ssam */
298146773Ssam
299