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