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