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