Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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  * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp
     22  */
     23 #ifndef lint
     24 static const char rcsid[] _U_ =
     25     "@(#) $Header: /tcpdump/master/tcpdump/print-arcnet.c,v 1.20 2005-04-06 21:32:38 mcr Exp $ (LBL)";
     26 #endif
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <tcpdump-stdinc.h>
     33 
     34 #include <stdio.h>
     35 #include <pcap.h>
     36 
     37 #include "interface.h"
     38 #include "extract.h"
     39 #include "arcnet.h"
     40 
     41 static int arcnet_encap_print(u_char arctype, const u_char *p,
     42     u_int length, u_int caplen);
     43 
     44 static const struct tok arctypemap[] = {
     45 	{ ARCTYPE_IP_OLD,	"oldip" },
     46 	{ ARCTYPE_ARP_OLD,	"oldarp" },
     47 	{ ARCTYPE_IP,		"ip" },
     48 	{ ARCTYPE_ARP,		"arp" },
     49 	{ ARCTYPE_REVARP,	"rarp" },
     50 	{ ARCTYPE_ATALK,	"atalk" },
     51 	{ ARCTYPE_BANIAN,	"banyan" },
     52 	{ ARCTYPE_IPX,		"ipx" },
     53 	{ ARCTYPE_INET6,	"ipv6" },
     54 	{ ARCTYPE_DIAGNOSE,	"diag" },
     55 	{ 0, 0 }
     56 };
     57 
     58 static inline void
     59 arcnet_print(const u_char *bp, u_int length, int phds, int flag, u_int seqid)
     60 {
     61 	const struct arc_header *ap;
     62 	const char *arctypename;
     63 
     64 
     65 	ap = (const struct arc_header *)bp;
     66 
     67 
     68 	if (qflag) {
     69 		(void)printf("%02x %02x %d: ",
     70 			     ap->arc_shost,
     71 			     ap->arc_dhost,
     72 			     length);
     73 		return;
     74 	}
     75 
     76 	arctypename = tok2str(arctypemap, "%02x", ap->arc_type);
     77 
     78 	if (!phds) {
     79 		(void)printf("%02x %02x %s %d: ",
     80 			     ap->arc_shost, ap->arc_dhost, arctypename,
     81 			     length);
     82 			     return;
     83 	}
     84 
     85 	if (flag == 0) {
     86 		(void)printf("%02x %02x %s seqid %04x %d: ",
     87 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
     88 			length);
     89 			return;
     90 	}
     91 
     92 	if (flag & 1)
     93 		(void)printf("%02x %02x %s seqid %04x "
     94 			"(first of %d fragments) %d: ",
     95 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
     96 			(flag + 3) / 2, length);
     97 	else
     98 		(void)printf("%02x %02x %s seqid %04x "
     99 			"(fragment %d) %d: ",
    100 			ap->arc_shost, ap->arc_dhost, arctypename, seqid,
    101 			flag/2 + 1, length);
    102 }
    103 
    104 /*
    105  * This is the top level routine of the printer.  'p' points
    106  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
    107  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
    108  * is the number of bytes actually captured.
    109  */
    110 u_int
    111 arcnet_if_print(const struct pcap_pkthdr *h, const u_char *p)
    112 {
    113 	u_int caplen = h->caplen;
    114 	u_int length = h->len;
    115 	const struct arc_header *ap;
    116 
    117 	int phds, flag = 0, archdrlen = 0;
    118 	u_int seqid = 0;
    119 	u_char arc_type;
    120 
    121 	if (caplen < ARC_HDRLEN) {
    122 		printf("[|arcnet]");
    123 		return (caplen);
    124 	}
    125 
    126 	ap = (const struct arc_header *)p;
    127 	arc_type = ap->arc_type;
    128 
    129 	switch (arc_type) {
    130 	default:
    131 		phds = 1;
    132 		break;
    133 	case ARCTYPE_IP_OLD:
    134 	case ARCTYPE_ARP_OLD:
    135 	case ARCTYPE_DIAGNOSE:
    136 		phds = 0;
    137 		archdrlen = ARC_HDRLEN;
    138 		break;
    139 	}
    140 
    141 	if (phds) {
    142 		if (caplen < ARC_HDRNEWLEN) {
    143 			arcnet_print(p, length, 0, 0, 0);
    144 			printf("[|phds]");
    145 			return (caplen);
    146 		}
    147 
    148 		if (ap->arc_flag == 0xff) {
    149 			if (caplen < ARC_HDRNEWLEN_EXC) {
    150 				arcnet_print(p, length, 0, 0, 0);
    151 				printf("[|phds extended]");
    152 				return (caplen);
    153 			}
    154 			flag = ap->arc_flag2;
    155 			seqid = EXTRACT_16BITS(&ap->arc_seqid2);
    156 			archdrlen = ARC_HDRNEWLEN_EXC;
    157 		} else {
    158 			flag = ap->arc_flag;
    159 			seqid = EXTRACT_16BITS(&ap->arc_seqid);
    160 			archdrlen = ARC_HDRNEWLEN;
    161 		}
    162 	}
    163 
    164 
    165 	if (eflag)
    166 		arcnet_print(p, length, phds, flag, seqid);
    167 
    168 	/*
    169 	 * Go past the ARCNET header.
    170 	 */
    171 	length -= archdrlen;
    172 	caplen -= archdrlen;
    173 	p += archdrlen;
    174 
    175 	if (phds && flag && (flag & 1) == 0) {
    176 		/*
    177 		 * This is a middle fragment.
    178 		 */
    179 		return (archdrlen);
    180 	}
    181 
    182 	if (!arcnet_encap_print(arc_type, p, length, caplen))
    183 		default_print(p, caplen);
    184 
    185 	return (archdrlen);
    186 }
    187 
    188 /*
    189  * This is the top level routine of the printer.  'p' points
    190  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
    191  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
    192  * is the number of bytes actually captured.  It is quite similar
    193  * to the non-Linux style printer except that Linux doesn't ever
    194  * supply packets that look like exception frames, it always supplies
    195  * reassembled packets rather than raw frames, and headers have an
    196  * extra "offset" field between the src/dest and packet type.
    197  */
    198 u_int
    199 arcnet_linux_if_print(const struct pcap_pkthdr *h, const u_char *p)
    200 {
    201 	u_int caplen = h->caplen;
    202 	u_int length = h->len;
    203 	const struct arc_linux_header *ap;
    204 
    205 	int archdrlen = 0;
    206 	u_char arc_type;
    207 
    208 	if (caplen < ARC_LINUX_HDRLEN) {
    209 		printf("[|arcnet]");
    210 		return (caplen);
    211 	}
    212 
    213 	ap = (const struct arc_linux_header *)p;
    214 	arc_type = ap->arc_type;
    215 
    216 	switch (arc_type) {
    217 	default:
    218 		archdrlen = ARC_LINUX_HDRNEWLEN;
    219 		if (caplen < ARC_LINUX_HDRNEWLEN) {
    220 			printf("[|arcnet]");
    221 			return (caplen);
    222 		}
    223 		break;
    224 	case ARCTYPE_IP_OLD:
    225 	case ARCTYPE_ARP_OLD:
    226 	case ARCTYPE_DIAGNOSE:
    227 		archdrlen = ARC_LINUX_HDRLEN;
    228 		break;
    229 	}
    230 
    231 	if (eflag)
    232 		arcnet_print(p, length, 0, 0, 0);
    233 
    234 	/*
    235 	 * Go past the ARCNET header.
    236 	 */
    237 	length -= archdrlen;
    238 	caplen -= archdrlen;
    239 	p += archdrlen;
    240 
    241 	if (!arcnet_encap_print(arc_type, p, length, caplen))
    242 		default_print(p, caplen);
    243 
    244 	return (archdrlen);
    245 }
    246 
    247 /*
    248  * Prints the packet encapsulated in an ARCnet data field,
    249  * given the ARCnet system code.
    250  *
    251  * Returns non-zero if it can do so, zero if the system code is unknown.
    252  */
    253 
    254 
    255 static int
    256 arcnet_encap_print(u_char arctype, const u_char *p,
    257     u_int length, u_int caplen)
    258 {
    259 	switch (arctype) {
    260 
    261 	case ARCTYPE_IP_OLD:
    262 	case ARCTYPE_IP:
    263 	        ip_print(gndo, p, length);
    264 		return (1);
    265 
    266 #ifdef INET6
    267 	case ARCTYPE_INET6:
    268 		ip6_print(gndo, p, length);
    269 		return (1);
    270 #endif /*INET6*/
    271 
    272 	case ARCTYPE_ARP_OLD:
    273 	case ARCTYPE_ARP:
    274 	case ARCTYPE_REVARP:
    275 		arp_print(gndo, p, length, caplen);
    276 		return (1);
    277 
    278 	case ARCTYPE_ATALK:	/* XXX was this ever used? */
    279 		if (vflag)
    280 			fputs("et1 ", stdout);
    281 		atalk_print(p, length);
    282 		return (1);
    283 
    284 	case ARCTYPE_IPX:
    285 		ipx_print(p, length);
    286 		return (1);
    287 
    288 	default:
    289 		return (0);
    290 	}
    291 }
    292 
    293 /*
    294  * Local Variables:
    295  * c-style: bsd
    296  * End:
    297  */
    298 
    299