diff options
Diffstat (limited to '')
-rw-r--r-- | print-arcnet.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/print-arcnet.c b/print-arcnet.c new file mode 100644 index 0000000..5f6aaf9 --- /dev/null +++ b/print-arcnet.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * From: NetBSD: print-arcnet.c,v 1.2 2000/04/24 13:02:28 itojun Exp + */ + +/* \summary: Attached Resource Computer NETwork (ARCNET) printer */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "netdissect-stdinc.h" + +#include "netdissect.h" +#include "extract.h" + +/* + * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp + */ + +/* + * Structure of a 2.5MB/s Arcnet header on the BSDs, + * as given to interface code. + */ +struct arc_header { + nd_uint8_t arc_shost; + nd_uint8_t arc_dhost; + nd_uint8_t arc_type; + /* + * only present for newstyle encoding with LL fragmentation. + * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead. + */ + nd_uint8_t arc_flag; + nd_uint16_t arc_seqid; + + /* + * only present in exception packets (arc_flag == 0xff) + */ + nd_uint8_t arc_type2; /* same as arc_type */ + nd_uint8_t arc_flag2; /* real flag value */ + nd_uint16_t arc_seqid2; /* real seqid value */ +}; + +#define ARC_HDRLEN 3 +#define ARC_HDRNEWLEN 6 +#define ARC_HDRNEWLEN_EXC 10 + +/* RFC 1051 */ +#define ARCTYPE_IP_OLD 240 /* IP protocol */ +#define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ + +/* RFC 1201 */ +#define ARCTYPE_IP 212 /* IP protocol */ +#define ARCTYPE_ARP 213 /* address resolution protocol */ +#define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ + +#define ARCTYPE_ATALK 221 /* Appletalk */ +#define ARCTYPE_BANIAN 247 /* Banyan Vines */ +#define ARCTYPE_IPX 250 /* Novell IPX */ + +#define ARCTYPE_INET6 0xc4 /* IPng */ +#define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ + +/* + * Structure of a 2.5MB/s Arcnet header on Linux. Linux has + * an extra "offset" field when given to interface code, and + * never presents packets that look like exception frames. + */ +struct arc_linux_header { + nd_uint8_t arc_shost; + nd_uint8_t arc_dhost; + nd_uint16_t arc_offset; + nd_uint8_t arc_type; + /* + * only present for newstyle encoding with LL fragmentation. + * Don't use sizeof(anything), use ARC_LINUX_HDR{,NEW}LEN + * instead. + */ + nd_uint8_t arc_flag; + nd_uint16_t arc_seqid; +}; + +#define ARC_LINUX_HDRLEN 5 +#define ARC_LINUX_HDRNEWLEN 8 + +static int arcnet_encap_print(netdissect_options *, u_char arctype, const u_char *p, + u_int length, u_int caplen); + +static const struct tok arctypemap[] = { + { ARCTYPE_IP_OLD, "oldip" }, + { ARCTYPE_ARP_OLD, "oldarp" }, + { ARCTYPE_IP, "ip" }, + { ARCTYPE_ARP, "arp" }, + { ARCTYPE_REVARP, "rarp" }, + { ARCTYPE_ATALK, "atalk" }, + { ARCTYPE_BANIAN, "banyan" }, + { ARCTYPE_IPX, "ipx" }, + { ARCTYPE_INET6, "ipv6" }, + { ARCTYPE_DIAGNOSE, "diag" }, + { 0, NULL } +}; + +static void +arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds, + u_int flag, u_int seqid) +{ + const struct arc_header *ap; + const char *arctypename; + + ndo->ndo_protocol = "arcnet"; + ap = (const struct arc_header *)bp; + + if (ndo->ndo_qflag) { + ND_PRINT("%02x %02x %u: ", + GET_U_1(ap->arc_shost), + GET_U_1(ap->arc_dhost), + length); + return; + } + + arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type)); + + if (!phds) { + ND_PRINT("%02x %02x %s %u: ", + GET_U_1(ap->arc_shost), + GET_U_1(ap->arc_dhost), + arctypename, + length); + return; + } + + if (flag == 0) { + ND_PRINT("%02x %02x %s seqid %04x %u: ", + GET_U_1(ap->arc_shost), + GET_U_1(ap->arc_dhost), + arctypename, seqid, + length); + return; + } + + if (flag & 1) + ND_PRINT("%02x %02x %s seqid %04x " + "(first of %u fragments) %u: ", + GET_U_1(ap->arc_shost), + GET_U_1(ap->arc_dhost), + arctypename, seqid, + (flag + 3) / 2, length); + else + ND_PRINT("%02x %02x %s seqid %04x " + "(fragment %u) %u: ", + GET_U_1(ap->arc_shost), + GET_U_1(ap->arc_dhost), + arctypename, seqid, + flag/2 + 1, length); +} + +/* + * This is the top level routine of the printer. 'p' points + * to the ARCNET header of the packet, 'h->ts' is the timestamp, + * 'h->len' is the length of the packet off the wire, and 'h->caplen' + * is the number of bytes actually captured. + */ +void +arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) +{ + u_int caplen = h->caplen; + u_int length = h->len; + const struct arc_header *ap; + + int phds; + u_int flag = 0, archdrlen = 0; + u_int seqid = 0; + u_char arc_type; + + ndo->ndo_protocol = "arcnet"; + if (caplen < ARC_HDRLEN) { + ndo->ndo_ll_hdr_len += caplen; + nd_trunc_longjmp(ndo); + } + + ap = (const struct arc_header *)p; + arc_type = GET_U_1(ap->arc_type); + + switch (arc_type) { + default: + phds = 1; + break; + case ARCTYPE_IP_OLD: + case ARCTYPE_ARP_OLD: + case ARCTYPE_DIAGNOSE: + phds = 0; + archdrlen = ARC_HDRLEN; + break; + } + + if (phds) { + if (caplen < ARC_HDRNEWLEN) { + arcnet_print(ndo, p, length, 0, 0, 0); + ND_PRINT(" phds"); + ndo->ndo_ll_hdr_len += caplen; + nd_trunc_longjmp(ndo); + } + + flag = GET_U_1(ap->arc_flag); + if (flag == 0xff) { + if (caplen < ARC_HDRNEWLEN_EXC) { + arcnet_print(ndo, p, length, 0, 0, 0); + ND_PRINT(" phds extended"); + ndo->ndo_ll_hdr_len += caplen; + nd_trunc_longjmp(ndo); + } + flag = GET_U_1(ap->arc_flag2); + seqid = GET_BE_U_2(ap->arc_seqid2); + archdrlen = ARC_HDRNEWLEN_EXC; + } else { + seqid = GET_BE_U_2(ap->arc_seqid); + archdrlen = ARC_HDRNEWLEN; + } + } + + + if (ndo->ndo_eflag) + arcnet_print(ndo, p, length, phds, flag, seqid); + + /* + * Go past the ARCNET header. + */ + length -= archdrlen; + caplen -= archdrlen; + p += archdrlen; + + if (phds && flag && (flag & 1) == 0) { + /* + * This is a middle fragment. + */ + ndo->ndo_ll_hdr_len += archdrlen; + return; + } + + if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) + ND_DEFAULTPRINT(p, caplen); + + ndo->ndo_ll_hdr_len += archdrlen; +} + +/* + * This is the top level routine of the printer. 'p' points + * to the ARCNET header of the packet, 'h->ts' is the timestamp, + * 'h->len' is the length of the packet off the wire, and 'h->caplen' + * is the number of bytes actually captured. It is quite similar + * to the non-Linux style printer except that Linux doesn't ever + * supply packets that look like exception frames, it always supplies + * reassembled packets rather than raw frames, and headers have an + * extra "offset" field between the src/dest and packet type. + */ +void +arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) +{ + u_int caplen = h->caplen; + u_int length = h->len; + const struct arc_linux_header *ap; + + int archdrlen = 0; + u_char arc_type; + + ndo->ndo_protocol = "arcnet_linux"; + if (caplen < ARC_LINUX_HDRLEN) { + ndo->ndo_ll_hdr_len += caplen; + nd_trunc_longjmp(ndo); + } + + ap = (const struct arc_linux_header *)p; + arc_type = GET_U_1(ap->arc_type); + + switch (arc_type) { + default: + archdrlen = ARC_LINUX_HDRNEWLEN; + if (caplen < ARC_LINUX_HDRNEWLEN) { + ndo->ndo_ll_hdr_len += caplen; + nd_trunc_longjmp(ndo); + } + break; + case ARCTYPE_IP_OLD: + case ARCTYPE_ARP_OLD: + case ARCTYPE_DIAGNOSE: + archdrlen = ARC_LINUX_HDRLEN; + break; + } + + if (ndo->ndo_eflag) + arcnet_print(ndo, p, length, 0, 0, 0); + + /* + * Go past the ARCNET header. + */ + length -= archdrlen; + caplen -= archdrlen; + p += archdrlen; + + if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) + ND_DEFAULTPRINT(p, caplen); + + ndo->ndo_ll_hdr_len += archdrlen; +} + +/* + * Prints the packet encapsulated in an ARCnet data field, + * given the ARCnet system code. + * + * Returns non-zero if it can do so, zero if the system code is unknown. + */ + + +static int +arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p, + u_int length, u_int caplen) +{ + switch (arctype) { + + case ARCTYPE_IP_OLD: + case ARCTYPE_IP: + ip_print(ndo, p, length); + return (1); + + case ARCTYPE_INET6: + ip6_print(ndo, p, length); + return (1); + + case ARCTYPE_ARP_OLD: + case ARCTYPE_ARP: + case ARCTYPE_REVARP: + arp_print(ndo, p, length, caplen); + return (1); + + case ARCTYPE_ATALK: /* XXX was this ever used? */ + if (ndo->ndo_vflag) + ND_PRINT("et1 "); + atalk_print(ndo, p, length); + return (1); + + case ARCTYPE_IPX: + ipx_print(ndo, p, length); + return (1); + + default: + return (0); + } +} |