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 22 /* \summary: AppleTalk printer */ 23 24 #include <sys/cdefs.h> 25 #ifndef lint 26 __RCSID("$NetBSD: print-atalk.c,v 1.7 2017/02/05 04:05:05 spz Exp $"); 27 #endif 28 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #include <netdissect-stdinc.h> 34 35 #include <stdio.h> 36 #include <string.h> 37 38 #include "netdissect.h" 39 #include "addrtoname.h" 40 #include "ethertype.h" 41 #include "extract.h" 42 #include "appletalk.h" 43 44 static const char tstr[] = "[|atalk]"; 45 46 static const struct tok type2str[] = { 47 { ddpRTMP, "rtmp" }, 48 { ddpRTMPrequest, "rtmpReq" }, 49 { ddpECHO, "echo" }, 50 { ddpIP, "IP" }, 51 { ddpARP, "ARP" }, 52 { ddpKLAP, "KLAP" }, 53 { 0, NULL } 54 }; 55 56 struct aarp { 57 uint16_t htype, ptype; 58 uint8_t halen, palen; 59 uint16_t op; 60 uint8_t hsaddr[6]; 61 uint8_t psaddr[4]; 62 uint8_t hdaddr[6]; 63 uint8_t pdaddr[4]; 64 }; 65 66 static void atp_print(netdissect_options *, const struct atATP *, u_int); 67 static void atp_bitmap_print(netdissect_options *, u_char); 68 static void nbp_print(netdissect_options *, const struct atNBP *, u_int, u_short, u_char, u_char); 69 static const struct atNBPtuple *nbp_tuple_print(netdissect_options *ndo, const struct atNBPtuple *, 70 const u_char *, 71 u_short, u_char, u_char); 72 static const struct atNBPtuple *nbp_name_print(netdissect_options *, const struct atNBPtuple *, 73 const u_char *); 74 static const char *ataddr_string(netdissect_options *, u_short, u_char); 75 static void ddp_print(netdissect_options *, const u_char *, u_int, int, u_short, u_char, u_char); 76 static const char *ddpskt_string(netdissect_options *, int); 77 78 /* 79 * Print LLAP packets received on a physical LocalTalk interface. 80 */ 81 u_int 82 ltalk_if_print(netdissect_options *ndo, 83 const struct pcap_pkthdr *h, const u_char *p) 84 { 85 u_int hdrlen; 86 87 hdrlen = llap_print(ndo, p, h->len); 88 if (hdrlen == 0) { 89 /* Cut short by the snapshot length. */ 90 return (h->caplen); 91 } 92 return (hdrlen); 93 } 94 95 /* 96 * Print AppleTalk LLAP packets. 97 */ 98 u_int 99 llap_print(netdissect_options *ndo, 100 register const u_char *bp, u_int length) 101 { 102 register const struct LAP *lp; 103 register const struct atDDP *dp; 104 register const struct atShortDDP *sdp; 105 u_short snet; 106 u_int hdrlen; 107 108 if (length < sizeof(*lp)) { 109 ND_PRINT((ndo, " [|llap %u]", length)); 110 return (length); 111 } 112 if (!ND_TTEST2(*bp, sizeof(*lp))) { 113 ND_PRINT((ndo, " [|llap]")); 114 return (0); /* cut short by the snapshot length */ 115 } 116 lp = (const struct LAP *)bp; 117 bp += sizeof(*lp); 118 length -= sizeof(*lp); 119 hdrlen = sizeof(*lp); 120 switch (lp->type) { 121 122 case lapShortDDP: 123 if (length < ddpSSize) { 124 ND_PRINT((ndo, " [|sddp %u]", length)); 125 return (length); 126 } 127 if (!ND_TTEST2(*bp, ddpSSize)) { 128 ND_PRINT((ndo, " [|sddp]")); 129 return (0); /* cut short by the snapshot length */ 130 } 131 sdp = (const struct atShortDDP *)bp; 132 ND_PRINT((ndo, "%s.%s", 133 ataddr_string(ndo, 0, lp->src), ddpskt_string(ndo, sdp->srcSkt))); 134 ND_PRINT((ndo, " > %s.%s:", 135 ataddr_string(ndo, 0, lp->dst), ddpskt_string(ndo, sdp->dstSkt))); 136 bp += ddpSSize; 137 length -= ddpSSize; 138 hdrlen += ddpSSize; 139 ddp_print(ndo, bp, length, sdp->type, 0, lp->src, sdp->srcSkt); 140 break; 141 142 case lapDDP: 143 if (length < ddpSize) { 144 ND_PRINT((ndo, " [|ddp %u]", length)); 145 return (length); 146 } 147 if (!ND_TTEST2(*bp, ddpSize)) { 148 ND_PRINT((ndo, " [|ddp]")); 149 return (0); /* cut short by the snapshot length */ 150 } 151 dp = (const struct atDDP *)bp; 152 snet = EXTRACT_16BITS(&dp->srcNet); 153 ND_PRINT((ndo, "%s.%s", ataddr_string(ndo, snet, dp->srcNode), 154 ddpskt_string(ndo, dp->srcSkt))); 155 ND_PRINT((ndo, " > %s.%s:", 156 ataddr_string(ndo, EXTRACT_16BITS(&dp->dstNet), dp->dstNode), 157 ddpskt_string(ndo, dp->dstSkt))); 158 bp += ddpSize; 159 length -= ddpSize; 160 hdrlen += ddpSize; 161 ddp_print(ndo, bp, length, dp->type, snet, dp->srcNode, dp->srcSkt); 162 break; 163 164 #ifdef notdef 165 case lapKLAP: 166 klap_print(bp, length); 167 break; 168 #endif 169 170 default: 171 ND_PRINT((ndo, "%d > %d at-lap#%d %u", 172 lp->src, lp->dst, lp->type, length)); 173 break; 174 } 175 return (hdrlen); 176 } 177 178 /* 179 * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called 180 * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk 181 * packets in them). 182 */ 183 void 184 atalk_print(netdissect_options *ndo, 185 register const u_char *bp, u_int length) 186 { 187 register const struct atDDP *dp; 188 u_short snet; 189 190 if(!ndo->ndo_eflag) 191 ND_PRINT((ndo, "AT ")); 192 193 if (length < ddpSize) { 194 ND_PRINT((ndo, " [|ddp %u]", length)); 195 return; 196 } 197 if (!ND_TTEST2(*bp, ddpSize)) { 198 ND_PRINT((ndo, " [|ddp]")); 199 return; 200 } 201 dp = (const struct atDDP *)bp; 202 snet = EXTRACT_16BITS(&dp->srcNet); 203 ND_PRINT((ndo, "%s.%s", ataddr_string(ndo, snet, dp->srcNode), 204 ddpskt_string(ndo, dp->srcSkt))); 205 ND_PRINT((ndo, " > %s.%s: ", 206 ataddr_string(ndo, EXTRACT_16BITS(&dp->dstNet), dp->dstNode), 207 ddpskt_string(ndo, dp->dstSkt))); 208 bp += ddpSize; 209 length -= ddpSize; 210 ddp_print(ndo, bp, length, dp->type, snet, dp->srcNode, dp->srcSkt); 211 } 212 213 /* XXX should probably pass in the snap header and do checks like arp_print() */ 214 void 215 aarp_print(netdissect_options *ndo, 216 register const u_char *bp, u_int length) 217 { 218 register const struct aarp *ap; 219 220 #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) 221 222 ND_PRINT((ndo, "aarp ")); 223 ap = (const struct aarp *)bp; 224 if (!ND_TTEST(*ap)) { 225 /* Just bail if we don't have the whole chunk. */ 226 ND_PRINT((ndo, " [|aarp]")); 227 return; 228 } 229 if (length < sizeof(*ap)) { 230 ND_PRINT((ndo, " [|aarp %u]", length)); 231 return; 232 } 233 if (EXTRACT_16BITS(&ap->htype) == 1 && 234 EXTRACT_16BITS(&ap->ptype) == ETHERTYPE_ATALK && 235 ap->halen == 6 && ap->palen == 4 ) 236 switch (EXTRACT_16BITS(&ap->op)) { 237 238 case 1: /* request */ 239 ND_PRINT((ndo, "who-has %s tell %s", AT(pdaddr), AT(psaddr))); 240 return; 241 242 case 2: /* response */ 243 ND_PRINT((ndo, "reply %s is-at %s", AT(psaddr), etheraddr_string(ndo, ap->hsaddr))); 244 return; 245 246 case 3: /* probe (oy!) */ 247 ND_PRINT((ndo, "probe %s tell %s", AT(pdaddr), AT(psaddr))); 248 return; 249 } 250 ND_PRINT((ndo, "len %u op %u htype %u ptype %#x halen %u palen %u", 251 length, EXTRACT_16BITS(&ap->op), EXTRACT_16BITS(&ap->htype), 252 EXTRACT_16BITS(&ap->ptype), ap->halen, ap->palen)); 253 } 254 255 /* 256 * Print AppleTalk Datagram Delivery Protocol packets. 257 */ 258 static void 259 ddp_print(netdissect_options *ndo, 260 register const u_char *bp, register u_int length, register int t, 261 register u_short snet, register u_char snode, u_char skt) 262 { 263 264 switch (t) { 265 266 case ddpNBP: 267 nbp_print(ndo, (const struct atNBP *)bp, length, snet, snode, skt); 268 break; 269 270 case ddpATP: 271 atp_print(ndo, (const struct atATP *)bp, length); 272 break; 273 274 case ddpEIGRP: 275 eigrp_print(ndo, bp, length); 276 break; 277 278 default: 279 ND_PRINT((ndo, " at-%s %d", tok2str(type2str, NULL, t), length)); 280 break; 281 } 282 } 283 284 static void 285 atp_print(netdissect_options *ndo, 286 register const struct atATP *ap, u_int length) 287 { 288 char c; 289 uint32_t data; 290 291 if ((const u_char *)(ap + 1) > ndo->ndo_snapend) { 292 /* Just bail if we don't have the whole chunk. */ 293 ND_PRINT((ndo, "%s", tstr)); 294 return; 295 } 296 if (length < sizeof(*ap)) { 297 ND_PRINT((ndo, " [|atp %u]", length)); 298 return; 299 } 300 length -= sizeof(*ap); 301 switch (ap->control & 0xc0) { 302 303 case atpReqCode: 304 ND_PRINT((ndo, " atp-req%s %d", 305 ap->control & atpXO? " " : "*", 306 EXTRACT_16BITS(&ap->transID))); 307 308 atp_bitmap_print(ndo, ap->bitmap); 309 310 if (length != 0) 311 ND_PRINT((ndo, " [len=%u]", length)); 312 313 switch (ap->control & (atpEOM|atpSTS)) { 314 case atpEOM: 315 ND_PRINT((ndo, " [EOM]")); 316 break; 317 case atpSTS: 318 ND_PRINT((ndo, " [STS]")); 319 break; 320 case atpEOM|atpSTS: 321 ND_PRINT((ndo, " [EOM,STS]")); 322 break; 323 } 324 break; 325 326 case atpRspCode: 327 ND_PRINT((ndo, " atp-resp%s%d:%d (%u)", 328 ap->control & atpEOM? "*" : " ", 329 EXTRACT_16BITS(&ap->transID), ap->bitmap, length)); 330 switch (ap->control & (atpXO|atpSTS)) { 331 case atpXO: 332 ND_PRINT((ndo, " [XO]")); 333 break; 334 case atpSTS: 335 ND_PRINT((ndo, " [STS]")); 336 break; 337 case atpXO|atpSTS: 338 ND_PRINT((ndo, " [XO,STS]")); 339 break; 340 } 341 break; 342 343 case atpRelCode: 344 ND_PRINT((ndo, " atp-rel %d", EXTRACT_16BITS(&ap->transID))); 345 346 atp_bitmap_print(ndo, ap->bitmap); 347 348 /* length should be zero */ 349 if (length) 350 ND_PRINT((ndo, " [len=%u]", length)); 351 352 /* there shouldn't be any control flags */ 353 if (ap->control & (atpXO|atpEOM|atpSTS)) { 354 c = '['; 355 if (ap->control & atpXO) { 356 ND_PRINT((ndo, "%cXO", c)); 357 c = ','; 358 } 359 if (ap->control & atpEOM) { 360 ND_PRINT((ndo, "%cEOM", c)); 361 c = ','; 362 } 363 if (ap->control & atpSTS) { 364 ND_PRINT((ndo, "%cSTS", c)); 365 c = ','; 366 } 367 ND_PRINT((ndo, "]")); 368 } 369 break; 370 371 default: 372 ND_PRINT((ndo, " atp-0x%x %d (%u)", ap->control, 373 EXTRACT_16BITS(&ap->transID), length)); 374 break; 375 } 376 data = EXTRACT_32BITS(&ap->userData); 377 if (data != 0) 378 ND_PRINT((ndo, " 0x%x", data)); 379 } 380 381 static void 382 atp_bitmap_print(netdissect_options *ndo, 383 register u_char bm) 384 { 385 register char c; 386 register int i; 387 388 /* 389 * The '& 0xff' below is needed for compilers that want to sign 390 * extend a u_char, which is the case with the Ultrix compiler. 391 * (gcc is smart enough to eliminate it, at least on the Sparc). 392 */ 393 if ((bm + 1) & (bm & 0xff)) { 394 c = '<'; 395 for (i = 0; bm; ++i) { 396 if (bm & 1) { 397 ND_PRINT((ndo, "%c%d", c, i)); 398 c = ','; 399 } 400 bm >>= 1; 401 } 402 ND_PRINT((ndo, ">")); 403 } else { 404 for (i = 0; bm; ++i) 405 bm >>= 1; 406 if (i > 1) 407 ND_PRINT((ndo, "<0-%d>", i - 1)); 408 else 409 ND_PRINT((ndo, "<0>")); 410 } 411 } 412 413 static void 414 nbp_print(netdissect_options *ndo, 415 register const struct atNBP *np, u_int length, register u_short snet, 416 register u_char snode, register u_char skt) 417 { 418 register const struct atNBPtuple *tp = 419 (const struct atNBPtuple *)((const u_char *)np + nbpHeaderSize); 420 int i; 421 const u_char *ep; 422 423 if (length < nbpHeaderSize) { 424 ND_PRINT((ndo, " truncated-nbp %u", length)); 425 return; 426 } 427 428 length -= nbpHeaderSize; 429 if (length < 8) { 430 /* must be room for at least one tuple */ 431 ND_PRINT((ndo, " truncated-nbp %u", length + nbpHeaderSize)); 432 return; 433 } 434 /* ep points to end of available data */ 435 ep = ndo->ndo_snapend; 436 if ((const u_char *)tp > ep) { 437 ND_PRINT((ndo, "%s", tstr)); 438 return; 439 } 440 switch (i = np->control & 0xf0) { 441 442 case nbpBrRq: 443 case nbpLkUp: 444 ND_PRINT((ndo, i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:", np->id)); 445 if ((const u_char *)(tp + 1) > ep) { 446 ND_PRINT((ndo, "%s", tstr)); 447 return; 448 } 449 (void)nbp_name_print(ndo, tp, ep); 450 /* 451 * look for anomalies: the spec says there can only 452 * be one tuple, the address must match the source 453 * address and the enumerator should be zero. 454 */ 455 if ((np->control & 0xf) != 1) 456 ND_PRINT((ndo, " [ntup=%d]", np->control & 0xf)); 457 if (tp->enumerator) 458 ND_PRINT((ndo, " [enum=%d]", tp->enumerator)); 459 if (EXTRACT_16BITS(&tp->net) != snet || 460 tp->node != snode || tp->skt != skt) 461 ND_PRINT((ndo, " [addr=%s.%d]", 462 ataddr_string(ndo, EXTRACT_16BITS(&tp->net), 463 tp->node), tp->skt)); 464 break; 465 466 case nbpLkUpReply: 467 ND_PRINT((ndo, " nbp-reply %d:", np->id)); 468 469 /* print each of the tuples in the reply */ 470 for (i = np->control & 0xf; --i >= 0 && tp; ) 471 tp = nbp_tuple_print(ndo, tp, ep, snet, snode, skt); 472 break; 473 474 default: 475 ND_PRINT((ndo, " nbp-0x%x %d (%u)", np->control, np->id, length)); 476 break; 477 } 478 } 479 480 /* print a counted string */ 481 static const char * 482 print_cstring(netdissect_options *ndo, 483 register const char *cp, register const u_char *ep) 484 { 485 register u_int length; 486 487 if (cp >= (const char *)ep) { 488 ND_PRINT((ndo, "%s", tstr)); 489 return (0); 490 } 491 length = *cp++; 492 493 /* Spec says string can be at most 32 bytes long */ 494 if (length > 32) { 495 ND_PRINT((ndo, "[len=%u]", length)); 496 return (0); 497 } 498 while ((int)--length >= 0) { 499 if (cp >= (const char *)ep) { 500 ND_PRINT((ndo, "%s", tstr)); 501 return (0); 502 } 503 ND_PRINT((ndo, "%c", *cp++)); 504 } 505 return (cp); 506 } 507 508 static const struct atNBPtuple * 509 nbp_tuple_print(netdissect_options *ndo, 510 register const struct atNBPtuple *tp, register const u_char *ep, 511 register u_short snet, register u_char snode, register u_char skt) 512 { 513 register const struct atNBPtuple *tpn; 514 515 if ((const u_char *)(tp + 1) > ep) { 516 ND_PRINT((ndo, "%s", tstr)); 517 return 0; 518 } 519 tpn = nbp_name_print(ndo, tp, ep); 520 521 /* if the enumerator isn't 1, print it */ 522 if (tp->enumerator != 1) 523 ND_PRINT((ndo, "(%d)", tp->enumerator)); 524 525 /* if the socket doesn't match the src socket, print it */ 526 if (tp->skt != skt) 527 ND_PRINT((ndo, " %d", tp->skt)); 528 529 /* if the address doesn't match the src address, it's an anomaly */ 530 if (EXTRACT_16BITS(&tp->net) != snet || tp->node != snode) 531 ND_PRINT((ndo, " [addr=%s]", 532 ataddr_string(ndo, EXTRACT_16BITS(&tp->net), tp->node))); 533 534 return (tpn); 535 } 536 537 static const struct atNBPtuple * 538 nbp_name_print(netdissect_options *ndo, 539 const struct atNBPtuple *tp, register const u_char *ep) 540 { 541 register const char *cp = (const char *)tp + nbpTupleSize; 542 543 ND_PRINT((ndo, " ")); 544 545 /* Object */ 546 ND_PRINT((ndo, "\"")); 547 if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 548 /* Type */ 549 ND_PRINT((ndo, ":")); 550 if ((cp = print_cstring(ndo, cp, ep)) != NULL) { 551 /* Zone */ 552 ND_PRINT((ndo, "@")); 553 if ((cp = print_cstring(ndo, cp, ep)) != NULL) 554 ND_PRINT((ndo, "\"")); 555 } 556 } 557 return ((const struct atNBPtuple *)cp); 558 } 559 560 561 #define HASHNAMESIZE 4096 562 563 struct hnamemem { 564 int addr; 565 char *name; 566 struct hnamemem *nxt; 567 }; 568 569 static struct hnamemem hnametable[HASHNAMESIZE]; 570 571 static const char * 572 ataddr_string(netdissect_options *ndo, 573 u_short atnet, u_char athost) 574 { 575 register struct hnamemem *tp, *tp2; 576 register int i = (atnet << 8) | athost; 577 char nambuf[256+1]; 578 static int first = 1; 579 FILE *fp; 580 581 /* 582 * if this is the first call, see if there's an AppleTalk 583 * number to name map file. 584 */ 585 if (first && (first = 0, !ndo->ndo_nflag) 586 && (fp = fopen("/etc/atalk.names", "r"))) { 587 char line[256]; 588 int i1, i2; 589 590 while (fgets(line, sizeof(line), fp)) { 591 if (line[0] == '\n' || line[0] == 0 || line[0] == '#') 592 continue; 593 if (sscanf(line, "%d.%d %256s", &i1, &i2, nambuf) == 3) 594 /* got a hostname. */ 595 i2 |= (i1 << 8); 596 else if (sscanf(line, "%d %256s", &i1, nambuf) == 2) 597 /* got a net name */ 598 i2 = (i1 << 8) | 255; 599 else 600 continue; 601 602 for (tp = &hnametable[i2 & (HASHNAMESIZE-1)]; 603 tp->nxt; tp = tp->nxt) 604 ; 605 tp->addr = i2; 606 tp->nxt = newhnamemem(ndo); 607 tp->name = strdup(nambuf); 608 if (tp->name == NULL) 609 (*ndo->ndo_error)(ndo, 610 "ataddr_string: strdup(nambuf)"); 611 } 612 fclose(fp); 613 } 614 615 for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) 616 if (tp->addr == i) 617 return (tp->name); 618 619 /* didn't have the node name -- see if we've got the net name */ 620 i |= 255; 621 for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt) 622 if (tp2->addr == i) { 623 tp->addr = (atnet << 8) | athost; 624 tp->nxt = newhnamemem(ndo); 625 (void)snprintf(nambuf, sizeof(nambuf), "%s.%d", 626 tp2->name, athost); 627 tp->name = strdup(nambuf); 628 if (tp->name == NULL) 629 (*ndo->ndo_error)(ndo, 630 "ataddr_string: strdup(nambuf)"); 631 return (tp->name); 632 } 633 634 tp->addr = (atnet << 8) | athost; 635 tp->nxt = newhnamemem(ndo); 636 if (athost != 255) 637 (void)snprintf(nambuf, sizeof(nambuf), "%d.%d", atnet, athost); 638 else 639 (void)snprintf(nambuf, sizeof(nambuf), "%d", atnet); 640 tp->name = strdup(nambuf); 641 if (tp->name == NULL) 642 (*ndo->ndo_error)(ndo, "ataddr_string: strdup(nambuf)"); 643 644 return (tp->name); 645 } 646 647 static const struct tok skt2str[] = { 648 { rtmpSkt, "rtmp" }, /* routing table maintenance */ 649 { nbpSkt, "nis" }, /* name info socket */ 650 { echoSkt, "echo" }, /* AppleTalk echo protocol */ 651 { zipSkt, "zip" }, /* zone info protocol */ 652 { 0, NULL } 653 }; 654 655 static const char * 656 ddpskt_string(netdissect_options *ndo, 657 register int skt) 658 { 659 static char buf[8]; 660 661 if (ndo->ndo_nflag) { 662 (void)snprintf(buf, sizeof(buf), "%d", skt); 663 return (buf); 664 } 665 return (tok2str(skt2str, "%d", skt)); 666 } 667