xref: /netbsd-src/external/bsd/tcpdump/dist/print-atalk.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  */
210f74e101Schristos 
22dc860a36Sspz /* \summary: AppleTalk printer */
23dc860a36Sspz 
2411b3aaa1Schristos #include <sys/cdefs.h>
250f74e101Schristos #ifndef lint
26*26ba0b50Schristos __RCSID("$NetBSD: print-atalk.c,v 1.9 2024/09/02 16:15:30 christos Exp $");
270f74e101Schristos #endif
280f74e101Schristos 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
330f74e101Schristos #include <stdio.h>
340f74e101Schristos #include <string.h>
350f74e101Schristos 
36fdccd7e4Schristos #include "netdissect.h"
370f74e101Schristos #include "addrtoname.h"
380f74e101Schristos #include "ethertype.h"
39fdccd7e4Schristos #include "extract.h"
400f74e101Schristos #include "appletalk.h"
410f74e101Schristos 
42b3a00663Schristos 
43870189d2Schristos static const struct tok type2str[] = {
440f74e101Schristos 	{ ddpRTMP,		"rtmp" },
450f74e101Schristos 	{ ddpRTMPrequest,	"rtmpReq" },
460f74e101Schristos 	{ ddpECHO,		"echo" },
470f74e101Schristos 	{ ddpIP,		"IP" },
480f74e101Schristos 	{ ddpARP,		"ARP" },
490f74e101Schristos 	{ ddpKLAP,		"KLAP" },
500f74e101Schristos 	{ 0,			NULL }
510f74e101Schristos };
520f74e101Schristos 
530f74e101Schristos struct aarp {
54c74ad251Schristos 	nd_uint16_t	htype, ptype;
55c74ad251Schristos 	nd_uint8_t	halen, palen;
56c74ad251Schristos 	nd_uint16_t	op;
57c74ad251Schristos 	nd_mac_addr	hsaddr;
58b3a00663Schristos 	uint8_t		psaddr[4];
59c74ad251Schristos 	nd_mac_addr	hdaddr;
60b3a00663Schristos 	uint8_t		pdaddr[4];
610f74e101Schristos };
620f74e101Schristos 
63b3a00663Schristos static void atp_print(netdissect_options *, const struct atATP *, u_int);
64b3a00663Schristos static void atp_bitmap_print(netdissect_options *, u_char);
65b3a00663Schristos static void nbp_print(netdissect_options *, const struct atNBP *, u_int, u_short, u_char, u_char);
66b3a00663Schristos static const struct atNBPtuple *nbp_tuple_print(netdissect_options *ndo, const struct atNBPtuple *,
670f74e101Schristos 						const u_char *,
680f74e101Schristos 						u_short, u_char, u_char);
69b3a00663Schristos static const struct atNBPtuple *nbp_name_print(netdissect_options *, const struct atNBPtuple *,
700f74e101Schristos 					       const u_char *);
71b3a00663Schristos static const char *ataddr_string(netdissect_options *, u_short, u_char);
72c74ad251Schristos static void ddp_print(netdissect_options *, const u_char *, u_int, u_int, u_short, u_char, u_char);
73c74ad251Schristos static const char *ddpskt_string(netdissect_options *, u_int);
740f74e101Schristos 
750f74e101Schristos /*
760f74e101Schristos  * Print LLAP packets received on a physical LocalTalk interface.
770f74e101Schristos  */
78c74ad251Schristos void
79b3a00663Schristos ltalk_if_print(netdissect_options *ndo,
80b3a00663Schristos                const struct pcap_pkthdr *h, const u_char *p)
810f74e101Schristos {
82dc860a36Sspz 	u_int hdrlen;
83dc860a36Sspz 
84c74ad251Schristos 	ndo->ndo_protocol = "ltalk";
85dc860a36Sspz 	hdrlen = llap_print(ndo, p, h->len);
86dc860a36Sspz 	if (hdrlen == 0) {
87dc860a36Sspz 		/* Cut short by the snapshot length. */
88c74ad251Schristos 		ndo->ndo_ll_hdr_len += h->caplen;
89c74ad251Schristos 		return;
90dc860a36Sspz 	}
91c74ad251Schristos 	ndo->ndo_ll_hdr_len += hdrlen;
920f74e101Schristos }
930f74e101Schristos 
940f74e101Schristos /*
950f74e101Schristos  * Print AppleTalk LLAP packets.
960f74e101Schristos  */
970f74e101Schristos u_int
98b3a00663Schristos llap_print(netdissect_options *ndo,
99c74ad251Schristos            const u_char *bp, u_int length)
1000f74e101Schristos {
101c74ad251Schristos 	const struct LAP *lp;
102c74ad251Schristos 	const struct atDDP *dp;
103c74ad251Schristos 	const struct atShortDDP *sdp;
1040f74e101Schristos 	u_short snet;
1050f74e101Schristos 	u_int hdrlen;
1060f74e101Schristos 
107c74ad251Schristos 	ndo->ndo_protocol = "llap";
1080e9868baSchristos 	if (length < sizeof(*lp)) {
109c74ad251Schristos 		ND_PRINT(" [|llap %u]", length);
1100e9868baSchristos 		return (length);
1110e9868baSchristos 	}
112c74ad251Schristos 	if (!ND_TTEST_LEN(bp, sizeof(*lp))) {
113c74ad251Schristos 		nd_print_trunc(ndo);
114dc860a36Sspz 		return (0);	/* cut short by the snapshot length */
115dc860a36Sspz 	}
1160f74e101Schristos 	lp = (const struct LAP *)bp;
1170f74e101Schristos 	bp += sizeof(*lp);
1180f74e101Schristos 	length -= sizeof(*lp);
1190f74e101Schristos 	hdrlen = sizeof(*lp);
120c74ad251Schristos 	switch (GET_U_1(lp->type)) {
1210f74e101Schristos 
1220f74e101Schristos 	case lapShortDDP:
1230f74e101Schristos 		if (length < ddpSSize) {
124c74ad251Schristos 			ND_PRINT(" [|sddp %u]", length);
1250f74e101Schristos 			return (length);
1260f74e101Schristos 		}
127c74ad251Schristos 		if (!ND_TTEST_LEN(bp, ddpSSize)) {
128c74ad251Schristos 			ND_PRINT(" [|sddp]");
129dc860a36Sspz 			return (0);	/* cut short by the snapshot length */
130dc860a36Sspz 		}
1310f74e101Schristos 		sdp = (const struct atShortDDP *)bp;
132c74ad251Schristos 		ND_PRINT("%s.%s",
133c74ad251Schristos 		    ataddr_string(ndo, 0, GET_U_1(lp->src)),
134c74ad251Schristos 		    ddpskt_string(ndo, GET_U_1(sdp->srcSkt)));
135c74ad251Schristos 		ND_PRINT(" > %s.%s:",
136c74ad251Schristos 		    ataddr_string(ndo, 0, GET_U_1(lp->dst)),
137c74ad251Schristos 		    ddpskt_string(ndo, GET_U_1(sdp->dstSkt)));
1380f74e101Schristos 		bp += ddpSSize;
1390f74e101Schristos 		length -= ddpSSize;
1400f74e101Schristos 		hdrlen += ddpSSize;
141c74ad251Schristos 		ddp_print(ndo, bp, length, GET_U_1(sdp->type), 0,
142c74ad251Schristos 			  GET_U_1(lp->src), GET_U_1(sdp->srcSkt));
1430f74e101Schristos 		break;
1440f74e101Schristos 
1450f74e101Schristos 	case lapDDP:
1460f74e101Schristos 		if (length < ddpSize) {
147c74ad251Schristos 			ND_PRINT(" [|ddp %u]", length);
1480f74e101Schristos 			return (length);
1490f74e101Schristos 		}
150c74ad251Schristos 		if (!ND_TTEST_LEN(bp, ddpSize)) {
151c74ad251Schristos 			ND_PRINT(" [|ddp]");
152dc860a36Sspz 			return (0);	/* cut short by the snapshot length */
153dc860a36Sspz 		}
1540f74e101Schristos 		dp = (const struct atDDP *)bp;
155c74ad251Schristos 		snet = GET_BE_U_2(dp->srcNet);
156c74ad251Schristos 		ND_PRINT("%s.%s",
157c74ad251Schristos 			 ataddr_string(ndo, snet, GET_U_1(dp->srcNode)),
158c74ad251Schristos 			 ddpskt_string(ndo, GET_U_1(dp->srcSkt)));
159c74ad251Schristos 		ND_PRINT(" > %s.%s:",
160c74ad251Schristos 		    ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)),
161c74ad251Schristos 		    ddpskt_string(ndo, GET_U_1(dp->dstSkt)));
1620f74e101Schristos 		bp += ddpSize;
1630f74e101Schristos 		length -= ddpSize;
1640f74e101Schristos 		hdrlen += ddpSize;
165c74ad251Schristos 		ddp_print(ndo, bp, length, GET_U_1(dp->type), snet,
166c74ad251Schristos 			  GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt));
1670f74e101Schristos 		break;
1680f74e101Schristos 
1690f74e101Schristos #ifdef notdef
1700f74e101Schristos 	case lapKLAP:
1710f74e101Schristos 		klap_print(bp, length);
1720f74e101Schristos 		break;
1730f74e101Schristos #endif
1740f74e101Schristos 
1750f74e101Schristos 	default:
176c74ad251Schristos 		ND_PRINT("%u > %u at-lap#%u %u",
177c74ad251Schristos 		    GET_U_1(lp->src), GET_U_1(lp->dst), GET_U_1(lp->type),
178c74ad251Schristos 		    length);
1790f74e101Schristos 		break;
1800f74e101Schristos 	}
1810f74e101Schristos 	return (hdrlen);
1820f74e101Schristos }
1830f74e101Schristos 
1840f74e101Schristos /*
1850f74e101Schristos  * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called
1860f74e101Schristos  * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk
1870f74e101Schristos  * packets in them).
1880f74e101Schristos  */
1890f74e101Schristos void
190b3a00663Schristos atalk_print(netdissect_options *ndo,
191c74ad251Schristos             const u_char *bp, u_int length)
1920f74e101Schristos {
193c74ad251Schristos 	const struct atDDP *dp;
1940f74e101Schristos 	u_short snet;
1950f74e101Schristos 
196c74ad251Schristos 	ndo->ndo_protocol = "atalk";
197b3a00663Schristos         if(!ndo->ndo_eflag)
198c74ad251Schristos             ND_PRINT("AT ");
1990f74e101Schristos 
2000f74e101Schristos 	if (length < ddpSize) {
201c74ad251Schristos 		ND_PRINT(" [|ddp %u]", length);
2020f74e101Schristos 		return;
2030f74e101Schristos 	}
204c74ad251Schristos 	if (!ND_TTEST_LEN(bp, ddpSize)) {
205c74ad251Schristos 		ND_PRINT(" [|ddp]");
206dc860a36Sspz 		return;
207dc860a36Sspz 	}
2080f74e101Schristos 	dp = (const struct atDDP *)bp;
209c74ad251Schristos 	snet = GET_BE_U_2(dp->srcNet);
210c74ad251Schristos 	ND_PRINT("%s.%s", ataddr_string(ndo, snet, GET_U_1(dp->srcNode)),
211c74ad251Schristos 		 ddpskt_string(ndo, GET_U_1(dp->srcSkt)));
212c74ad251Schristos 	ND_PRINT(" > %s.%s: ",
213c74ad251Schristos 	       ataddr_string(ndo, GET_BE_U_2(dp->dstNet), GET_U_1(dp->dstNode)),
214c74ad251Schristos 	       ddpskt_string(ndo, GET_U_1(dp->dstSkt)));
2150f74e101Schristos 	bp += ddpSize;
2160f74e101Schristos 	length -= ddpSize;
217c74ad251Schristos 	ddp_print(ndo, bp, length, GET_U_1(dp->type), snet,
218c74ad251Schristos 		  GET_U_1(dp->srcNode), GET_U_1(dp->srcSkt));
2190f74e101Schristos }
2200f74e101Schristos 
2210f74e101Schristos /* XXX should probably pass in the snap header and do checks like arp_print() */
2220f74e101Schristos void
223b3a00663Schristos aarp_print(netdissect_options *ndo,
224c74ad251Schristos            const u_char *bp, u_int length)
2250f74e101Schristos {
226c74ad251Schristos 	const struct aarp *ap;
2270f74e101Schristos 
228b3a00663Schristos #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3])
2290f74e101Schristos 
230c74ad251Schristos 	ndo->ndo_protocol = "aarp";
231c74ad251Schristos 	ND_PRINT("aarp ");
2320f74e101Schristos 	ap = (const struct aarp *)bp;
233c74ad251Schristos 	if (!ND_TTEST_SIZE(ap)) {
234dc860a36Sspz 		/* Just bail if we don't have the whole chunk. */
235c74ad251Schristos 		nd_print_trunc(ndo);
236dc860a36Sspz 		return;
237dc860a36Sspz 	}
238dc860a36Sspz 	if (length < sizeof(*ap)) {
239c74ad251Schristos 		ND_PRINT(" [|aarp %u]", length);
240dc860a36Sspz 		return;
241dc860a36Sspz 	}
242c74ad251Schristos 	if (GET_BE_U_2(ap->htype) == 1 &&
243c74ad251Schristos 	    GET_BE_U_2(ap->ptype) == ETHERTYPE_ATALK &&
244c74ad251Schristos 	    GET_U_1(ap->halen) == MAC_ADDR_LEN && GET_U_1(ap->palen) == 4)
245c74ad251Schristos 		switch (GET_BE_U_2(ap->op)) {
2460f74e101Schristos 
2470f74e101Schristos 		case 1:				/* request */
248c74ad251Schristos 			ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr));
2490f74e101Schristos 			return;
2500f74e101Schristos 
2510f74e101Schristos 		case 2:				/* response */
252c74ad251Schristos 			ND_PRINT("reply %s is-at %s", AT(psaddr), GET_ETHERADDR_STRING(ap->hsaddr));
2530f74e101Schristos 			return;
2540f74e101Schristos 
2550f74e101Schristos 		case 3:				/* probe (oy!) */
256c74ad251Schristos 			ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr));
2570f74e101Schristos 			return;
2580f74e101Schristos 		}
259c74ad251Schristos 	ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u",
260c74ad251Schristos 	    length, GET_BE_U_2(ap->op), GET_BE_U_2(ap->htype),
261c74ad251Schristos 	    GET_BE_U_2(ap->ptype), GET_U_1(ap->halen), GET_U_1(ap->palen));
2620f74e101Schristos }
2630f74e101Schristos 
2640f74e101Schristos /*
2650f74e101Schristos  * Print AppleTalk Datagram Delivery Protocol packets.
2660f74e101Schristos  */
2670f74e101Schristos static void
268b3a00663Schristos ddp_print(netdissect_options *ndo,
269c74ad251Schristos           const u_char *bp, u_int length, u_int t,
270c74ad251Schristos           u_short snet, u_char snode, u_char skt)
2710f74e101Schristos {
2720f74e101Schristos 
2730f74e101Schristos 	switch (t) {
2740f74e101Schristos 
2750f74e101Schristos 	case ddpNBP:
276b3a00663Schristos 		nbp_print(ndo, (const struct atNBP *)bp, length, snet, snode, skt);
2770f74e101Schristos 		break;
2780f74e101Schristos 
2790f74e101Schristos 	case ddpATP:
280b3a00663Schristos 		atp_print(ndo, (const struct atATP *)bp, length);
2810f74e101Schristos 		break;
2820f74e101Schristos 
2830f74e101Schristos 	case ddpEIGRP:
284b3a00663Schristos 		eigrp_print(ndo, bp, length);
2850f74e101Schristos 		break;
2860f74e101Schristos 
2870f74e101Schristos 	default:
288c74ad251Schristos 		ND_PRINT(" at-%s %u", tok2str(type2str, NULL, t), length);
2890f74e101Schristos 		break;
2900f74e101Schristos 	}
2910f74e101Schristos }
2920f74e101Schristos 
2930f74e101Schristos static void
294b3a00663Schristos atp_print(netdissect_options *ndo,
295c74ad251Schristos           const struct atATP *ap, u_int length)
2960f74e101Schristos {
297c74ad251Schristos 	uint8_t control;
298b3a00663Schristos 	uint32_t data;
2990f74e101Schristos 
300b3a00663Schristos 	if ((const u_char *)(ap + 1) > ndo->ndo_snapend) {
3010f74e101Schristos 		/* Just bail if we don't have the whole chunk. */
302c74ad251Schristos 		nd_print_trunc(ndo);
3030f74e101Schristos 		return;
3040f74e101Schristos 	}
3050e9868baSchristos 	if (length < sizeof(*ap)) {
306c74ad251Schristos 		ND_PRINT(" [|atp %u]", length);
3070e9868baSchristos 		return;
3080e9868baSchristos 	}
3090f74e101Schristos 	length -= sizeof(*ap);
310c74ad251Schristos 	control = GET_U_1(ap->control);
311c74ad251Schristos 	switch (control & 0xc0) {
3120f74e101Schristos 
3130f74e101Schristos 	case atpReqCode:
314c74ad251Schristos 		ND_PRINT(" atp-req%s %u",
315c74ad251Schristos 			     control & atpXO? " " : "*",
316c74ad251Schristos 			     GET_BE_U_2(ap->transID));
3170f74e101Schristos 
318c74ad251Schristos 		atp_bitmap_print(ndo, GET_U_1(ap->bitmap));
3190f74e101Schristos 
3200f74e101Schristos 		if (length != 0)
321c74ad251Schristos 			ND_PRINT(" [len=%u]", length);
3220f74e101Schristos 
323c74ad251Schristos 		switch (control & (atpEOM|atpSTS)) {
3240f74e101Schristos 		case atpEOM:
325c74ad251Schristos 			ND_PRINT(" [EOM]");
3260f74e101Schristos 			break;
3270f74e101Schristos 		case atpSTS:
328c74ad251Schristos 			ND_PRINT(" [STS]");
3290f74e101Schristos 			break;
3300f74e101Schristos 		case atpEOM|atpSTS:
331c74ad251Schristos 			ND_PRINT(" [EOM,STS]");
3320f74e101Schristos 			break;
3330f74e101Schristos 		}
3340f74e101Schristos 		break;
3350f74e101Schristos 
3360f74e101Schristos 	case atpRspCode:
337c74ad251Schristos 		ND_PRINT(" atp-resp%s%u:%u (%u)",
338c74ad251Schristos 			     control & atpEOM? "*" : " ",
339c74ad251Schristos 			     GET_BE_U_2(ap->transID), GET_U_1(ap->bitmap),
340c74ad251Schristos 			     length);
341c74ad251Schristos 		switch (control & (atpXO|atpSTS)) {
3420f74e101Schristos 		case atpXO:
343c74ad251Schristos 			ND_PRINT(" [XO]");
3440f74e101Schristos 			break;
3450f74e101Schristos 		case atpSTS:
346c74ad251Schristos 			ND_PRINT(" [STS]");
3470f74e101Schristos 			break;
3480f74e101Schristos 		case atpXO|atpSTS:
349c74ad251Schristos 			ND_PRINT(" [XO,STS]");
3500f74e101Schristos 			break;
3510f74e101Schristos 		}
3520f74e101Schristos 		break;
3530f74e101Schristos 
3540f74e101Schristos 	case atpRelCode:
355c74ad251Schristos 		ND_PRINT(" atp-rel  %u", GET_BE_U_2(ap->transID));
3560f74e101Schristos 
357c74ad251Schristos 		atp_bitmap_print(ndo, GET_U_1(ap->bitmap));
3580f74e101Schristos 
3590f74e101Schristos 		/* length should be zero */
3600f74e101Schristos 		if (length)
361c74ad251Schristos 			ND_PRINT(" [len=%u]", length);
3620f74e101Schristos 
3630f74e101Schristos 		/* there shouldn't be any control flags */
364c74ad251Schristos 		if (control & (atpXO|atpEOM|atpSTS)) {
365c74ad251Schristos 			char c = '[';
366c74ad251Schristos 			if (control & atpXO) {
367c74ad251Schristos 				ND_PRINT("%cXO", c);
3680f74e101Schristos 				c = ',';
3690f74e101Schristos 			}
370c74ad251Schristos 			if (control & atpEOM) {
371c74ad251Schristos 				ND_PRINT("%cEOM", c);
3720f74e101Schristos 				c = ',';
3730f74e101Schristos 			}
374c74ad251Schristos 			if (control & atpSTS) {
375c74ad251Schristos 				ND_PRINT("%cSTS", c);
3760f74e101Schristos 			}
377c74ad251Schristos 			ND_PRINT("]");
3780f74e101Schristos 		}
3790f74e101Schristos 		break;
3800f74e101Schristos 
3810f74e101Schristos 	default:
382c74ad251Schristos 		ND_PRINT(" atp-0x%x  %u (%u)", control,
383c74ad251Schristos 			     GET_BE_U_2(ap->transID), length);
3840f74e101Schristos 		break;
3850f74e101Schristos 	}
386c74ad251Schristos 	data = GET_BE_U_4(ap->userData);
3870f74e101Schristos 	if (data != 0)
388c74ad251Schristos 		ND_PRINT(" 0x%x", data);
3890f74e101Schristos }
3900f74e101Schristos 
3910f74e101Schristos static void
392b3a00663Schristos atp_bitmap_print(netdissect_options *ndo,
393c74ad251Schristos                  u_char bm)
3940f74e101Schristos {
395c74ad251Schristos 	u_int i;
3960f74e101Schristos 
3970f74e101Schristos 	/*
3980f74e101Schristos 	 * The '& 0xff' below is needed for compilers that want to sign
3990f74e101Schristos 	 * extend a u_char, which is the case with the Ultrix compiler.
4000f74e101Schristos 	 * (gcc is smart enough to eliminate it, at least on the Sparc).
4010f74e101Schristos 	 */
4020f74e101Schristos 	if ((bm + 1) & (bm & 0xff)) {
403c74ad251Schristos 		char c = '<';
4040f74e101Schristos 		for (i = 0; bm; ++i) {
4050f74e101Schristos 			if (bm & 1) {
406c74ad251Schristos 				ND_PRINT("%c%u", c, i);
4070f74e101Schristos 				c = ',';
4080f74e101Schristos 			}
4090f74e101Schristos 			bm >>= 1;
4100f74e101Schristos 		}
411c74ad251Schristos 		ND_PRINT(">");
4120f74e101Schristos 	} else {
4130f74e101Schristos 		for (i = 0; bm; ++i)
4140f74e101Schristos 			bm >>= 1;
4150f74e101Schristos 		if (i > 1)
416c74ad251Schristos 			ND_PRINT("<0-%u>", i - 1);
4170f74e101Schristos 		else
418c74ad251Schristos 			ND_PRINT("<0>");
4190f74e101Schristos 	}
4200f74e101Schristos }
4210f74e101Schristos 
4220f74e101Schristos static void
423b3a00663Schristos nbp_print(netdissect_options *ndo,
424c74ad251Schristos           const struct atNBP *np, u_int length, u_short snet,
425c74ad251Schristos           u_char snode, u_char skt)
4260f74e101Schristos {
427c74ad251Schristos 	const struct atNBPtuple *tp =
428fdccd7e4Schristos 		(const struct atNBPtuple *)((const u_char *)np + nbpHeaderSize);
429c74ad251Schristos 	uint8_t control;
430c74ad251Schristos 	u_int i;
4310f74e101Schristos 	const u_char *ep;
4320f74e101Schristos 
4330f74e101Schristos 	if (length < nbpHeaderSize) {
434c74ad251Schristos 		ND_PRINT(" truncated-nbp %u", length);
4350f74e101Schristos 		return;
4360f74e101Schristos 	}
4370f74e101Schristos 
4380f74e101Schristos 	length -= nbpHeaderSize;
4390f74e101Schristos 	if (length < 8) {
4400f74e101Schristos 		/* must be room for at least one tuple */
441c74ad251Schristos 		ND_PRINT(" truncated-nbp %u", length + nbpHeaderSize);
4420f74e101Schristos 		return;
4430f74e101Schristos 	}
4440f74e101Schristos 	/* ep points to end of available data */
445b3a00663Schristos 	ep = ndo->ndo_snapend;
4460f74e101Schristos 	if ((const u_char *)tp > ep) {
447c74ad251Schristos 		nd_print_trunc(ndo);
4480f74e101Schristos 		return;
4490f74e101Schristos 	}
450c74ad251Schristos 	control = GET_U_1(np->control);
451c74ad251Schristos 	switch (i = (control & 0xf0)) {
4520f74e101Schristos 
4530f74e101Schristos 	case nbpBrRq:
4540f74e101Schristos 	case nbpLkUp:
455c74ad251Schristos 		ND_PRINT(i == nbpLkUp? " nbp-lkup %u:":" nbp-brRq %u:",
456c74ad251Schristos 			 GET_U_1(np->id));
4570f74e101Schristos 		if ((const u_char *)(tp + 1) > ep) {
458c74ad251Schristos 			nd_print_trunc(ndo);
4590f74e101Schristos 			return;
4600f74e101Schristos 		}
461b3a00663Schristos 		(void)nbp_name_print(ndo, tp, ep);
4620f74e101Schristos 		/*
4630f74e101Schristos 		 * look for anomalies: the spec says there can only
4640f74e101Schristos 		 * be one tuple, the address must match the source
4650f74e101Schristos 		 * address and the enumerator should be zero.
4660f74e101Schristos 		 */
467c74ad251Schristos 		if ((control & 0xf) != 1)
468c74ad251Schristos 			ND_PRINT(" [ntup=%u]", control & 0xf);
469c74ad251Schristos 		if (GET_U_1(tp->enumerator))
470c74ad251Schristos 			ND_PRINT(" [enum=%u]", GET_U_1(tp->enumerator));
471c74ad251Schristos 		if (GET_BE_U_2(tp->net) != snet ||
472c74ad251Schristos 		    GET_U_1(tp->node) != snode ||
473c74ad251Schristos 		    GET_U_1(tp->skt) != skt)
474c74ad251Schristos 			ND_PRINT(" [addr=%s.%u]",
475c74ad251Schristos 			    ataddr_string(ndo, GET_BE_U_2(tp->net),
476c74ad251Schristos 					  GET_U_1(tp->node)),
477c74ad251Schristos 			    GET_U_1(tp->skt));
4780f74e101Schristos 		break;
4790f74e101Schristos 
4800f74e101Schristos 	case nbpLkUpReply:
481c74ad251Schristos 		ND_PRINT(" nbp-reply %u:", GET_U_1(np->id));
4820f74e101Schristos 
4830f74e101Schristos 		/* print each of the tuples in the reply */
484c74ad251Schristos 		for (i = control & 0xf; i != 0 && tp; i--)
485b3a00663Schristos 			tp = nbp_tuple_print(ndo, tp, ep, snet, snode, skt);
4860f74e101Schristos 		break;
4870f74e101Schristos 
4880f74e101Schristos 	default:
489c74ad251Schristos 		ND_PRINT(" nbp-0x%x  %u (%u)", control, GET_U_1(np->id),
490c74ad251Schristos 			 length);
4910f74e101Schristos 		break;
4920f74e101Schristos 	}
4930f74e101Schristos }
4940f74e101Schristos 
4950f74e101Schristos /* print a counted string */
496c74ad251Schristos static const u_char *
497b3a00663Schristos print_cstring(netdissect_options *ndo,
498c74ad251Schristos               const u_char *cp, const u_char *ep)
4990f74e101Schristos {
500c74ad251Schristos 	u_int length;
5010f74e101Schristos 
502c74ad251Schristos 	if (cp >= ep) {
503c74ad251Schristos 		nd_print_trunc(ndo);
5040f74e101Schristos 		return (0);
5050f74e101Schristos 	}
506c74ad251Schristos 	length = GET_U_1(cp);
507c74ad251Schristos 	cp++;
5080f74e101Schristos 
5090f74e101Schristos 	/* Spec says string can be at most 32 bytes long */
5100f74e101Schristos 	if (length > 32) {
511c74ad251Schristos 		ND_PRINT("[len=%u]", length);
5120f74e101Schristos 		return (0);
5130f74e101Schristos 	}
514c74ad251Schristos 	while (length != 0) {
515c74ad251Schristos 		if (cp >= ep) {
516c74ad251Schristos 			nd_print_trunc(ndo);
5170f74e101Schristos 			return (0);
5180f74e101Schristos 		}
519c74ad251Schristos 		fn_print_char(ndo, GET_U_1(cp));
520c74ad251Schristos 		cp++;
521c74ad251Schristos 		length--;
5220f74e101Schristos 	}
5230f74e101Schristos 	return (cp);
5240f74e101Schristos }
5250f74e101Schristos 
5260f74e101Schristos static const struct atNBPtuple *
527b3a00663Schristos nbp_tuple_print(netdissect_options *ndo,
528c74ad251Schristos                 const struct atNBPtuple *tp, const u_char *ep,
529c74ad251Schristos                 u_short snet, u_char snode, u_char skt)
5300f74e101Schristos {
531c74ad251Schristos 	const struct atNBPtuple *tpn;
5320f74e101Schristos 
5330f74e101Schristos 	if ((const u_char *)(tp + 1) > ep) {
534c74ad251Schristos 		nd_print_trunc(ndo);
5350f74e101Schristos 		return 0;
5360f74e101Schristos 	}
537b3a00663Schristos 	tpn = nbp_name_print(ndo, tp, ep);
5380f74e101Schristos 
5390f74e101Schristos 	/* if the enumerator isn't 1, print it */
540c74ad251Schristos 	if (GET_U_1(tp->enumerator) != 1)
541c74ad251Schristos 		ND_PRINT("(%u)", GET_U_1(tp->enumerator));
5420f74e101Schristos 
5430f74e101Schristos 	/* if the socket doesn't match the src socket, print it */
544c74ad251Schristos 	if (GET_U_1(tp->skt) != skt)
545c74ad251Schristos 		ND_PRINT(" %u", GET_U_1(tp->skt));
5460f74e101Schristos 
5470f74e101Schristos 	/* if the address doesn't match the src address, it's an anomaly */
548c74ad251Schristos 	if (GET_BE_U_2(tp->net) != snet ||
549c74ad251Schristos 	    GET_U_1(tp->node) != snode)
550c74ad251Schristos 		ND_PRINT(" [addr=%s]",
551c74ad251Schristos 		    ataddr_string(ndo, GET_BE_U_2(tp->net), GET_U_1(tp->node)));
5520f74e101Schristos 
5530f74e101Schristos 	return (tpn);
5540f74e101Schristos }
5550f74e101Schristos 
5560f74e101Schristos static const struct atNBPtuple *
557b3a00663Schristos nbp_name_print(netdissect_options *ndo,
558c74ad251Schristos                const struct atNBPtuple *tp, const u_char *ep)
5590f74e101Schristos {
560c74ad251Schristos 	const u_char *cp = (const u_char *)tp + nbpTupleSize;
5610f74e101Schristos 
562c74ad251Schristos 	ND_PRINT(" ");
5630f74e101Schristos 
5640f74e101Schristos 	/* Object */
565c74ad251Schristos 	ND_PRINT("\"");
566b3a00663Schristos 	if ((cp = print_cstring(ndo, cp, ep)) != NULL) {
5670f74e101Schristos 		/* Type */
568c74ad251Schristos 		ND_PRINT(":");
569b3a00663Schristos 		if ((cp = print_cstring(ndo, cp, ep)) != NULL) {
5700f74e101Schristos 			/* Zone */
571c74ad251Schristos 			ND_PRINT("@");
572b3a00663Schristos 			if ((cp = print_cstring(ndo, cp, ep)) != NULL)
573c74ad251Schristos 				ND_PRINT("\"");
5740f74e101Schristos 		}
5750f74e101Schristos 	}
5760f74e101Schristos 	return ((const struct atNBPtuple *)cp);
5770f74e101Schristos }
5780f74e101Schristos 
5790f74e101Schristos 
5800f74e101Schristos #define HASHNAMESIZE 4096
5810f74e101Schristos 
5820f74e101Schristos struct hnamemem {
583c74ad251Schristos 	u_int addr;
5840f74e101Schristos 	char *name;
5850f74e101Schristos 	struct hnamemem *nxt;
5860f74e101Schristos };
5870f74e101Schristos 
5880f74e101Schristos static struct hnamemem hnametable[HASHNAMESIZE];
5890f74e101Schristos 
5900f74e101Schristos static const char *
591b3a00663Schristos ataddr_string(netdissect_options *ndo,
592b3a00663Schristos               u_short atnet, u_char athost)
5930f74e101Schristos {
594c74ad251Schristos 	struct hnamemem *tp, *tp2;
595c74ad251Schristos 	u_int i = (atnet << 8) | athost;
596870189d2Schristos 	char nambuf[256+1];
5970f74e101Schristos 	static int first = 1;
5980f74e101Schristos 	FILE *fp;
5990f74e101Schristos 
6000f74e101Schristos 	/*
601c74ad251Schristos 	 * Are we doing address to name resolution?
6020f74e101Schristos 	 */
603c74ad251Schristos 	if (!ndo->ndo_nflag) {
604c74ad251Schristos 		/*
605c74ad251Schristos 		 * Yes.  Have we tried to open and read an AppleTalk
606c74ad251Schristos 		 * number to name map file?
607c74ad251Schristos 		 */
608c74ad251Schristos 		if (!first) {
609c74ad251Schristos 			/*
610c74ad251Schristos 			 * No; try to do so.
611c74ad251Schristos 			 */
612c74ad251Schristos 			first = 0;
613c74ad251Schristos 			fp = fopen("/etc/atalk.names", "r");
614c74ad251Schristos 			if (fp != NULL) {
6150f74e101Schristos 				char line[256];
616c74ad251Schristos 				u_int i1, i2;
6170f74e101Schristos 
6180f74e101Schristos 				while (fgets(line, sizeof(line), fp)) {
619c74ad251Schristos 					if (line[0] == '\n' || line[0] == 0 ||
620c74ad251Schristos 					    line[0] == '#')
6210f74e101Schristos 						continue;
622c74ad251Schristos 					if (sscanf(line, "%u.%u %256s", &i1,
623c74ad251Schristos 					    &i2, nambuf) == 3)
6240f74e101Schristos 						/* got a hostname. */
6250e9868baSchristos 						i2 |= (i1 << 8);
626c74ad251Schristos 					else if (sscanf(line, "%u %256s", &i1,
627c74ad251Schristos 					    nambuf) == 2)
6280f74e101Schristos 						/* got a net name */
6290e9868baSchristos 						i2 = (i1 << 8) | 255;
6300f74e101Schristos 					else
6310f74e101Schristos 						continue;
6320f74e101Schristos 
6330e9868baSchristos 					for (tp = &hnametable[i2 & (HASHNAMESIZE-1)];
6340f74e101Schristos 					     tp->nxt; tp = tp->nxt)
6350f74e101Schristos 						;
6360e9868baSchristos 					tp->addr = i2;
637fdccd7e4Schristos 					tp->nxt = newhnamemem(ndo);
6380f74e101Schristos 					tp->name = strdup(nambuf);
639fdccd7e4Schristos 					if (tp->name == NULL)
640fdccd7e4Schristos 						(*ndo->ndo_error)(ndo,
641c74ad251Schristos 						    S_ERR_ND_MEM_ALLOC,
642c74ad251Schristos 						    "%s: strdup(nambuf)", __func__);
6430f74e101Schristos 				}
6440f74e101Schristos 				fclose(fp);
6450f74e101Schristos 			}
646c74ad251Schristos 		}
647c74ad251Schristos 	}
6480f74e101Schristos 
649c74ad251Schristos 	/*
650c74ad251Schristos 	 * Now try to look up the address in the table.
651c74ad251Schristos 	 */
6520f74e101Schristos 	for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
6530f74e101Schristos 		if (tp->addr == i)
6540f74e101Schristos 			return (tp->name);
6550f74e101Schristos 
6560f74e101Schristos 	/* didn't have the node name -- see if we've got the net name */
6570f74e101Schristos 	i |= 255;
6580f74e101Schristos 	for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt)
6590f74e101Schristos 		if (tp2->addr == i) {
6600f74e101Schristos 			tp->addr = (atnet << 8) | athost;
661fdccd7e4Schristos 			tp->nxt = newhnamemem(ndo);
662c74ad251Schristos 			(void)snprintf(nambuf, sizeof(nambuf), "%s.%u",
6630f74e101Schristos 			    tp2->name, athost);
6640f74e101Schristos 			tp->name = strdup(nambuf);
665fdccd7e4Schristos 			if (tp->name == NULL)
666c74ad251Schristos 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
667c74ad251Schristos 					"%s: strdup(nambuf)", __func__);
6680f74e101Schristos 			return (tp->name);
6690f74e101Schristos 		}
6700f74e101Schristos 
6710f74e101Schristos 	tp->addr = (atnet << 8) | athost;
672fdccd7e4Schristos 	tp->nxt = newhnamemem(ndo);
6730f74e101Schristos 	if (athost != 255)
674c74ad251Schristos 		(void)snprintf(nambuf, sizeof(nambuf), "%u.%u", atnet, athost);
6750f74e101Schristos 	else
676c74ad251Schristos 		(void)snprintf(nambuf, sizeof(nambuf), "%u", atnet);
6770f74e101Schristos 	tp->name = strdup(nambuf);
678fdccd7e4Schristos 	if (tp->name == NULL)
679c74ad251Schristos 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
680c74ad251Schristos 				  "%s: strdup(nambuf)", __func__);
6810f74e101Schristos 
6820f74e101Schristos 	return (tp->name);
6830f74e101Schristos }
6840f74e101Schristos 
685870189d2Schristos static const struct tok skt2str[] = {
6860f74e101Schristos 	{ rtmpSkt,	"rtmp" },	/* routing table maintenance */
6870f74e101Schristos 	{ nbpSkt,	"nis" },	/* name info socket */
6880f74e101Schristos 	{ echoSkt,	"echo" },	/* AppleTalk echo protocol */
6890f74e101Schristos 	{ zipSkt,	"zip" },	/* zone info protocol */
6900f74e101Schristos 	{ 0,		NULL }
6910f74e101Schristos };
6920f74e101Schristos 
6930f74e101Schristos static const char *
694b3a00663Schristos ddpskt_string(netdissect_options *ndo,
695c74ad251Schristos               u_int skt)
6960f74e101Schristos {
6970f74e101Schristos 	static char buf[8];
6980f74e101Schristos 
699b3a00663Schristos 	if (ndo->ndo_nflag) {
700c74ad251Schristos 		(void)snprintf(buf, sizeof(buf), "%u", skt);
7010f74e101Schristos 		return (buf);
7020f74e101Schristos 	}
703c74ad251Schristos 	return (tok2str(skt2str, "%u", skt));
7040f74e101Schristos }
705