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