Home | History | Annotate | Line # | Download | only in dist
      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 #include <sys/cdefs.h>
     24 #ifndef lint
     25 __RCSID("$NetBSD: print-arcnet.c,v 1.10 2024/09/02 16:15:30 christos Exp $");
     26 #endif
     27 
     28 /* \summary: Attached Resource Computer NETwork (ARCNET) printer */
     29 
     30 #include <config.h>
     31 
     32 #include "netdissect-stdinc.h"
     33 
     34 #include "netdissect.h"
     35 #include "extract.h"
     36 
     37 /*
     38  * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp
     39  */
     40 
     41 /*
     42  * Structure of a 2.5MB/s Arcnet header on the BSDs,
     43  * as given to interface code.
     44  */
     45 struct	arc_header {
     46 	nd_uint8_t  arc_shost;
     47 	nd_uint8_t  arc_dhost;
     48 	nd_uint8_t  arc_type;
     49 	/*
     50 	 * only present for newstyle encoding with LL fragmentation.
     51 	 * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead.
     52 	 */
     53 	nd_uint8_t  arc_flag;
     54 	nd_uint16_t arc_seqid;
     55 
     56 	/*
     57 	 * only present in exception packets (arc_flag == 0xff)
     58 	 */
     59 	nd_uint8_t  arc_type2;	/* same as arc_type */
     60 	nd_uint8_t  arc_flag2;	/* real flag value */
     61 	nd_uint16_t arc_seqid2;	/* real seqid value */
     62 };
     63 
     64 #define	ARC_HDRLEN		3
     65 #define	ARC_HDRNEWLEN		6
     66 #define	ARC_HDRNEWLEN_EXC	10
     67 
     68 /* RFC 1051 */
     69 #define	ARCTYPE_IP_OLD		240	/* IP protocol */
     70 #define	ARCTYPE_ARP_OLD		241	/* address resolution protocol */
     71 
     72 /* RFC 1201 */
     73 #define	ARCTYPE_IP		212	/* IP protocol */
     74 #define	ARCTYPE_ARP		213	/* address resolution protocol */
     75 #define	ARCTYPE_REVARP		214	/* reverse addr resolution protocol */
     76 
     77 #define	ARCTYPE_ATALK		221	/* Appletalk */
     78 #define	ARCTYPE_BANIAN		247	/* Banyan Vines */
     79 #define	ARCTYPE_IPX		250	/* Novell IPX */
     80 
     81 #define ARCTYPE_INET6		0xc4	/* IPng */
     82 #define ARCTYPE_DIAGNOSE	0x80	/* as per ANSI/ATA 878.1 */
     83 
     84 /*
     85  * Structure of a 2.5MB/s Arcnet header on Linux.  Linux has
     86  * an extra "offset" field when given to interface code, and
     87  * never presents packets that look like exception frames.
     88  */
     89 struct	arc_linux_header {
     90 	nd_uint8_t  arc_shost;
     91 	nd_uint8_t  arc_dhost;
     92 	nd_uint16_t arc_offset;
     93 	nd_uint8_t  arc_type;
     94 	/*
     95 	 * only present for newstyle encoding with LL fragmentation.
     96 	 * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN
     97 	 * instead.
     98 	 */
     99 	nd_uint8_t  arc_flag;
    100 	nd_uint16_t arc_seqid;
    101 };
    102 
    103 #define	ARC_LINUX_HDRLEN	5
    104 #define	ARC_LINUX_HDRNEWLEN	8
    105 
    106 static int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p,
    107     u_int length, u_int caplen);
    108 
    109 static const struct tok arctypemap[] = {
    110 	{ ARCTYPE_IP_OLD,	"oldip" },
    111 	{ ARCTYPE_ARP_OLD,	"oldarp" },
    112 	{ ARCTYPE_IP,		"ip" },
    113 	{ ARCTYPE_ARP,		"arp" },
    114 	{ ARCTYPE_REVARP,	"rarp" },
    115 	{ ARCTYPE_ATALK,	"atalk" },
    116 	{ ARCTYPE_BANIAN,	"banyan" },
    117 	{ ARCTYPE_IPX,		"ipx" },
    118 	{ ARCTYPE_INET6,	"ipv6" },
    119 	{ ARCTYPE_DIAGNOSE,	"diag" },
    120 	{ 0, NULL }
    121 };
    122 
    123 static void
    124 arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds,
    125              u_int flag, u_int seqid)
    126 {
    127 	const struct arc_header *ap;
    128 	const char *arctypename;
    129 
    130 	ndo->ndo_protocol = "arcnet";
    131 	ap = (const struct arc_header *)bp;
    132 
    133 	if (ndo->ndo_qflag) {
    134 		ND_PRINT("%02x %02x %u: ",
    135 			     GET_U_1(ap->arc_shost),
    136 			     GET_U_1(ap->arc_dhost),
    137 			     length);
    138 		return;
    139 	}
    140 
    141 	arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type));
    142 
    143 	if (!phds) {
    144 		ND_PRINT("%02x %02x %s %u: ",
    145 			     GET_U_1(ap->arc_shost),
    146 			     GET_U_1(ap->arc_dhost),
    147 			     arctypename,
    148 			     length);
    149 		return;
    150 	}
    151 
    152 	if (flag == 0) {
    153 		ND_PRINT("%02x %02x %s seqid %04x %u: ",
    154 			GET_U_1(ap->arc_shost),
    155 			GET_U_1(ap->arc_dhost),
    156 			arctypename, seqid,
    157 			length);
    158 		return;
    159 	}
    160 
    161 	if (flag & 1)
    162 		ND_PRINT("%02x %02x %s seqid %04x "
    163 			"(first of %u fragments) %u: ",
    164 			GET_U_1(ap->arc_shost),
    165 			GET_U_1(ap->arc_dhost),
    166 			arctypename, seqid,
    167 			(flag + 3) / 2, length);
    168 	else
    169 		ND_PRINT("%02x %02x %s seqid %04x "
    170 			"(fragment %u) %u: ",
    171 			GET_U_1(ap->arc_shost),
    172 			GET_U_1(ap->arc_dhost),
    173 			arctypename, seqid,
    174 			flag/2 + 1, length);
    175 }
    176 
    177 /*
    178  * This is the top level routine of the printer.  'p' points
    179  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
    180  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
    181  * is the number of bytes actually captured.
    182  */
    183 void
    184 arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
    185 {
    186 	u_int caplen = h->caplen;
    187 	u_int length = h->len;
    188 	const struct arc_header *ap;
    189 
    190 	int phds;
    191 	u_int flag = 0, archdrlen = 0;
    192 	u_int seqid = 0;
    193 	u_char arc_type;
    194 
    195 	ndo->ndo_protocol = "arcnet";
    196 	if (caplen < ARC_HDRLEN) {
    197 		ndo->ndo_ll_hdr_len += caplen;
    198 		nd_trunc_longjmp(ndo);
    199 	}
    200 
    201 	ap = (const struct arc_header *)p;
    202 	arc_type = GET_U_1(ap->arc_type);
    203 
    204 	switch (arc_type) {
    205 	default:
    206 		phds = 1;
    207 		break;
    208 	case ARCTYPE_IP_OLD:
    209 	case ARCTYPE_ARP_OLD:
    210 	case ARCTYPE_DIAGNOSE:
    211 		phds = 0;
    212 		archdrlen = ARC_HDRLEN;
    213 		break;
    214 	}
    215 
    216 	if (phds) {
    217 		if (caplen < ARC_HDRNEWLEN) {
    218 			arcnet_print(ndo, p, length, 0, 0, 0);
    219 			ND_PRINT(" phds");
    220 			ndo->ndo_ll_hdr_len += caplen;
    221 			nd_trunc_longjmp(ndo);
    222 		}
    223 
    224 		flag = GET_U_1(ap->arc_flag);
    225 		if (flag == 0xff) {
    226 			if (caplen < ARC_HDRNEWLEN_EXC) {
    227 				arcnet_print(ndo, p, length, 0, 0, 0);
    228 				ND_PRINT(" phds extended");
    229 				ndo->ndo_ll_hdr_len += caplen;
    230 				nd_trunc_longjmp(ndo);
    231 			}
    232 			flag = GET_U_1(ap->arc_flag2);
    233 			seqid = GET_BE_U_2(ap->arc_seqid2);
    234 			archdrlen = ARC_HDRNEWLEN_EXC;
    235 		} else {
    236 			seqid = GET_BE_U_2(ap->arc_seqid);
    237 			archdrlen = ARC_HDRNEWLEN;
    238 		}
    239 	}
    240 
    241 
    242 	if (ndo->ndo_eflag)
    243 		arcnet_print(ndo, p, length, phds, flag, seqid);
    244 
    245 	/*
    246 	 * Go past the ARCNET header.
    247 	 */
    248 	length -= archdrlen;
    249 	caplen -= archdrlen;
    250 	p += archdrlen;
    251 
    252 	if (phds && flag && (flag & 1) == 0) {
    253 		/*
    254 		 * This is a middle fragment.
    255 		 */
    256 		ndo->ndo_ll_hdr_len += archdrlen;
    257 		return;
    258 	}
    259 
    260 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
    261 		ND_DEFAULTPRINT(p, caplen);
    262 
    263 	ndo->ndo_ll_hdr_len += archdrlen;
    264 }
    265 
    266 /*
    267  * This is the top level routine of the printer.  'p' points
    268  * to the ARCNET header of the packet, 'h->ts' is the timestamp,
    269  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
    270  * is the number of bytes actually captured.  It is quite similar
    271  * to the non-Linux style printer except that Linux doesn't ever
    272  * supply packets that look like exception frames, it always supplies
    273  * reassembled packets rather than raw frames, and headers have an
    274  * extra "offset" field between the src/dest and packet type.
    275  */
    276 void
    277 arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
    278 {
    279 	u_int caplen = h->caplen;
    280 	u_int length = h->len;
    281 	const struct arc_linux_header *ap;
    282 
    283 	int archdrlen = 0;
    284 	u_char arc_type;
    285 
    286 	ndo->ndo_protocol = "arcnet_linux";
    287 	if (caplen < ARC_LINUX_HDRLEN) {
    288 		ndo->ndo_ll_hdr_len += caplen;
    289 		nd_trunc_longjmp(ndo);
    290 	}
    291 
    292 	ap = (const struct arc_linux_header *)p;
    293 	arc_type = GET_U_1(ap->arc_type);
    294 
    295 	switch (arc_type) {
    296 	default:
    297 		archdrlen = ARC_LINUX_HDRNEWLEN;
    298 		if (caplen < ARC_LINUX_HDRNEWLEN) {
    299 			ndo->ndo_ll_hdr_len += caplen;
    300 			nd_trunc_longjmp(ndo);
    301 		}
    302 		break;
    303 	case ARCTYPE_IP_OLD:
    304 	case ARCTYPE_ARP_OLD:
    305 	case ARCTYPE_DIAGNOSE:
    306 		archdrlen = ARC_LINUX_HDRLEN;
    307 		break;
    308 	}
    309 
    310 	if (ndo->ndo_eflag)
    311 		arcnet_print(ndo, p, length, 0, 0, 0);
    312 
    313 	/*
    314 	 * Go past the ARCNET header.
    315 	 */
    316 	length -= archdrlen;
    317 	caplen -= archdrlen;
    318 	p += archdrlen;
    319 
    320 	if (!arcnet_encap_print(ndo, arc_type, p, length, caplen))
    321 		ND_DEFAULTPRINT(p, caplen);
    322 
    323 	ndo->ndo_ll_hdr_len += archdrlen;
    324 }
    325 
    326 /*
    327  * Prints the packet encapsulated in an ARCnet data field,
    328  * given the ARCnet system code.
    329  *
    330  * Returns non-zero if it can do so, zero if the system code is unknown.
    331  */
    332 
    333 
    334 static int
    335 arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p,
    336     u_int length, u_int caplen)
    337 {
    338 	switch (arctype) {
    339 
    340 	case ARCTYPE_IP_OLD:
    341 	case ARCTYPE_IP:
    342 	        ip_print(ndo, p, length);
    343 		return (1);
    344 
    345 	case ARCTYPE_INET6:
    346 		ip6_print(ndo, p, length);
    347 		return (1);
    348 
    349 	case ARCTYPE_ARP_OLD:
    350 	case ARCTYPE_ARP:
    351 	case ARCTYPE_REVARP:
    352 		arp_print(ndo, p, length, caplen);
    353 		return (1);
    354 
    355 	case ARCTYPE_ATALK:	/* XXX was this ever used? */
    356 		if (ndo->ndo_vflag)
    357 			ND_PRINT("et1 ");
    358 		atalk_print(ndo, p, length);
    359 		return (1);
    360 
    361 	case ARCTYPE_IPX:
    362 		ipx_print(ndo, p, length);
    363 		return (1);
    364 
    365 	default:
    366 		return (0);
    367 	}
    368 }
    369