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 nd_uint8_t arc_shost; 45 nd_uint8_t arc_dhost; 46 nd_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 nd_uint8_t arc_flag; 52 nd_uint16_t arc_seqid; 53 54 /* 55 * only present in exception packets (arc_flag == 0xff) 56 */ 57 nd_uint8_t arc_type2; /* same as arc_type */ 58 nd_uint8_t arc_flag2; /* real flag value */ 59 nd_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 nd_uint8_t arc_shost; 89 nd_uint8_t arc_dhost; 90 nd_uint16_t arc_offset; 91 nd_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 nd_uint8_t arc_flag; 98 nd_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, NULL } 119 }; 120 121 static void 122 arcnet_print(netdissect_options *ndo, const u_char *bp, u_int length, int phds, 123 u_int flag, u_int seqid) 124 { 125 const struct arc_header *ap; 126 const char *arctypename; 127 128 ndo->ndo_protocol = "arcnet"; 129 ap = (const struct arc_header *)bp; 130 131 if (ndo->ndo_qflag) { 132 ND_PRINT("%02x %02x %u: ", 133 GET_U_1(ap->arc_shost), 134 GET_U_1(ap->arc_dhost), 135 length); 136 return; 137 } 138 139 arctypename = tok2str(arctypemap, "%02x", GET_U_1(ap->arc_type)); 140 141 if (!phds) { 142 ND_PRINT("%02x %02x %s %u: ", 143 GET_U_1(ap->arc_shost), 144 GET_U_1(ap->arc_dhost), 145 arctypename, 146 length); 147 return; 148 } 149 150 if (flag == 0) { 151 ND_PRINT("%02x %02x %s seqid %04x %u: ", 152 GET_U_1(ap->arc_shost), 153 GET_U_1(ap->arc_dhost), 154 arctypename, seqid, 155 length); 156 return; 157 } 158 159 if (flag & 1) 160 ND_PRINT("%02x %02x %s seqid %04x " 161 "(first of %u fragments) %u: ", 162 GET_U_1(ap->arc_shost), 163 GET_U_1(ap->arc_dhost), 164 arctypename, seqid, 165 (flag + 3) / 2, length); 166 else 167 ND_PRINT("%02x %02x %s seqid %04x " 168 "(fragment %u) %u: ", 169 GET_U_1(ap->arc_shost), 170 GET_U_1(ap->arc_dhost), 171 arctypename, seqid, 172 flag/2 + 1, length); 173 } 174 175 /* 176 * This is the top level routine of the printer. 'p' points 177 * to the ARCNET header of the packet, 'h->ts' is the timestamp, 178 * 'h->len' is the length of the packet off the wire, and 'h->caplen' 179 * is the number of bytes actually captured. 180 */ 181 void 182 arcnet_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) 183 { 184 u_int caplen = h->caplen; 185 u_int length = h->len; 186 const struct arc_header *ap; 187 188 int phds; 189 u_int flag = 0, archdrlen = 0; 190 u_int seqid = 0; 191 u_char arc_type; 192 193 ndo->ndo_protocol = "arcnet"; 194 if (caplen < ARC_HDRLEN) { 195 ndo->ndo_ll_hdr_len += caplen; 196 nd_trunc_longjmp(ndo); 197 } 198 199 ap = (const struct arc_header *)p; 200 arc_type = GET_U_1(ap->arc_type); 201 202 switch (arc_type) { 203 default: 204 phds = 1; 205 break; 206 case ARCTYPE_IP_OLD: 207 case ARCTYPE_ARP_OLD: 208 case ARCTYPE_DIAGNOSE: 209 phds = 0; 210 archdrlen = ARC_HDRLEN; 211 break; 212 } 213 214 if (phds) { 215 if (caplen < ARC_HDRNEWLEN) { 216 arcnet_print(ndo, p, length, 0, 0, 0); 217 ND_PRINT(" phds"); 218 ndo->ndo_ll_hdr_len += caplen; 219 nd_trunc_longjmp(ndo); 220 } 221 222 flag = GET_U_1(ap->arc_flag); 223 if (flag == 0xff) { 224 if (caplen < ARC_HDRNEWLEN_EXC) { 225 arcnet_print(ndo, p, length, 0, 0, 0); 226 ND_PRINT(" phds extended"); 227 ndo->ndo_ll_hdr_len += caplen; 228 nd_trunc_longjmp(ndo); 229 } 230 flag = GET_U_1(ap->arc_flag2); 231 seqid = GET_BE_U_2(ap->arc_seqid2); 232 archdrlen = ARC_HDRNEWLEN_EXC; 233 } else { 234 seqid = GET_BE_U_2(ap->arc_seqid); 235 archdrlen = ARC_HDRNEWLEN; 236 } 237 } 238 239 240 if (ndo->ndo_eflag) 241 arcnet_print(ndo, p, length, phds, flag, seqid); 242 243 /* 244 * Go past the ARCNET header. 245 */ 246 length -= archdrlen; 247 caplen -= archdrlen; 248 p += archdrlen; 249 250 if (phds && flag && (flag & 1) == 0) { 251 /* 252 * This is a middle fragment. 253 */ 254 ndo->ndo_ll_hdr_len += archdrlen; 255 return; 256 } 257 258 if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) 259 ND_DEFAULTPRINT(p, caplen); 260 261 ndo->ndo_ll_hdr_len += archdrlen; 262 } 263 264 /* 265 * This is the top level routine of the printer. 'p' points 266 * to the ARCNET header of the packet, 'h->ts' is the timestamp, 267 * 'h->len' is the length of the packet off the wire, and 'h->caplen' 268 * is the number of bytes actually captured. It is quite similar 269 * to the non-Linux style printer except that Linux doesn't ever 270 * supply packets that look like exception frames, it always supplies 271 * reassembled packets rather than raw frames, and headers have an 272 * extra "offset" field between the src/dest and packet type. 273 */ 274 void 275 arcnet_linux_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) 276 { 277 u_int caplen = h->caplen; 278 u_int length = h->len; 279 const struct arc_linux_header *ap; 280 281 int archdrlen = 0; 282 u_char arc_type; 283 284 ndo->ndo_protocol = "arcnet_linux"; 285 if (caplen < ARC_LINUX_HDRLEN) { 286 ndo->ndo_ll_hdr_len += caplen; 287 nd_trunc_longjmp(ndo); 288 } 289 290 ap = (const struct arc_linux_header *)p; 291 arc_type = GET_U_1(ap->arc_type); 292 293 switch (arc_type) { 294 default: 295 archdrlen = ARC_LINUX_HDRNEWLEN; 296 if (caplen < ARC_LINUX_HDRNEWLEN) { 297 ndo->ndo_ll_hdr_len += caplen; 298 nd_trunc_longjmp(ndo); 299 } 300 break; 301 case ARCTYPE_IP_OLD: 302 case ARCTYPE_ARP_OLD: 303 case ARCTYPE_DIAGNOSE: 304 archdrlen = ARC_LINUX_HDRLEN; 305 break; 306 } 307 308 if (ndo->ndo_eflag) 309 arcnet_print(ndo, p, length, 0, 0, 0); 310 311 /* 312 * Go past the ARCNET header. 313 */ 314 length -= archdrlen; 315 caplen -= archdrlen; 316 p += archdrlen; 317 318 if (!arcnet_encap_print(ndo, arc_type, p, length, caplen)) 319 ND_DEFAULTPRINT(p, caplen); 320 321 ndo->ndo_ll_hdr_len += archdrlen; 322 } 323 324 /* 325 * Prints the packet encapsulated in an ARCnet data field, 326 * given the ARCnet system code. 327 * 328 * Returns non-zero if it can do so, zero if the system code is unknown. 329 */ 330 331 332 static int 333 arcnet_encap_print(netdissect_options *ndo, u_char arctype, const u_char *p, 334 u_int length, u_int caplen) 335 { 336 switch (arctype) { 337 338 case ARCTYPE_IP_OLD: 339 case ARCTYPE_IP: 340 ip_print(ndo, p, length); 341 return (1); 342 343 case ARCTYPE_INET6: 344 ip6_print(ndo, p, length); 345 return (1); 346 347 case ARCTYPE_ARP_OLD: 348 case ARCTYPE_ARP: 349 case ARCTYPE_REVARP: 350 arp_print(ndo, p, length, caplen); 351 return (1); 352 353 case ARCTYPE_ATALK: /* XXX was this ever used? */ 354 if (ndo->ndo_vflag) 355 ND_PRINT("et1 "); 356 atalk_print(ndo, p, length); 357 return (1); 358 359 case ARCTYPE_IPX: 360 ipx_print(ndo, p, length); 361 return (1); 362 363 default: 364 return (0); 365 } 366 } 367