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