117680Spst/*
239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst *
2117680Spst * Format and print AppleTalk packets.
2256896Sfenner *
2356896Sfenner * $FreeBSD$
2417680Spst */
2526183Sfenner
2617680Spst#ifndef lint
27127675Sbmsstatic const char rcsid[] _U_ =
28190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-atalk.c,v 1.81 2004-05-01 09:41:50 hannes Exp $ (LBL)";
2917680Spst#endif
3017680Spst
3156896Sfenner#ifdef HAVE_CONFIG_H
3256896Sfenner#include "config.h"
3356896Sfenner#endif
3456896Sfenner
35127675Sbms#include <tcpdump-stdinc.h>
3617680Spst
3717680Spst#include <stdio.h>
3817680Spst#include <stdlib.h>
3917680Spst#include <string.h>
4098527Sfenner#include <pcap.h>
4117680Spst
4217680Spst#include "interface.h"
4317680Spst#include "addrtoname.h"
4417680Spst#include "ethertype.h"
4517680Spst#include "extract.h"			/* must come after interface.h */
4617680Spst#include "appletalk.h"
4717680Spst
4817680Spststatic struct tok type2str[] = {
4917680Spst	{ ddpRTMP,		"rtmp" },
5017680Spst	{ ddpRTMPrequest,	"rtmpReq" },
5117680Spst	{ ddpECHO,		"echo" },
5217680Spst	{ ddpIP,		"IP" },
5317680Spst	{ ddpARP,		"ARP" },
5417680Spst	{ ddpKLAP,		"KLAP" },
5517680Spst	{ 0,			NULL }
5617680Spst};
5717680Spst
5817680Spststruct aarp {
5975118Sfenner	u_int16_t	htype, ptype;
6075118Sfenner	u_int8_t	halen, palen;
6175118Sfenner	u_int16_t	op;
6275118Sfenner	u_int8_t	hsaddr[6];
6375118Sfenner	u_int8_t	psaddr[4];
6475118Sfenner	u_int8_t	hdaddr[6];
6575118Sfenner	u_int8_t	pdaddr[4];
6617680Spst};
6717680Spst
6817680Spststatic char tstr[] = "[|atalk]";
6917680Spst
7017680Spststatic void atp_print(const struct atATP *, u_int);
7117680Spststatic void atp_bitmap_print(u_char);
7217680Spststatic void nbp_print(const struct atNBP *, u_int, u_short, u_char, u_char);
7317680Spststatic const char *print_cstring(const char *, const u_char *);
7417680Spststatic const struct atNBPtuple *nbp_tuple_print(const struct atNBPtuple *,
7517680Spst						const u_char *,
7617680Spst						u_short, u_char, u_char);
7717680Spststatic const struct atNBPtuple *nbp_name_print(const struct atNBPtuple *,
7817680Spst					       const u_char *);
7917680Spststatic const char *ataddr_string(u_short, u_char);
8017680Spststatic void ddp_print(const u_char *, u_int, int, u_short, u_char, u_char);
8117680Spststatic const char *ddpskt_string(int);
8217680Spst
8317680Spst/*
8498527Sfenner * Print LLAP packets received on a physical LocalTalk interface.
8598527Sfenner */
86127675Sbmsu_int
87127675Sbmsltalk_if_print(const struct pcap_pkthdr *h, const u_char *p)
8898527Sfenner{
89127675Sbms	return (llap_print(p, h->caplen));
9098527Sfenner}
9198527Sfenner
9298527Sfenner/*
9375118Sfenner * Print AppleTalk LLAP packets.
9417680Spst */
95127675Sbmsu_int
9675118Sfennerllap_print(register const u_char *bp, u_int length)
9717680Spst{
9817680Spst	register const struct LAP *lp;
9917680Spst	register const struct atDDP *dp;
10017680Spst	register const struct atShortDDP *sdp;
10117680Spst	u_short snet;
102127675Sbms	u_int hdrlen;
10317680Spst
104235530Sdelphij	if (length < sizeof(*lp)) {
105235530Sdelphij		(void)printf(" [|llap %u]", length);
106235530Sdelphij		return (length);
107235530Sdelphij	}
10898527Sfenner	lp = (const struct LAP *)bp;
10917680Spst	bp += sizeof(*lp);
11017680Spst	length -= sizeof(*lp);
111127675Sbms	hdrlen = sizeof(*lp);
11217680Spst	switch (lp->type) {
11317680Spst
11417680Spst	case lapShortDDP:
11517680Spst		if (length < ddpSSize) {
116235530Sdelphij			(void)printf(" [|sddp %u]", length);
117127675Sbms			return (length);
11817680Spst		}
11917680Spst		sdp = (const struct atShortDDP *)bp;
12017680Spst		printf("%s.%s",
12117680Spst		    ataddr_string(0, lp->src), ddpskt_string(sdp->srcSkt));
12217680Spst		printf(" > %s.%s:",
12317680Spst		    ataddr_string(0, lp->dst), ddpskt_string(sdp->dstSkt));
12417680Spst		bp += ddpSSize;
12517680Spst		length -= ddpSSize;
126127675Sbms		hdrlen += ddpSSize;
12717680Spst		ddp_print(bp, length, sdp->type, 0, lp->src, sdp->srcSkt);
12817680Spst		break;
12917680Spst
13017680Spst	case lapDDP:
13117680Spst		if (length < ddpSize) {
132235530Sdelphij			(void)printf(" [|ddp %u]", length);
133127675Sbms			return (length);
13417680Spst		}
13517680Spst		dp = (const struct atDDP *)bp;
13617680Spst		snet = EXTRACT_16BITS(&dp->srcNet);
13717680Spst		printf("%s.%s", ataddr_string(snet, dp->srcNode),
13817680Spst		    ddpskt_string(dp->srcSkt));
13917680Spst		printf(" > %s.%s:",
14017680Spst		    ataddr_string(EXTRACT_16BITS(&dp->dstNet), dp->dstNode),
14117680Spst		    ddpskt_string(dp->dstSkt));
14217680Spst		bp += ddpSize;
14317680Spst		length -= ddpSize;
144127675Sbms		hdrlen += ddpSize;
14517680Spst		ddp_print(bp, length, dp->type, snet, dp->srcNode, dp->srcSkt);
14617680Spst		break;
14717680Spst
14817680Spst#ifdef notdef
14917680Spst	case lapKLAP:
15017680Spst		klap_print(bp, length);
15117680Spst		break;
15217680Spst#endif
15317680Spst
15417680Spst	default:
155235530Sdelphij		printf("%d > %d at-lap#%d %u",
15617680Spst		    lp->src, lp->dst, lp->type, length);
15717680Spst		break;
15817680Spst	}
159127675Sbms	return (hdrlen);
16017680Spst}
16117680Spst
16275118Sfenner/*
16375118Sfenner * Print EtherTalk/TokenTalk packets (or FDDITalk, or whatever it's called
16475118Sfenner * when it runs over FDDI; yes, I've seen FDDI captures with AppleTalk
16575118Sfenner * packets in them).
16675118Sfenner */
16775118Sfennervoid
16875118Sfenneratalk_print(register const u_char *bp, u_int length)
16975118Sfenner{
17075118Sfenner	register const struct atDDP *dp;
17175118Sfenner	u_short snet;
17275118Sfenner
173146778Ssam        if(!eflag)
174146778Ssam            printf("AT ");
175146778Ssam
17675118Sfenner	if (length < ddpSize) {
177235530Sdelphij		(void)printf(" [|ddp %u]", length);
17898527Sfenner		return;
17975118Sfenner	}
18075118Sfenner	dp = (const struct atDDP *)bp;
18175118Sfenner	snet = EXTRACT_16BITS(&dp->srcNet);
18275118Sfenner	printf("%s.%s", ataddr_string(snet, dp->srcNode),
18375118Sfenner	       ddpskt_string(dp->srcSkt));
184146778Ssam	printf(" > %s.%s: ",
18575118Sfenner	       ataddr_string(EXTRACT_16BITS(&dp->dstNet), dp->dstNode),
18675118Sfenner	       ddpskt_string(dp->dstSkt));
18775118Sfenner	bp += ddpSize;
18875118Sfenner	length -= ddpSize;
18975118Sfenner	ddp_print(bp, length, dp->type, snet, dp->srcNode, dp->srcSkt);
19075118Sfenner}
19175118Sfenner
19217680Spst/* XXX should probably pass in the snap header and do checks like arp_print() */
19317680Spstvoid
19417680Spstaarp_print(register const u_char *bp, u_int length)
19517680Spst{
19617680Spst	register const struct aarp *ap;
19717680Spst
19817680Spst#define AT(member) ataddr_string((ap->member[1]<<8)|ap->member[2],ap->member[3])
19917680Spst
20017680Spst	printf("aarp ");
20117680Spst	ap = (const struct aarp *)bp;
202127675Sbms	if (EXTRACT_16BITS(&ap->htype) == 1 &&
203127675Sbms	    EXTRACT_16BITS(&ap->ptype) == ETHERTYPE_ATALK &&
20417680Spst	    ap->halen == 6 && ap->palen == 4 )
205127675Sbms		switch (EXTRACT_16BITS(&ap->op)) {
20617680Spst
20717680Spst		case 1:				/* request */
20817680Spst			(void)printf("who-has %s tell %s",
20917680Spst			    AT(pdaddr), AT(psaddr));
21017680Spst			return;
21117680Spst
21217680Spst		case 2:				/* response */
21317680Spst			(void)printf("reply %s is-at %s",
21417690Spst			    AT(psaddr), etheraddr_string(ap->hsaddr));
21517680Spst			return;
21617680Spst
21717680Spst		case 3:				/* probe (oy!) */
21817680Spst			(void)printf("probe %s tell %s",
21917680Spst			    AT(pdaddr), AT(psaddr));
22017680Spst			return;
22117680Spst		}
22275118Sfenner	(void)printf("len %u op %u htype %u ptype %#x halen %u palen %u",
223127675Sbms	    length, EXTRACT_16BITS(&ap->op), EXTRACT_16BITS(&ap->htype),
224127675Sbms	    EXTRACT_16BITS(&ap->ptype), ap->halen, ap->palen);
22517680Spst}
22617680Spst
22775118Sfenner/*
22875118Sfenner * Print AppleTalk Datagram Delivery Protocol packets.
22975118Sfenner */
23017680Spststatic void
23117680Spstddp_print(register const u_char *bp, register u_int length, register int t,
23217680Spst	  register u_short snet, register u_char snode, u_char skt)
23317680Spst{
23417680Spst
23517680Spst	switch (t) {
23617680Spst
23717680Spst	case ddpNBP:
23817680Spst		nbp_print((const struct atNBP *)bp, length, snet, snode, skt);
23917680Spst		break;
24017680Spst
24117680Spst	case ddpATP:
24217680Spst		atp_print((const struct atATP *)bp, length);
24317680Spst		break;
24417680Spst
245146778Ssam	case ddpEIGRP:
246146778Ssam		eigrp_print(bp, length);
247146778Ssam		break;
248146778Ssam
24917680Spst	default:
25017680Spst		(void)printf(" at-%s %d", tok2str(type2str, NULL, t), length);
25117680Spst		break;
25217680Spst	}
25317680Spst}
25417680Spst
25517680Spststatic void
25617680Spstatp_print(register const struct atATP *ap, u_int length)
25717680Spst{
25817680Spst	char c;
25917680Spst	u_int32_t data;
26017680Spst
26117680Spst	if ((const u_char *)(ap + 1) > snapend) {
26217680Spst		/* Just bail if we don't have the whole chunk. */
26317680Spst		fputs(tstr, stdout);
26417680Spst		return;
26517680Spst	}
266235530Sdelphij	if (length < sizeof(*ap)) {
267235530Sdelphij		(void)printf(" [|atp %u]", length);
268235530Sdelphij		return;
269235530Sdelphij	}
27017680Spst	length -= sizeof(*ap);
27117680Spst	switch (ap->control & 0xc0) {
27217680Spst
27317680Spst	case atpReqCode:
27417680Spst		(void)printf(" atp-req%s %d",
27517680Spst			     ap->control & atpXO? " " : "*",
27617680Spst			     EXTRACT_16BITS(&ap->transID));
27717680Spst
27817680Spst		atp_bitmap_print(ap->bitmap);
27917680Spst
28017680Spst		if (length != 0)
281235530Sdelphij			(void)printf(" [len=%u]", length);
28217680Spst
28317680Spst		switch (ap->control & (atpEOM|atpSTS)) {
28417680Spst		case atpEOM:
28517680Spst			(void)printf(" [EOM]");
28617680Spst			break;
28717680Spst		case atpSTS:
28817680Spst			(void)printf(" [STS]");
28917680Spst			break;
29017680Spst		case atpEOM|atpSTS:
29117680Spst			(void)printf(" [EOM,STS]");
29217680Spst			break;
29317680Spst		}
29417680Spst		break;
29517680Spst
29617680Spst	case atpRspCode:
297235530Sdelphij		(void)printf(" atp-resp%s%d:%d (%u)",
29817680Spst			     ap->control & atpEOM? "*" : " ",
29917680Spst			     EXTRACT_16BITS(&ap->transID), ap->bitmap, length);
30017680Spst		switch (ap->control & (atpXO|atpSTS)) {
30117680Spst		case atpXO:
30217680Spst			(void)printf(" [XO]");
30317680Spst			break;
30417680Spst		case atpSTS:
30517680Spst			(void)printf(" [STS]");
30617680Spst			break;
30717680Spst		case atpXO|atpSTS:
30817680Spst			(void)printf(" [XO,STS]");
30917680Spst			break;
31017680Spst		}
31117680Spst		break;
31217680Spst
31317680Spst	case atpRelCode:
31417680Spst		(void)printf(" atp-rel  %d", EXTRACT_16BITS(&ap->transID));
31517680Spst
31617680Spst		atp_bitmap_print(ap->bitmap);
31717680Spst
31817680Spst		/* length should be zero */
31917680Spst		if (length)
320235530Sdelphij			(void)printf(" [len=%u]", length);
32117680Spst
32217680Spst		/* there shouldn't be any control flags */
32317680Spst		if (ap->control & (atpXO|atpEOM|atpSTS)) {
32417680Spst			c = '[';
32517680Spst			if (ap->control & atpXO) {
32617680Spst				(void)printf("%cXO", c);
32717680Spst				c = ',';
32817680Spst			}
32917680Spst			if (ap->control & atpEOM) {
33017680Spst				(void)printf("%cEOM", c);
33117680Spst				c = ',';
33217680Spst			}
33317680Spst			if (ap->control & atpSTS) {
33417680Spst				(void)printf("%cSTS", c);
33517680Spst				c = ',';
33617680Spst			}
33717680Spst			(void)printf("]");
33817680Spst		}
33917680Spst		break;
34017680Spst
34117680Spst	default:
342235530Sdelphij		(void)printf(" atp-0x%x  %d (%u)", ap->control,
34317680Spst			     EXTRACT_16BITS(&ap->transID), length);
34417680Spst		break;
34517680Spst	}
34617680Spst	data = EXTRACT_32BITS(&ap->userData);
34717680Spst	if (data != 0)
34817680Spst		(void)printf(" 0x%x", data);
34917680Spst}
35017680Spst
35117680Spststatic void
35217680Spstatp_bitmap_print(register u_char bm)
35317680Spst{
35417680Spst	register char c;
35517680Spst	register int i;
35617680Spst
35717680Spst	/*
35817680Spst	 * The '& 0xff' below is needed for compilers that want to sign
35917680Spst	 * extend a u_char, which is the case with the Ultrix compiler.
36017680Spst	 * (gcc is smart enough to eliminate it, at least on the Sparc).
36117680Spst	 */
36217680Spst	if ((bm + 1) & (bm & 0xff)) {
36317680Spst		c = '<';
36417680Spst		for (i = 0; bm; ++i) {
36517680Spst			if (bm & 1) {
36617680Spst				(void)printf("%c%d", c, i);
36717680Spst				c = ',';
36817680Spst			}
36917680Spst			bm >>= 1;
37017680Spst		}
37117680Spst		(void)printf(">");
37217680Spst	} else {
37317680Spst		for (i = 0; bm; ++i)
37417680Spst			bm >>= 1;
37517680Spst		if (i > 1)
37617680Spst			(void)printf("<0-%d>", i - 1);
37717680Spst		else
37817680Spst			(void)printf("<0>");
37917680Spst	}
38017680Spst}
38117680Spst
38217680Spststatic void
38317680Spstnbp_print(register const struct atNBP *np, u_int length, register u_short snet,
38417680Spst	  register u_char snode, register u_char skt)
38517680Spst{
38617680Spst	register const struct atNBPtuple *tp =
38798527Sfenner		(const struct atNBPtuple *)((u_char *)np + nbpHeaderSize);
38817680Spst	int i;
38917680Spst	const u_char *ep;
39017680Spst
391111729Sfenner	if (length < nbpHeaderSize) {
392235530Sdelphij		(void)printf(" truncated-nbp %u", length);
393111729Sfenner		return;
394111729Sfenner	}
395111729Sfenner
39617680Spst	length -= nbpHeaderSize;
39717680Spst	if (length < 8) {
39817680Spst		/* must be room for at least one tuple */
399235530Sdelphij		(void)printf(" truncated-nbp %u", length + nbpHeaderSize);
40017680Spst		return;
40117680Spst	}
40217680Spst	/* ep points to end of available data */
40317680Spst	ep = snapend;
40417680Spst	if ((const u_char *)tp > ep) {
40517680Spst		fputs(tstr, stdout);
40617680Spst		return;
40717680Spst	}
40817680Spst	switch (i = np->control & 0xf0) {
40917680Spst
41017680Spst	case nbpBrRq:
41117680Spst	case nbpLkUp:
41217680Spst		(void)printf(i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:",
41317680Spst			     np->id);
41417680Spst		if ((const u_char *)(tp + 1) > ep) {
41517680Spst			fputs(tstr, stdout);
41617680Spst			return;
41717680Spst		}
41817680Spst		(void)nbp_name_print(tp, ep);
41917680Spst		/*
42017680Spst		 * look for anomalies: the spec says there can only
42117680Spst		 * be one tuple, the address must match the source
42217680Spst		 * address and the enumerator should be zero.
42317680Spst		 */
42417680Spst		if ((np->control & 0xf) != 1)
42517680Spst			(void)printf(" [ntup=%d]", np->control & 0xf);
42617680Spst		if (tp->enumerator)
42717680Spst			(void)printf(" [enum=%d]", tp->enumerator);
42817680Spst		if (EXTRACT_16BITS(&tp->net) != snet ||
42917680Spst		    tp->node != snode || tp->skt != skt)
43017680Spst			(void)printf(" [addr=%s.%d]",
43117680Spst			    ataddr_string(EXTRACT_16BITS(&tp->net),
43217680Spst			    tp->node), tp->skt);
43317680Spst		break;
43417680Spst
43517680Spst	case nbpLkUpReply:
43617680Spst		(void)printf(" nbp-reply %d:", np->id);
43717680Spst
43817680Spst		/* print each of the tuples in the reply */
43917680Spst		for (i = np->control & 0xf; --i >= 0 && tp; )
44017680Spst			tp = nbp_tuple_print(tp, ep, snet, snode, skt);
44117680Spst		break;
44217680Spst
44317680Spst	default:
444235530Sdelphij		(void)printf(" nbp-0x%x  %d (%u)", np->control, np->id,
44517680Spst				length);
44617680Spst		break;
44717680Spst	}
44817680Spst}
44917680Spst
45017680Spst/* print a counted string */
45117680Spststatic const char *
45217680Spstprint_cstring(register const char *cp, register const u_char *ep)
45317680Spst{
45417680Spst	register u_int length;
45517680Spst
45617680Spst	if (cp >= (const char *)ep) {
45717680Spst		fputs(tstr, stdout);
45817680Spst		return (0);
45917680Spst	}
46017680Spst	length = *cp++;
46117680Spst
46217680Spst	/* Spec says string can be at most 32 bytes long */
46339300Sfenner	if (length > 32) {
46439300Sfenner		(void)printf("[len=%u]", length);
46517680Spst		return (0);
46617680Spst	}
46739300Sfenner	while ((int)--length >= 0) {
46898527Sfenner		if (cp >= (const char *)ep) {
46917680Spst			fputs(tstr, stdout);
47017680Spst			return (0);
47117680Spst		}
47217680Spst		putchar(*cp++);
47317680Spst	}
47417680Spst	return (cp);
47517680Spst}
47617680Spst
47717680Spststatic const struct atNBPtuple *
47817680Spstnbp_tuple_print(register const struct atNBPtuple *tp,
47917680Spst		register const u_char *ep,
48017680Spst		register u_short snet, register u_char snode,
48117680Spst		register u_char skt)
48217680Spst{
48317680Spst	register const struct atNBPtuple *tpn;
48417680Spst
48517680Spst	if ((const u_char *)(tp + 1) > ep) {
48617680Spst		fputs(tstr, stdout);
48717680Spst		return 0;
48817680Spst	}
48917680Spst	tpn = nbp_name_print(tp, ep);
49017680Spst
49117680Spst	/* if the enumerator isn't 1, print it */
49217680Spst	if (tp->enumerator != 1)
49317680Spst		(void)printf("(%d)", tp->enumerator);
49417680Spst
49517680Spst	/* if the socket doesn't match the src socket, print it */
49617680Spst	if (tp->skt != skt)
49717680Spst		(void)printf(" %d", tp->skt);
49817680Spst
49917680Spst	/* if the address doesn't match the src address, it's an anomaly */
50017680Spst	if (EXTRACT_16BITS(&tp->net) != snet || tp->node != snode)
50117680Spst		(void)printf(" [addr=%s]",
50217680Spst		    ataddr_string(EXTRACT_16BITS(&tp->net), tp->node));
50317680Spst
50417680Spst	return (tpn);
50517680Spst}
50617680Spst
50717680Spststatic const struct atNBPtuple *
50817680Spstnbp_name_print(const struct atNBPtuple *tp, register const u_char *ep)
50917680Spst{
51017680Spst	register const char *cp = (const char *)tp + nbpTupleSize;
51117680Spst
51217680Spst	putchar(' ');
51317680Spst
51417680Spst	/* Object */
51517680Spst	putchar('"');
51617680Spst	if ((cp = print_cstring(cp, ep)) != NULL) {
51717680Spst		/* Type */
51817680Spst		putchar(':');
51917680Spst		if ((cp = print_cstring(cp, ep)) != NULL) {
52017680Spst			/* Zone */
52117680Spst			putchar('@');
52217680Spst			if ((cp = print_cstring(cp, ep)) != NULL)
52317680Spst				putchar('"');
52417680Spst		}
52517680Spst	}
52617680Spst	return ((const struct atNBPtuple *)cp);
52717680Spst}
52817680Spst
52917680Spst
53017680Spst#define HASHNAMESIZE 4096
53117680Spst
53217680Spststruct hnamemem {
53317680Spst	int addr;
53417680Spst	char *name;
53517680Spst	struct hnamemem *nxt;
53617680Spst};
53717680Spst
53817680Spststatic struct hnamemem hnametable[HASHNAMESIZE];
53917680Spst
54017680Spststatic const char *
54117680Spstataddr_string(u_short atnet, u_char athost)
54217680Spst{
54317680Spst	register struct hnamemem *tp, *tp2;
54417680Spst	register int i = (atnet << 8) | athost;
54566644Skris	char nambuf[MAXHOSTNAMELEN + 20];
54617680Spst	static int first = 1;
54717680Spst	FILE *fp;
54817680Spst
54917680Spst	/*
55017680Spst	 * if this is the first call, see if there's an AppleTalk
55117680Spst	 * number to name map file.
55217680Spst	 */
55317680Spst	if (first && (first = 0, !nflag)
55417680Spst	    && (fp = fopen("/etc/atalk.names", "r"))) {
55517680Spst		char line[256];
556235530Sdelphij		int i1, i2;
55717680Spst
55817680Spst		while (fgets(line, sizeof(line), fp)) {
55917680Spst			if (line[0] == '\n' || line[0] == 0 || line[0] == '#')
56017680Spst				continue;
561235530Sdelphij			if (sscanf(line, "%d.%d %256s", &i1, &i2, nambuf) == 3)
56217680Spst				/* got a hostname. */
563235530Sdelphij				i2 |= (i1 << 8);
564235530Sdelphij			else if (sscanf(line, "%d %256s", &i1, nambuf) == 2)
56517680Spst				/* got a net name */
566235530Sdelphij				i2 = (i1 << 8) | 255;
56717680Spst			else
56817680Spst				continue;
56917680Spst
57018241Spst			for (tp = &hnametable[i2 & (HASHNAMESIZE-1)];
57117680Spst			     tp->nxt; tp = tp->nxt)
57217680Spst				;
57318241Spst			tp->addr = i2;
57417680Spst			tp->nxt = newhnamemem();
57598527Sfenner			tp->name = strdup(nambuf);
57617680Spst		}
57717680Spst		fclose(fp);
57817680Spst	}
57917680Spst
58017680Spst	for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
58117680Spst		if (tp->addr == i)
58217680Spst			return (tp->name);
58317680Spst
58417680Spst	/* didn't have the node name -- see if we've got the net name */
58517680Spst	i |= 255;
58617680Spst	for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt)
58717680Spst		if (tp2->addr == i) {
58817680Spst			tp->addr = (atnet << 8) | athost;
58917680Spst			tp->nxt = newhnamemem();
59075118Sfenner			(void)snprintf(nambuf, sizeof(nambuf), "%s.%d",
59175118Sfenner			    tp2->name, athost);
59298527Sfenner			tp->name = strdup(nambuf);
59317680Spst			return (tp->name);
59417680Spst		}
59517680Spst
59617680Spst	tp->addr = (atnet << 8) | athost;
59717680Spst	tp->nxt = newhnamemem();
59817680Spst	if (athost != 255)
599235530Sdelphij		(void)snprintf(nambuf, sizeof(nambuf), "%d.%d", atnet, athost);
60017680Spst	else
601235530Sdelphij		(void)snprintf(nambuf, sizeof(nambuf), "%d", atnet);
60298527Sfenner	tp->name = strdup(nambuf);
60317680Spst
60417680Spst	return (tp->name);
60517680Spst}
60617680Spst
60717680Spststatic struct tok skt2str[] = {
60817680Spst	{ rtmpSkt,	"rtmp" },	/* routing table maintenance */
60917680Spst	{ nbpSkt,	"nis" },	/* name info socket */
61017680Spst	{ echoSkt,	"echo" },	/* AppleTalk echo protocol */
61117680Spst	{ zipSkt,	"zip" },	/* zone info protocol */
61217680Spst	{ 0,		NULL }
61317680Spst};
61417680Spst
61517680Spststatic const char *
61617680Spstddpskt_string(register int skt)
61717680Spst{
61817680Spst	static char buf[8];
61917680Spst
62017680Spst	if (nflag) {
62175118Sfenner		(void)snprintf(buf, sizeof(buf), "%d", skt);
62217680Spst		return (buf);
62317680Spst	}
62417680Spst	return (tok2str(skt2str, "%d", skt));
62517680Spst}
626