10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos * 210f74e101Schristos * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp 220f74e101Schristos */ 2311b3aaa1Schristos #include <sys/cdefs.h> 240f74e101Schristos #ifndef lint 25*26ba0b50Schristos __RCSID("$NetBSD: print-arcnet.c,v 1.10 2024/09/02 16:15:30 christos Exp $"); 260f74e101Schristos #endif 270f74e101Schristos 28dc860a36Sspz /* \summary: Attached Resource Computer NETwork (ARCNET) printer */ 29dc860a36Sspz 30c74ad251Schristos #include <config.h> 310f74e101Schristos 32c74ad251Schristos #include "netdissect-stdinc.h" 330f74e101Schristos 34fdccd7e4Schristos #include "netdissect.h" 350f74e101Schristos #include "extract.h" 360f74e101Schristos 37b3a00663Schristos /* 38b3a00663Schristos * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp 39b3a00663Schristos */ 40b3a00663Schristos 41b3a00663Schristos /* 42b3a00663Schristos * Structure of a 2.5MB/s Arcnet header on the BSDs, 43b3a00663Schristos * as given to interface code. 44b3a00663Schristos */ 45b3a00663Schristos struct arc_header { 46c74ad251Schristos nd_uint8_t arc_shost; 47c74ad251Schristos nd_uint8_t arc_dhost; 48c74ad251Schristos nd_uint8_t arc_type; 49b3a00663Schristos /* 50b3a00663Schristos * only present for newstyle encoding with LL fragmentation. 51b3a00663Schristos * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead. 52b3a00663Schristos */ 53c74ad251Schristos nd_uint8_t arc_flag; 54c74ad251Schristos nd_uint16_t arc_seqid; 55b3a00663Schristos 56b3a00663Schristos /* 57b3a00663Schristos * only present in exception packets (arc_flag == 0xff) 58b3a00663Schristos */ 59c74ad251Schristos nd_uint8_t arc_type2; /* same as arc_type */ 60c74ad251Schristos nd_uint8_t arc_flag2; /* real flag value */ 61c74ad251Schristos nd_uint16_t arc_seqid2; /* real seqid value */ 62b3a00663Schristos }; 63b3a00663Schristos 64b3a00663Schristos #define ARC_HDRLEN 3 65b3a00663Schristos #define ARC_HDRNEWLEN 6 66b3a00663Schristos #define ARC_HDRNEWLEN_EXC 10 67b3a00663Schristos 68b3a00663Schristos /* RFC 1051 */ 69b3a00663Schristos #define ARCTYPE_IP_OLD 240 /* IP protocol */ 70b3a00663Schristos #define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ 71b3a00663Schristos 72b3a00663Schristos /* RFC 1201 */ 73b3a00663Schristos #define ARCTYPE_IP 212 /* IP protocol */ 74b3a00663Schristos #define ARCTYPE_ARP 213 /* address resolution protocol */ 75b3a00663Schristos #define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ 76b3a00663Schristos 77b3a00663Schristos #define ARCTYPE_ATALK 221 /* Appletalk */ 78b3a00663Schristos #define ARCTYPE_BANIAN 247 /* Banyan Vines */ 79b3a00663Schristos #define ARCTYPE_IPX 250 /* Novell IPX */ 80b3a00663Schristos 81b3a00663Schristos #define ARCTYPE_INET6 0xc4 /* IPng */ 82b3a00663Schristos #define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ 83b3a00663Schristos 84b3a00663Schristos /* 85b3a00663Schristos * Structure of a 2.5MB/s Arcnet header on Linux. Linux has 86b3a00663Schristos * an extra "offset" field when given to interface code, and 87b3a00663Schristos * never presents packets that look like exception frames. 88b3a00663Schristos */ 89b3a00663Schristos struct arc_linux_header { 90c74ad251Schristos nd_uint8_t arc_shost; 91c74ad251Schristos nd_uint8_t arc_dhost; 92c74ad251Schristos nd_uint16_t arc_offset; 93c74ad251Schristos nd_uint8_t arc_type; 94b3a00663Schristos /* 95b3a00663Schristos * only present for newstyle encoding with LL fragmentation. 96b3a00663Schristos * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN 97b3a00663Schristos * instead. 98b3a00663Schristos */ 99c74ad251Schristos nd_uint8_t arc_flag; 100c74ad251Schristos nd_uint16_t arc_seqid; 101b3a00663Schristos }; 102b3a00663Schristos 103b3a00663Schristos #define ARC_LINUX_HDRLEN 5 104b3a00663Schristos #define ARC_LINUX_HDRNEWLEN 8 105b3a00663Schristos 106b3a00663Schristos static int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p, 1070f74e101Schristos u_int length, u_int caplen); 1080f74e101Schristos 109870189d2Schristos static const struct tok arctypemap[] = { 1100f74e101Schristos { ARCTYPE_IP_OLD, "oldip" }, 1110f74e101Schristos { ARCTYPE_ARP_OLD, "oldarp" }, 1120f74e101Schristos { ARCTYPE_IP, "ip" }, 1130f74e101Schristos { ARCTYPE_ARP, "arp" }, 1140f74e101Schristos { ARCTYPE_REVARP, "rarp" }, 1150f74e101Schristos { ARCTYPE_ATALK, "atalk" }, 1160f74e101Schristos { ARCTYPE_BANIAN, "banyan" }, 1170f74e101Schristos { ARCTYPE_IPX, "ipx" }, 1180f74e101Schristos { ARCTYPE_INET6, "ipv6" }, 1190f74e101Schristos { ARCTYPE_DIAGNOSE, "diag" }, 120c74ad251Schristos { 0, NULL } 1210f74e101Schristos }; 1220f74e101Schristos 123c74ad251Schristos static void 124b3a00663Schristos arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds, 125c74ad251Schristos u_int flag, u_int seqid) 1260f74e101Schristos { 1270f74e101Schristos const struct arc_header *ap; 1280f74e101Schristos const char *arctypename; 1290f74e101Schristos 130c74ad251Schristos ndo->ndo_protocol = "arcnet"; 1310f74e101Schristos ap = (const struct arc_header *)bp; 1320f74e101Schristos 133b3a00663Schristos if (ndo->ndo_qflag) { 134c74ad251Schristos ND_PRINT("%02x %02x %u: ", 135c74ad251Schristos GET_U_1(ap->arc_shost), 136c74ad251Schristos GET_U_1(ap->arc_dhost), 137c74ad251Schristos length); 1380f74e101Schristos return; 1390f74e101Schristos } 1400f74e101Schristos 141c74ad251Schristos arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type)); 1420f74e101Schristos 1430f74e101Schristos if (!phds) { 144c74ad251Schristos ND_PRINT("%02x %02x %s %u: ", 145c74ad251Schristos GET_U_1(ap->arc_shost), 146c74ad251Schristos GET_U_1(ap->arc_dhost), 147c74ad251Schristos arctypename, 148c74ad251Schristos length); 1490f74e101Schristos return; 1500f74e101Schristos } 1510f74e101Schristos 1520f74e101Schristos if (flag == 0) { 153c74ad251Schristos ND_PRINT("%02x %02x %s seqid %04x %u: ", 154c74ad251Schristos GET_U_1(ap->arc_shost), 155c74ad251Schristos GET_U_1(ap->arc_dhost), 156c74ad251Schristos arctypename, seqid, 157c74ad251Schristos length); 1580f74e101Schristos return; 1590f74e101Schristos } 1600f74e101Schristos 1610f74e101Schristos if (flag & 1) 162c74ad251Schristos ND_PRINT("%02x %02x %s seqid %04x " 163c74ad251Schristos "(first of %u fragments) %u: ", 164c74ad251Schristos GET_U_1(ap->arc_shost), 165c74ad251Schristos GET_U_1(ap->arc_dhost), 166c74ad251Schristos arctypename, seqid, 167c74ad251Schristos (flag + 3) / 2, length); 1680f74e101Schristos else 169c74ad251Schristos ND_PRINT("%02x %02x %s seqid %04x " 170c74ad251Schristos "(fragment %u) %u: ", 171c74ad251Schristos GET_U_1(ap->arc_shost), 172c74ad251Schristos GET_U_1(ap->arc_dhost), 173c74ad251Schristos arctypename, seqid, 174c74ad251Schristos flag/2 + 1, length); 1750f74e101Schristos } 1760f74e101Schristos 1770f74e101Schristos /* 1780f74e101Schristos * This is the top level routine of the printer. 'p' points 1790f74e101Schristos * to the ARCNET header of the packet, 'h->ts' is the timestamp, 1800f74e101Schristos * 'h->len' is the length of the packet off the wire, and 'h->caplen' 1810f74e101Schristos * is the number of bytes actually captured. 1820f74e101Schristos */ 183c74ad251Schristos void 184b3a00663Schristos arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) 1850f74e101Schristos { 1860f74e101Schristos u_int caplen = h->caplen; 1870f74e101Schristos u_int length = h->len; 1880f74e101Schristos const struct arc_header *ap; 1890f74e101Schristos 190c74ad251Schristos int phds; 191c74ad251Schristos u_int flag = 0, archdrlen = 0; 1920f74e101Schristos u_int seqid = 0; 1930f74e101Schristos u_char arc_type; 1940f74e101Schristos 195c74ad251Schristos ndo->ndo_protocol = "arcnet"; 196c74ad251Schristos if (caplen < ARC_HDRLEN) { 197c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 198c74ad251Schristos nd_trunc_longjmp(ndo); 1990f74e101Schristos } 2000f74e101Schristos 2010f74e101Schristos ap = (const struct arc_header *)p; 202c74ad251Schristos arc_type = GET_U_1(ap->arc_type); 2030f74e101Schristos 2040f74e101Schristos switch (arc_type) { 2050f74e101Schristos default: 2060f74e101Schristos phds = 1; 2070f74e101Schristos break; 2080f74e101Schristos case ARCTYPE_IP_OLD: 2090f74e101Schristos case ARCTYPE_ARP_OLD: 2100f74e101Schristos case ARCTYPE_DIAGNOSE: 2110f74e101Schristos phds = 0; 2120f74e101Schristos archdrlen = ARC_HDRLEN; 2130f74e101Schristos break; 2140f74e101Schristos } 2150f74e101Schristos 2160f74e101Schristos if (phds) { 217c74ad251Schristos if (caplen < ARC_HDRNEWLEN) { 218b3a00663Schristos arcnet_print(ndo, p, length, 0, 0, 0); 219c74ad251Schristos ND_PRINT(" phds"); 220c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 221c74ad251Schristos nd_trunc_longjmp(ndo); 2220f74e101Schristos } 2230f74e101Schristos 224c74ad251Schristos flag = GET_U_1(ap->arc_flag); 225c74ad251Schristos if (flag == 0xff) { 226c74ad251Schristos if (caplen < ARC_HDRNEWLEN_EXC) { 227b3a00663Schristos arcnet_print(ndo, p, length, 0, 0, 0); 228c74ad251Schristos ND_PRINT(" phds extended"); 229c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 230c74ad251Schristos nd_trunc_longjmp(ndo); 2310f74e101Schristos } 232c74ad251Schristos flag = GET_U_1(ap->arc_flag2); 233c74ad251Schristos seqid = GET_BE_U_2(ap->arc_seqid2); 2340f74e101Schristos archdrlen = ARC_HDRNEWLEN_EXC; 2350f74e101Schristos } else { 236c74ad251Schristos seqid = GET_BE_U_2(ap->arc_seqid); 2370f74e101Schristos archdrlen = ARC_HDRNEWLEN; 2380f74e101Schristos } 2390f74e101Schristos } 2400f74e101Schristos 2410f74e101Schristos 242b3a00663Schristos if (ndo->ndo_eflag) 243b3a00663Schristos arcnet_print(ndo, p, length, phds, flag, seqid); 2440f74e101Schristos 2450f74e101Schristos /* 2460f74e101Schristos * Go past the ARCNET header. 2470f74e101Schristos */ 2480f74e101Schristos length -= archdrlen; 2490f74e101Schristos caplen -= archdrlen; 2500f74e101Schristos p += archdrlen; 2510f74e101Schristos 2520f74e101Schristos if (phds && flag && (flag & 1) == 0) { 2530f74e101Schristos /* 2540f74e101Schristos * This is a middle fragment. 2550f74e101Schristos */ 256c74ad251Schristos ndo->ndo_ll_hdr_len += archdrlen; 257c74ad251Schristos return; 2580f74e101Schristos } 2590f74e101Schristos 260b3a00663Schristos if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) 261b3a00663Schristos ND_DEFAULTPRINT(p, caplen); 2620f74e101Schristos 263c74ad251Schristos ndo->ndo_ll_hdr_len += archdrlen; 2640f74e101Schristos } 2650f74e101Schristos 2660f74e101Schristos /* 2670f74e101Schristos * This is the top level routine of the printer. 'p' points 2680f74e101Schristos * to the ARCNET header of the packet, 'h->ts' is the timestamp, 2690f74e101Schristos * 'h->len' is the length of the packet off the wire, and 'h->caplen' 2700f74e101Schristos * is the number of bytes actually captured. It is quite similar 2710f74e101Schristos * to the non-Linux style printer except that Linux doesn't ever 2720f74e101Schristos * supply packets that look like exception frames, it always supplies 2730f74e101Schristos * reassembled packets rather than raw frames, and headers have an 2740f74e101Schristos * extra "offset" field between the src/dest and packet type. 2750f74e101Schristos */ 276c74ad251Schristos void 277b3a00663Schristos arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) 2780f74e101Schristos { 2790f74e101Schristos u_int caplen = h->caplen; 2800f74e101Schristos u_int length = h->len; 2810f74e101Schristos const struct arc_linux_header *ap; 2820f74e101Schristos 2830f74e101Schristos int archdrlen = 0; 2840f74e101Schristos u_char arc_type; 2850f74e101Schristos 286c74ad251Schristos ndo->ndo_protocol = "arcnet_linux"; 287c74ad251Schristos if (caplen < ARC_LINUX_HDRLEN) { 288c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 289c74ad251Schristos nd_trunc_longjmp(ndo); 2900f74e101Schristos } 2910f74e101Schristos 2920f74e101Schristos ap = (const struct arc_linux_header *)p; 293c74ad251Schristos arc_type = GET_U_1(ap->arc_type); 2940f74e101Schristos 2950f74e101Schristos switch (arc_type) { 2960f74e101Schristos default: 2970f74e101Schristos archdrlen = ARC_LINUX_HDRNEWLEN; 298c74ad251Schristos if (caplen < ARC_LINUX_HDRNEWLEN) { 299c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 300c74ad251Schristos nd_trunc_longjmp(ndo); 3010f74e101Schristos } 3020f74e101Schristos break; 3030f74e101Schristos case ARCTYPE_IP_OLD: 3040f74e101Schristos case ARCTYPE_ARP_OLD: 3050f74e101Schristos case ARCTYPE_DIAGNOSE: 3060f74e101Schristos archdrlen = ARC_LINUX_HDRLEN; 3070f74e101Schristos break; 3080f74e101Schristos } 3090f74e101Schristos 310b3a00663Schristos if (ndo->ndo_eflag) 311b3a00663Schristos arcnet_print(ndo, p, length, 0, 0, 0); 3120f74e101Schristos 3130f74e101Schristos /* 3140f74e101Schristos * Go past the ARCNET header. 3150f74e101Schristos */ 3160f74e101Schristos length -= archdrlen; 3170f74e101Schristos caplen -= archdrlen; 3180f74e101Schristos p += archdrlen; 3190f74e101Schristos 320b3a00663Schristos if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) 321b3a00663Schristos ND_DEFAULTPRINT(p, caplen); 3220f74e101Schristos 323c74ad251Schristos ndo->ndo_ll_hdr_len += archdrlen; 3240f74e101Schristos } 3250f74e101Schristos 3260f74e101Schristos /* 3270f74e101Schristos * Prints the packet encapsulated in an ARCnet data field, 3280f74e101Schristos * given the ARCnet system code. 3290f74e101Schristos * 3300f74e101Schristos * Returns non-zero if it can do so, zero if the system code is unknown. 3310f74e101Schristos */ 3320f74e101Schristos 3330f74e101Schristos 3340f74e101Schristos static int 335b3a00663Schristos arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p, 3360f74e101Schristos u_int length, u_int caplen) 3370f74e101Schristos { 3380f74e101Schristos switch (arctype) { 3390f74e101Schristos 3400f74e101Schristos case ARCTYPE_IP_OLD: 3410f74e101Schristos case ARCTYPE_IP: 342b3a00663Schristos ip_print(ndo, p, length); 3430f74e101Schristos return (1); 3440f74e101Schristos 3450f74e101Schristos case ARCTYPE_INET6: 346b3a00663Schristos ip6_print(ndo, p, length); 3470f74e101Schristos return (1); 3480f74e101Schristos 3490f74e101Schristos case ARCTYPE_ARP_OLD: 3500f74e101Schristos case ARCTYPE_ARP: 3510f74e101Schristos case ARCTYPE_REVARP: 352b3a00663Schristos arp_print(ndo, p, length, caplen); 3530f74e101Schristos return (1); 3540f74e101Schristos 3550f74e101Schristos case ARCTYPE_ATALK: /* XXX was this ever used? */ 356b3a00663Schristos if (ndo->ndo_vflag) 357c74ad251Schristos ND_PRINT("et1 "); 358b3a00663Schristos atalk_print(ndo, p, length); 3590f74e101Schristos return (1); 3600f74e101Schristos 3610f74e101Schristos case ARCTYPE_IPX: 362b3a00663Schristos ipx_print(ndo, p, length); 3630f74e101Schristos return (1); 3640f74e101Schristos 3650f74e101Schristos default: 3660f74e101Schristos return (0); 3670f74e101Schristos } 3680f74e101Schristos } 369