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