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