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