xref: /freebsd/contrib/tcpdump/addrtoname.c (revision 96190b4fef3b4a0cc3ca0606b0c4e3e69a5e6717)
1 /*
2  * Copyright (c) 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  *  Internet, ethernet, port, and protocol string to address
22  *  and address to string conversion routines
23  */
24 
25 #include <config.h>
26 
27 #ifdef HAVE_CASPER
28 #include <libcasper.h>
29 #include <casper/cap_dns.h>
30 #endif /* HAVE_CASPER */
31 
32 #include "netdissect-stdinc.h"
33 
34 #ifdef USE_ETHER_NTOHOST
35   #if defined(NET_ETHERNET_H_DECLARES_ETHER_NTOHOST)
36     /*
37      * OK, just include <net/ethernet.h>.
38      */
39     #include <net/ethernet.h>
40   #elif defined(NETINET_ETHER_H_DECLARES_ETHER_NTOHOST)
41     /*
42      * OK, just include <netinet/ether.h>
43      */
44     #include <netinet/ether.h>
45   #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_NTOHOST)
46     /*
47      * OK, just include <sys/ethernet.h>
48      */
49     #include <sys/ethernet.h>
50   #elif defined(ARPA_INET_H_DECLARES_ETHER_NTOHOST)
51     /*
52      * OK, just include <arpa/inet.h>
53      */
54     #include <arpa/inet.h>
55   #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_NTOHOST)
56     /*
57      * OK, include <netinet/if_ether.h>, after all the other stuff we
58      * need to include or define for its benefit.
59      */
60     #define NEED_NETINET_IF_ETHER_H
61   #else
62     /*
63      * We'll have to declare it ourselves.
64      * If <netinet/if_ether.h> defines struct ether_addr, include
65      * it.  Otherwise, define it ourselves.
66      */
67     #ifdef HAVE_STRUCT_ETHER_ADDR
68       #define NEED_NETINET_IF_ETHER_H
69     #else /* HAVE_STRUCT_ETHER_ADDR */
70 	struct ether_addr {
71 		/* Beware FreeBSD calls this "octet". */
72 		unsigned char ether_addr_octet[MAC_ADDR_LEN];
73 	};
74     #endif /* HAVE_STRUCT_ETHER_ADDR */
75   #endif /* what declares ether_ntohost() */
76 
77   #ifdef NEED_NETINET_IF_ETHER_H
78     /*
79      * Include diag-control.h before <net/if.h>, which too defines a macro
80      * named ND_UNREACHABLE.
81      */
82     #include "diag-control.h"
83     #include <net/if.h>		/* Needed on some platforms */
84     #include <netinet/in.h>	/* Needed on some platforms */
85     #include <netinet/if_ether.h>
86   #endif /* NEED_NETINET_IF_ETHER_H */
87 
88   #ifndef HAVE_DECL_ETHER_NTOHOST
89     /*
90      * No header declares it, so declare it ourselves.
91      */
92     extern int ether_ntohost(char *, const struct ether_addr *);
93   #endif /* !defined(HAVE_DECL_ETHER_NTOHOST) */
94 #endif /* USE_ETHER_NTOHOST */
95 
96 #include <pcap.h>
97 #include <pcap-namedb.h>
98 #ifndef HAVE_GETSERVENT
99 #include <getservent.h>
100 #endif
101 #include <signal.h>
102 #include <stdio.h>
103 #include <string.h>
104 #include <stdlib.h>
105 
106 #include "netdissect.h"
107 #include "addrtoname.h"
108 #include "addrtostr.h"
109 #include "ethertype.h"
110 #include "llc.h"
111 #include "extract.h"
112 #include "oui.h"
113 
114 /*
115  * hash tables for whatever-to-name translations
116  *
117  * ndo_error() called on strdup(3) failure with S_ERR_ND_MEM_ALLOC status
118  */
119 
120 #define HASHNAMESIZE 4096
121 
122 struct hnamemem {
123 	uint32_t addr;
124 	const char *name;
125 	struct hnamemem *nxt;
126 };
127 
128 static struct hnamemem hnametable[HASHNAMESIZE];
129 static struct hnamemem tporttable[HASHNAMESIZE];
130 static struct hnamemem uporttable[HASHNAMESIZE];
131 static struct hnamemem eprototable[HASHNAMESIZE];
132 static struct hnamemem dnaddrtable[HASHNAMESIZE];
133 static struct hnamemem ipxsaptable[HASHNAMESIZE];
134 
135 #ifdef _WIN32
136 /*
137  * fake gethostbyaddr for Win2k/XP
138  * gethostbyaddr() returns incorrect value when AF_INET6 is passed
139  * to 3rd argument.
140  *
141  * h_name in struct hostent is only valid.
142  */
143 static struct hostent *
144 win32_gethostbyaddr(const char *addr, int len, int type)
145 {
146 	static struct hostent host;
147 	static char hostbuf[NI_MAXHOST];
148 	char hname[NI_MAXHOST];
149 	struct sockaddr_in6 addr6;
150 
151 	host.h_name = hostbuf;
152 	switch (type) {
153 	case AF_INET:
154 		return gethostbyaddr(addr, len, type);
155 		break;
156 	case AF_INET6:
157 		memset(&addr6, 0, sizeof(addr6));
158 		addr6.sin6_family = AF_INET6;
159 		memcpy(&addr6.sin6_addr, addr, len);
160 		if (getnameinfo((struct sockaddr *)&addr6, sizeof(addr6),
161 		    hname, sizeof(hname), NULL, 0, 0)) {
162 			return NULL;
163 		} else {
164 			strlcpy(host.h_name, hname, NI_MAXHOST);
165 			return &host;
166 		}
167 		break;
168 	default:
169 		return NULL;
170 	}
171 }
172 #define gethostbyaddr win32_gethostbyaddr
173 #endif /* _WIN32 */
174 
175 struct h6namemem {
176 	nd_ipv6 addr;
177 	char *name;
178 	struct h6namemem *nxt;
179 };
180 
181 static struct h6namemem h6nametable[HASHNAMESIZE];
182 
183 struct enamemem {
184 	u_short e_addr0;
185 	u_short e_addr1;
186 	u_short e_addr2;
187 	const char *e_name;
188 	u_char *e_nsap;			/* used only for nsaptable[] */
189 	struct enamemem *e_nxt;
190 };
191 
192 static struct enamemem enametable[HASHNAMESIZE];
193 static struct enamemem nsaptable[HASHNAMESIZE];
194 
195 struct bsnamemem {
196 	u_short bs_addr0;
197 	u_short bs_addr1;
198 	u_short bs_addr2;
199 	const char *bs_name;
200 	u_char *bs_bytes;
201 	unsigned int bs_nbytes;
202 	struct bsnamemem *bs_nxt;
203 };
204 
205 static struct bsnamemem bytestringtable[HASHNAMESIZE];
206 
207 struct protoidmem {
208 	uint32_t p_oui;
209 	u_short p_proto;
210 	const char *p_name;
211 	struct protoidmem *p_nxt;
212 };
213 
214 static struct protoidmem protoidtable[HASHNAMESIZE];
215 
216 /*
217  * A faster replacement for inet_ntoa().
218  */
219 const char *
220 intoa(uint32_t addr)
221 {
222 	char *cp;
223 	u_int byte;
224 	int n;
225 	static char buf[sizeof(".xxx.xxx.xxx.xxx")];
226 
227 	addr = ntohl(addr);
228 	cp = buf + sizeof(buf);
229 	*--cp = '\0';
230 
231 	n = 4;
232 	do {
233 		byte = addr & 0xff;
234 		*--cp = (char)(byte % 10) + '0';
235 		byte /= 10;
236 		if (byte > 0) {
237 			*--cp = (char)(byte % 10) + '0';
238 			byte /= 10;
239 			if (byte > 0)
240 				*--cp = (char)byte + '0';
241 		}
242 		*--cp = '.';
243 		addr >>= 8;
244 	} while (--n > 0);
245 
246 	return cp + 1;
247 }
248 
249 static uint32_t f_netmask;
250 static uint32_t f_localnet;
251 #ifdef HAVE_CASPER
252 cap_channel_t *capdns;
253 #endif
254 
255 /*
256  * Return a name for the IP address pointed to by ap.  This address
257  * is assumed to be in network byte order.
258  *
259  * NOTE: ap is *NOT* necessarily part of the packet data, so you
260  * *CANNOT* use the ND_TCHECK_* or ND_TTEST_* macros on it.  Furthermore,
261  * even in cases where it *is* part of the packet data, the caller
262  * would still have to check for a null return value, even if it's
263  * just printing the return value with "%s" - not all versions of
264  * printf print "(null)" with "%s" and a null pointer, some of them
265  * don't check for a null pointer and crash in that case.
266  *
267  * The callers of this routine should, before handing this routine
268  * a pointer to packet data, be sure that the data is present in
269  * the packet buffer.  They should probably do those checks anyway,
270  * as other data at that layer might not be IP addresses, and it
271  * also needs to check whether they're present in the packet buffer.
272  */
273 const char *
274 ipaddr_string(netdissect_options *ndo, const u_char *ap)
275 {
276 	struct hostent *hp;
277 	uint32_t addr;
278 	struct hnamemem *p;
279 
280 	memcpy(&addr, ap, sizeof(addr));
281 	p = &hnametable[addr & (HASHNAMESIZE-1)];
282 	for (; p->nxt; p = p->nxt) {
283 		if (p->addr == addr)
284 			return (p->name);
285 	}
286 	p->addr = addr;
287 	p->nxt = newhnamemem(ndo);
288 
289 	/*
290 	 * Print names unless:
291 	 *	(1) -n was given.
292 	 *      (2) Address is foreign and -f was given. (If -f was not
293 	 *	    given, f_netmask and f_localnet are 0 and the test
294 	 *	    evaluates to true)
295 	 */
296 	if (!ndo->ndo_nflag &&
297 	    (addr & f_netmask) == f_localnet) {
298 #ifdef HAVE_CASPER
299 		if (capdns != NULL) {
300 			hp = cap_gethostbyaddr(capdns, (char *)&addr, 4,
301 			    AF_INET);
302 		} else
303 #endif
304 			hp = gethostbyaddr((char *)&addr, 4, AF_INET);
305 		if (hp) {
306 			char *dotp;
307 
308 			p->name = strdup(hp->h_name);
309 			if (p->name == NULL)
310 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
311 					"%s: strdup(hp->h_name)", __func__);
312 			if (ndo->ndo_Nflag) {
313 				/* Remove domain qualifications */
314 				dotp = strchr(p->name, '.');
315 				if (dotp)
316 					*dotp = '\0';
317 			}
318 			return (p->name);
319 		}
320 	}
321 	p->name = strdup(intoa(addr));
322 	if (p->name == NULL)
323 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
324 				  "%s: strdup(intoa(addr))", __func__);
325 	return (p->name);
326 }
327 
328 /*
329  * Return a name for the IP6 address pointed to by ap.  This address
330  * is assumed to be in network byte order.
331  */
332 const char *
333 ip6addr_string(netdissect_options *ndo, const u_char *ap)
334 {
335 	struct hostent *hp;
336 	union {
337 		nd_ipv6 addr;
338 		struct for_hash_addr {
339 			char fill[14];
340 			uint16_t d;
341 		} addra;
342 	} addr;
343 	struct h6namemem *p;
344 	const char *cp;
345 	char ntop_buf[INET6_ADDRSTRLEN];
346 
347 	memcpy(&addr, ap, sizeof(addr));
348 	p = &h6nametable[addr.addra.d & (HASHNAMESIZE-1)];
349 	for (; p->nxt; p = p->nxt) {
350 		if (memcmp(&p->addr, &addr, sizeof(addr)) == 0)
351 			return (p->name);
352 	}
353 	memcpy(p->addr, addr.addr, sizeof(nd_ipv6));
354 	p->nxt = newh6namemem(ndo);
355 
356 	/*
357 	 * Do not print names if -n was given.
358 	 */
359 	if (!ndo->ndo_nflag) {
360 #ifdef HAVE_CASPER
361 		if (capdns != NULL) {
362 			hp = cap_gethostbyaddr(capdns, (char *)&addr,
363 			    sizeof(addr), AF_INET6);
364 		} else
365 #endif
366 			hp = gethostbyaddr((char *)&addr, sizeof(addr),
367 			    AF_INET6);
368 		if (hp) {
369 			char *dotp;
370 
371 			p->name = strdup(hp->h_name);
372 			if (p->name == NULL)
373 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
374 					"%s: strdup(hp->h_name)", __func__);
375 			if (ndo->ndo_Nflag) {
376 				/* Remove domain qualifications */
377 				dotp = strchr(p->name, '.');
378 				if (dotp)
379 					*dotp = '\0';
380 			}
381 			return (p->name);
382 		}
383 	}
384 	cp = addrtostr6(ap, ntop_buf, sizeof(ntop_buf));
385 	p->name = strdup(cp);
386 	if (p->name == NULL)
387 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
388 				  "%s: strdup(cp)", __func__);
389 	return (p->name);
390 }
391 
392 static const char hex[16] = {
393 	'0', '1', '2', '3', '4', '5', '6', '7',
394 	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
395 };
396 
397 /*
398  * Convert an octet to two hex digits.
399  *
400  * Coverity appears either:
401  *
402  *    not to believe the C standard when it asserts that a uint8_t is
403  *    exactly 8 bits in size;
404  *
405  *    not to believe that an unsigned type of exactly 8 bits has a value
406  *    in the range of 0 to 255;
407  *
408  *    not to believe that, for a range of unsigned values, if you shift
409  *    one of those values right by 4 bits, the maximum result value is
410  *    the maximum value shifted right by 4 bits, with no stray 1's shifted
411  *    in;
412  *
413  *    not to believe that 255 >> 4 is 15;
414  *
415  * so it gets upset that we're taking a "tainted" unsigned value, shifting
416  * it right 4 bits, and using it as an index into a 16-element array.
417  *
418  * So we do a stupid pointless masking of the result of the shift with
419  * 0xf, to hammer the point home to Coverity.
420  */
421 static inline char *
422 octet_to_hex(char *cp, uint8_t octet)
423 {
424 	*cp++ = hex[(octet >> 4) & 0xf];
425 	*cp++ = hex[(octet >> 0) & 0xf];
426 	return (cp);
427 }
428 
429 /* Find the hash node that corresponds the ether address 'ep' */
430 
431 static struct enamemem *
432 lookup_emem(netdissect_options *ndo, const u_char *ep)
433 {
434 	u_int i, j, k;
435 	struct enamemem *tp;
436 
437 	k = (ep[0] << 8) | ep[1];
438 	j = (ep[2] << 8) | ep[3];
439 	i = (ep[4] << 8) | ep[5];
440 
441 	tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
442 	while (tp->e_nxt)
443 		if (tp->e_addr0 == i &&
444 		    tp->e_addr1 == j &&
445 		    tp->e_addr2 == k)
446 			return tp;
447 		else
448 			tp = tp->e_nxt;
449 	tp->e_addr0 = (u_short)i;
450 	tp->e_addr1 = (u_short)j;
451 	tp->e_addr2 = (u_short)k;
452 	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
453 	if (tp->e_nxt == NULL)
454 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "%s: calloc", __func__);
455 
456 	return tp;
457 }
458 
459 /*
460  * Find the hash node that corresponds to the bytestring 'bs'
461  * with length 'nlen'
462  */
463 
464 static struct bsnamemem *
465 lookup_bytestring(netdissect_options *ndo, const u_char *bs,
466 		  const unsigned int nlen)
467 {
468 	struct bsnamemem *tp;
469 	u_int i, j, k;
470 
471 	if (nlen >= 6) {
472 		k = (bs[0] << 8) | bs[1];
473 		j = (bs[2] << 8) | bs[3];
474 		i = (bs[4] << 8) | bs[5];
475 	} else if (nlen >= 4) {
476 		k = (bs[0] << 8) | bs[1];
477 		j = (bs[2] << 8) | bs[3];
478 		i = 0;
479 	} else
480 		i = j = k = 0;
481 
482 	tp = &bytestringtable[(i ^ j) & (HASHNAMESIZE-1)];
483 	while (tp->bs_nxt)
484 		if (nlen == tp->bs_nbytes &&
485 		    tp->bs_addr0 == i &&
486 		    tp->bs_addr1 == j &&
487 		    tp->bs_addr2 == k &&
488 		    memcmp((const char *)bs, (const char *)(tp->bs_bytes), nlen) == 0)
489 			return tp;
490 		else
491 			tp = tp->bs_nxt;
492 
493 	tp->bs_addr0 = (u_short)i;
494 	tp->bs_addr1 = (u_short)j;
495 	tp->bs_addr2 = (u_short)k;
496 
497 	tp->bs_bytes = (u_char *) calloc(1, nlen);
498 	if (tp->bs_bytes == NULL)
499 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
500 				  "%s: calloc", __func__);
501 
502 	memcpy(tp->bs_bytes, bs, nlen);
503 	tp->bs_nbytes = nlen;
504 	tp->bs_nxt = (struct bsnamemem *)calloc(1, sizeof(*tp));
505 	if (tp->bs_nxt == NULL)
506 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
507 				  "%s: calloc", __func__);
508 
509 	return tp;
510 }
511 
512 /* Find the hash node that corresponds the NSAP 'nsap' */
513 
514 static struct enamemem *
515 lookup_nsap(netdissect_options *ndo, const u_char *nsap,
516 	    u_int nsap_length)
517 {
518 	u_int i, j, k;
519 	struct enamemem *tp;
520 	const u_char *ensap;
521 
522 	if (nsap_length > 6) {
523 		ensap = nsap + nsap_length - 6;
524 		k = (ensap[0] << 8) | ensap[1];
525 		j = (ensap[2] << 8) | ensap[3];
526 		i = (ensap[4] << 8) | ensap[5];
527 	} else
528 		i = j = k = 0;
529 
530 	tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
531 	while (tp->e_nxt)
532 		if (nsap_length == tp->e_nsap[0] &&
533 		    tp->e_addr0 == i &&
534 		    tp->e_addr1 == j &&
535 		    tp->e_addr2 == k &&
536 		    memcmp((const char *)nsap,
537 			(char *)&(tp->e_nsap[1]), nsap_length) == 0)
538 			return tp;
539 		else
540 			tp = tp->e_nxt;
541 	tp->e_addr0 = (u_short)i;
542 	tp->e_addr1 = (u_short)j;
543 	tp->e_addr2 = (u_short)k;
544 	tp->e_nsap = (u_char *)malloc(nsap_length + 1);
545 	if (tp->e_nsap == NULL)
546 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "%s: malloc", __func__);
547 	tp->e_nsap[0] = (u_char)nsap_length;	/* guaranteed < ISONSAP_MAX_LENGTH */
548 	memcpy((char *)&tp->e_nsap[1], (const char *)nsap, nsap_length);
549 	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
550 	if (tp->e_nxt == NULL)
551 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "%s: calloc", __func__);
552 
553 	return tp;
554 }
555 
556 /* Find the hash node that corresponds the protoid 'pi'. */
557 
558 static struct protoidmem *
559 lookup_protoid(netdissect_options *ndo, const u_char *pi)
560 {
561 	u_int i, j;
562 	struct protoidmem *tp;
563 
564 	/* 5 octets won't be aligned */
565 	i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
566 	j =   (pi[3] << 8) + pi[4];
567 	/* XXX should be endian-insensitive, but do big-endian testing  XXX */
568 
569 	tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
570 	while (tp->p_nxt)
571 		if (tp->p_oui == i && tp->p_proto == j)
572 			return tp;
573 		else
574 			tp = tp->p_nxt;
575 	tp->p_oui = i;
576 	tp->p_proto = (u_short)j;
577 	tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
578 	if (tp->p_nxt == NULL)
579 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "%s: calloc", __func__);
580 
581 	return tp;
582 }
583 
584 const char *
585 etheraddr_string(netdissect_options *ndo, const uint8_t *ep)
586 {
587 	int i;
588 	char *cp;
589 	struct enamemem *tp;
590 	int oui;
591 	char buf[BUFSIZE];
592 
593 	tp = lookup_emem(ndo, ep);
594 	if (tp->e_name)
595 		return (tp->e_name);
596 #ifdef USE_ETHER_NTOHOST
597 	if (!ndo->ndo_nflag) {
598 		char buf2[BUFSIZE];
599 		/*
600 		 * This is a non-const copy of ep for ether_ntohost(), which
601 		 * has its second argument non-const in OpenBSD. Also saves a
602 		 * type cast.
603 		 */
604 		struct ether_addr ea;
605 
606 		memcpy (&ea, ep, MAC_ADDR_LEN);
607 		if (ether_ntohost(buf2, &ea) == 0) {
608 			tp->e_name = strdup(buf2);
609 			if (tp->e_name == NULL)
610 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
611 					"%s: strdup(buf2)", __func__);
612 			return (tp->e_name);
613 		}
614 	}
615 #endif
616 	cp = buf;
617 	oui = EXTRACT_BE_U_3(ep);
618 	cp = octet_to_hex(cp, *ep++);
619 	for (i = 5; --i >= 0;) {
620 		*cp++ = ':';
621 		cp = octet_to_hex(cp, *ep++);
622 	}
623 
624 	if (!ndo->ndo_nflag) {
625 		snprintf(cp, BUFSIZE - (2 + 5*3), " (oui %s)",
626 		    tok2str(oui_values, "Unknown", oui));
627 	} else
628 		*cp = '\0';
629 	tp->e_name = strdup(buf);
630 	if (tp->e_name == NULL)
631 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
632 				  "%s: strdup(buf)", __func__);
633 	return (tp->e_name);
634 }
635 
636 const char *
637 le64addr_string(netdissect_options *ndo, const uint8_t *ep)
638 {
639 	const unsigned int len = 8;
640 	u_int i;
641 	char *cp;
642 	struct bsnamemem *tp;
643 	char buf[BUFSIZE];
644 
645 	tp = lookup_bytestring(ndo, ep, len);
646 	if (tp->bs_name)
647 		return (tp->bs_name);
648 
649 	cp = buf;
650 	for (i = len; i > 0 ; --i) {
651 		cp = octet_to_hex(cp, *(ep + i - 1));
652 		*cp++ = ':';
653 	}
654 	cp --;
655 
656 	*cp = '\0';
657 
658 	tp->bs_name = strdup(buf);
659 	if (tp->bs_name == NULL)
660 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
661 				  "%s: strdup(buf)", __func__);
662 
663 	return (tp->bs_name);
664 }
665 
666 const char *
667 linkaddr_string(netdissect_options *ndo, const uint8_t *ep,
668 		const unsigned int type, const unsigned int len)
669 {
670 	u_int i;
671 	char *cp;
672 	struct bsnamemem *tp;
673 
674 	if (len == 0)
675 		return ("<empty>");
676 
677 	if (type == LINKADDR_ETHER && len == MAC_ADDR_LEN)
678 		return (etheraddr_string(ndo, ep));
679 
680 	if (type == LINKADDR_FRELAY)
681 		return (q922_string(ndo, ep, len));
682 
683 	tp = lookup_bytestring(ndo, ep, len);
684 	if (tp->bs_name)
685 		return (tp->bs_name);
686 
687 	tp->bs_name = cp = (char *)malloc(len*3);
688 	if (tp->bs_name == NULL)
689 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
690 				  "%s: malloc", __func__);
691 	cp = octet_to_hex(cp, *ep++);
692 	for (i = len-1; i > 0 ; --i) {
693 		*cp++ = ':';
694 		cp = octet_to_hex(cp, *ep++);
695 	}
696 	*cp = '\0';
697 	return (tp->bs_name);
698 }
699 
700 #define ISONSAP_MAX_LENGTH 20
701 const char *
702 isonsap_string(netdissect_options *ndo, const uint8_t *nsap,
703 	       u_int nsap_length)
704 {
705 	u_int nsap_idx;
706 	char *cp;
707 	struct enamemem *tp;
708 
709 	if (nsap_length < 1 || nsap_length > ISONSAP_MAX_LENGTH)
710 		return ("isonsap_string: illegal length");
711 
712 	tp = lookup_nsap(ndo, nsap, nsap_length);
713 	if (tp->e_name)
714 		return tp->e_name;
715 
716 	tp->e_name = cp = (char *)malloc(sizeof("xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx"));
717 	if (cp == NULL)
718 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
719 				  "%s: malloc", __func__);
720 
721 	for (nsap_idx = 0; nsap_idx < nsap_length; nsap_idx++) {
722 		cp = octet_to_hex(cp, *nsap++);
723 		if (((nsap_idx & 1) == 0) &&
724 		     (nsap_idx + 1 < nsap_length)) {
725 			*cp++ = '.';
726 		}
727 	}
728 	*cp = '\0';
729 	return (tp->e_name);
730 }
731 
732 const char *
733 tcpport_string(netdissect_options *ndo, u_short port)
734 {
735 	struct hnamemem *tp;
736 	uint32_t i = port;
737 	char buf[sizeof("00000")];
738 
739 	for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
740 		if (tp->addr == i)
741 			return (tp->name);
742 
743 	tp->addr = i;
744 	tp->nxt = newhnamemem(ndo);
745 
746 	(void)snprintf(buf, sizeof(buf), "%u", i);
747 	tp->name = strdup(buf);
748 	if (tp->name == NULL)
749 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
750 				  "%s: strdup(buf)", __func__);
751 	return (tp->name);
752 }
753 
754 const char *
755 udpport_string(netdissect_options *ndo, u_short port)
756 {
757 	struct hnamemem *tp;
758 	uint32_t i = port;
759 	char buf[sizeof("00000")];
760 
761 	for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
762 		if (tp->addr == i)
763 			return (tp->name);
764 
765 	tp->addr = i;
766 	tp->nxt = newhnamemem(ndo);
767 
768 	(void)snprintf(buf, sizeof(buf), "%u", i);
769 	tp->name = strdup(buf);
770 	if (tp->name == NULL)
771 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
772 				  "%s: strdup(buf)", __func__);
773 	return (tp->name);
774 }
775 
776 const char *
777 ipxsap_string(netdissect_options *ndo, u_short port)
778 {
779 	char *cp;
780 	struct hnamemem *tp;
781 	uint32_t i = port;
782 	char buf[sizeof("0000")];
783 
784 	for (tp = &ipxsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
785 		if (tp->addr == i)
786 			return (tp->name);
787 
788 	tp->addr = i;
789 	tp->nxt = newhnamemem(ndo);
790 
791 	cp = buf;
792 	port = ntohs(port);
793 	*cp++ = hex[port >> 12 & 0xf];
794 	*cp++ = hex[port >> 8 & 0xf];
795 	*cp++ = hex[port >> 4 & 0xf];
796 	*cp++ = hex[port & 0xf];
797 	*cp++ = '\0';
798 	tp->name = strdup(buf);
799 	if (tp->name == NULL)
800 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
801 				  "%s: strdup(buf)", __func__);
802 	return (tp->name);
803 }
804 
805 static void
806 init_servarray(netdissect_options *ndo)
807 {
808 	struct servent *sv;
809 	struct hnamemem *table;
810 	int i;
811 	char buf[sizeof("0000000000")];
812 
813 	while ((sv = getservent()) != NULL) {
814 		int port = ntohs(sv->s_port);
815 		i = port & (HASHNAMESIZE-1);
816 		if (strcmp(sv->s_proto, "tcp") == 0)
817 			table = &tporttable[i];
818 		else if (strcmp(sv->s_proto, "udp") == 0)
819 			table = &uporttable[i];
820 		else
821 			continue;
822 
823 		while (table->name)
824 			table = table->nxt;
825 		if (ndo->ndo_nflag) {
826 			(void)snprintf(buf, sizeof(buf), "%d", port);
827 			table->name = strdup(buf);
828 		} else
829 			table->name = strdup(sv->s_name);
830 		if (table->name == NULL)
831 			(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
832 					  "%s: strdup", __func__);
833 
834 		table->addr = port;
835 		table->nxt = newhnamemem(ndo);
836 	}
837 	endservent();
838 }
839 
840 static const struct eproto {
841 	const char *s;
842 	u_short p;
843 } eproto_db[] = {
844 	{ "aarp", ETHERTYPE_AARP },
845 	{ "arp", ETHERTYPE_ARP },
846 	{ "atalk", ETHERTYPE_ATALK },
847 	{ "decnet", ETHERTYPE_DN },
848 	{ "ip", ETHERTYPE_IP },
849 	{ "ip6", ETHERTYPE_IPV6 },
850 	{ "lat", ETHERTYPE_LAT },
851 	{ "loopback", ETHERTYPE_LOOPBACK },
852 	{ "mopdl", ETHERTYPE_MOPDL },
853 	{ "moprc", ETHERTYPE_MOPRC },
854 	{ "rarp", ETHERTYPE_REVARP },
855 	{ "sca", ETHERTYPE_SCA },
856 	{ (char *)0, 0 }
857 };
858 
859 static void
860 init_eprotoarray(netdissect_options *ndo)
861 {
862 	int i;
863 	struct hnamemem *table;
864 
865 	for (i = 0; eproto_db[i].s; i++) {
866 		int j = htons(eproto_db[i].p) & (HASHNAMESIZE-1);
867 		table = &eprototable[j];
868 		while (table->name)
869 			table = table->nxt;
870 		table->name = eproto_db[i].s;
871 		table->addr = htons(eproto_db[i].p);
872 		table->nxt = newhnamemem(ndo);
873 	}
874 }
875 
876 static const struct protoidlist {
877 	const u_char protoid[5];
878 	const char *name;
879 } protoidlist[] = {
880 	{{ 0x00, 0x00, 0x0c, 0x01, 0x07 }, "CiscoMLS" },
881 	{{ 0x00, 0x00, 0x0c, 0x20, 0x00 }, "CiscoCDP" },
882 	{{ 0x00, 0x00, 0x0c, 0x20, 0x01 }, "CiscoCGMP" },
883 	{{ 0x00, 0x00, 0x0c, 0x20, 0x03 }, "CiscoVTP" },
884 	{{ 0x00, 0xe0, 0x2b, 0x00, 0xbb }, "ExtremeEDP" },
885 	{{ 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
886 };
887 
888 /*
889  * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
890  * types.
891  */
892 static void
893 init_protoidarray(netdissect_options *ndo)
894 {
895 	int i;
896 	struct protoidmem *tp;
897 	const struct protoidlist *pl;
898 	u_char protoid[5];
899 
900 	protoid[0] = 0;
901 	protoid[1] = 0;
902 	protoid[2] = 0;
903 	for (i = 0; eproto_db[i].s; i++) {
904 		u_short etype = htons(eproto_db[i].p);
905 
906 		memcpy((char *)&protoid[3], (char *)&etype, 2);
907 		tp = lookup_protoid(ndo, protoid);
908 		tp->p_name = strdup(eproto_db[i].s);
909 		if (tp->p_name == NULL)
910 			(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
911 				"%s: strdup(eproto_db[i].s)", __func__);
912 	}
913 	/* Hardwire some SNAP proto ID names */
914 	for (pl = protoidlist; pl->name != NULL; ++pl) {
915 		tp = lookup_protoid(ndo, pl->protoid);
916 		/* Don't override existing name */
917 		if (tp->p_name != NULL)
918 			continue;
919 
920 		tp->p_name = pl->name;
921 	}
922 }
923 
924 static const struct etherlist {
925 	const nd_mac_addr addr;
926 	const char *name;
927 } etherlist[] = {
928 	{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
929 	{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
930 };
931 
932 /*
933  * Initialize the ethers hash table.  We take two different approaches
934  * depending on whether or not the system provides the ethers name
935  * service.  If it does, we just wire in a few names at startup,
936  * and etheraddr_string() fills in the table on demand.  If it doesn't,
937  * then we suck in the entire /etc/ethers file at startup.  The idea
938  * is that parsing the local file will be fast, but spinning through
939  * all the ethers entries via NIS & next_etherent might be very slow.
940  *
941  * XXX pcap_next_etherent doesn't belong in the pcap interface, but
942  * since the pcap module already does name-to-address translation,
943  * it's already does most of the work for the ethernet address-to-name
944  * translation, so we just pcap_next_etherent as a convenience.
945  */
946 static void
947 init_etherarray(netdissect_options *ndo)
948 {
949 	const struct etherlist *el;
950 	struct enamemem *tp;
951 #ifdef USE_ETHER_NTOHOST
952 	char name[256];
953 #else
954 	struct pcap_etherent *ep;
955 	FILE *fp;
956 
957 	/* Suck in entire ethers file */
958 	fp = fopen(PCAP_ETHERS_FILE, "r");
959 	if (fp != NULL) {
960 		while ((ep = pcap_next_etherent(fp)) != NULL) {
961 			tp = lookup_emem(ndo, ep->addr);
962 			tp->e_name = strdup(ep->name);
963 			if (tp->e_name == NULL)
964 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
965 					"%s: strdup(ep->addr)", __func__);
966 		}
967 		(void)fclose(fp);
968 	}
969 #endif
970 
971 	/* Hardwire some ethernet names */
972 	for (el = etherlist; el->name != NULL; ++el) {
973 		tp = lookup_emem(ndo, el->addr);
974 		/* Don't override existing name */
975 		if (tp->e_name != NULL)
976 			continue;
977 
978 #ifdef USE_ETHER_NTOHOST
979 		/*
980 		 * Use YP/NIS version of name if available.
981 		 */
982 		/* Same workaround as in etheraddr_string(). */
983 		struct ether_addr ea;
984 		memcpy (&ea, el->addr, MAC_ADDR_LEN);
985 		if (ether_ntohost(name, &ea) == 0) {
986 			tp->e_name = strdup(name);
987 			if (tp->e_name == NULL)
988 				(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
989 					"%s: strdup(name)", __func__);
990 			continue;
991 		}
992 #endif
993 		tp->e_name = el->name;
994 	}
995 }
996 
997 static const struct ipxsap_ent {
998 	uint16_t	v;
999 	const char	*s;
1000 } ipxsap_db[] = {
1001 	{ 0x0000, "Unknown" },
1002 	{ 0x0001, "User" },
1003 	{ 0x0002, "User Group" },
1004 	{ 0x0003, "PrintQueue" },
1005 	{ 0x0004, "FileServer" },
1006 	{ 0x0005, "JobServer" },
1007 	{ 0x0006, "Gateway" },
1008 	{ 0x0007, "PrintServer" },
1009 	{ 0x0008, "ArchiveQueue" },
1010 	{ 0x0009, "ArchiveServer" },
1011 	{ 0x000a, "JobQueue" },
1012 	{ 0x000b, "Administration" },
1013 	{ 0x000F, "Novell TI-RPC" },
1014 	{ 0x0017, "Diagnostics" },
1015 	{ 0x0020, "NetBIOS" },
1016 	{ 0x0021, "NAS SNA Gateway" },
1017 	{ 0x0023, "NACS AsyncGateway" },
1018 	{ 0x0024, "RemoteBridge/RoutingService" },
1019 	{ 0x0026, "BridgeServer" },
1020 	{ 0x0027, "TCP/IP Gateway" },
1021 	{ 0x0028, "Point-to-point X.25 BridgeServer" },
1022 	{ 0x0029, "3270 Gateway" },
1023 	{ 0x002a, "CHI Corp" },
1024 	{ 0x002c, "PC Chalkboard" },
1025 	{ 0x002d, "TimeSynchServer" },
1026 	{ 0x002e, "ARCserve5.0/PalindromeBackup" },
1027 	{ 0x0045, "DI3270 Gateway" },
1028 	{ 0x0047, "AdvertisingPrintServer" },
1029 	{ 0x004a, "NetBlazerModems" },
1030 	{ 0x004b, "BtrieveVAP" },
1031 	{ 0x004c, "NetwareSQL" },
1032 	{ 0x004d, "XtreeNetwork" },
1033 	{ 0x0050, "BtrieveVAP4.11" },
1034 	{ 0x0052, "QuickLink" },
1035 	{ 0x0053, "PrintQueueUser" },
1036 	{ 0x0058, "Multipoint X.25 Router" },
1037 	{ 0x0060, "STLB/NLM" },
1038 	{ 0x0064, "ARCserve" },
1039 	{ 0x0066, "ARCserve3.0" },
1040 	{ 0x0072, "WAN CopyUtility" },
1041 	{ 0x007a, "TES-NetwareVMS" },
1042 	{ 0x0092, "WATCOM Debugger/EmeraldTapeBackupServer" },
1043 	{ 0x0095, "DDA OBGYN" },
1044 	{ 0x0098, "NetwareAccessServer" },
1045 	{ 0x009a, "Netware for VMS II/NamedPipeServer" },
1046 	{ 0x009b, "NetwareAccessServer" },
1047 	{ 0x009e, "PortableNetwareServer/SunLinkNVT" },
1048 	{ 0x00a1, "PowerchuteAPC UPS" },
1049 	{ 0x00aa, "LAWserve" },
1050 	{ 0x00ac, "CompaqIDA StatusMonitor" },
1051 	{ 0x0100, "PIPE STAIL" },
1052 	{ 0x0102, "LAN ProtectBindery" },
1053 	{ 0x0103, "OracleDataBaseServer" },
1054 	{ 0x0107, "Netware386/RSPX RemoteConsole" },
1055 	{ 0x010f, "NovellSNA Gateway" },
1056 	{ 0x0111, "TestServer" },
1057 	{ 0x0112, "HP PrintServer" },
1058 	{ 0x0114, "CSA MUX" },
1059 	{ 0x0115, "CSA LCA" },
1060 	{ 0x0116, "CSA CM" },
1061 	{ 0x0117, "CSA SMA" },
1062 	{ 0x0118, "CSA DBA" },
1063 	{ 0x0119, "CSA NMA" },
1064 	{ 0x011a, "CSA SSA" },
1065 	{ 0x011b, "CSA STATUS" },
1066 	{ 0x011e, "CSA APPC" },
1067 	{ 0x0126, "SNA TEST SSA Profile" },
1068 	{ 0x012a, "CSA TRACE" },
1069 	{ 0x012b, "NetwareSAA" },
1070 	{ 0x012e, "IKARUS VirusScan" },
1071 	{ 0x0130, "CommunicationsExecutive" },
1072 	{ 0x0133, "NNS DomainServer/NetwareNamingServicesDomain" },
1073 	{ 0x0135, "NetwareNamingServicesProfile" },
1074 	{ 0x0137, "Netware386 PrintQueue/NNS PrintQueue" },
1075 	{ 0x0141, "LAN SpoolServer" },
1076 	{ 0x0152, "IRMALAN Gateway" },
1077 	{ 0x0154, "NamedPipeServer" },
1078 	{ 0x0166, "NetWareManagement" },
1079 	{ 0x0168, "Intel PICKIT CommServer/Intel CAS TalkServer" },
1080 	{ 0x0173, "Compaq" },
1081 	{ 0x0174, "Compaq SNMP Agent" },
1082 	{ 0x0175, "Compaq" },
1083 	{ 0x0180, "XTreeServer/XTreeTools" },
1084 	{ 0x018A, "NASI ServicesBroadcastServer" },
1085 	{ 0x01b0, "GARP Gateway" },
1086 	{ 0x01b1, "Binfview" },
1087 	{ 0x01bf, "IntelLanDeskManager" },
1088 	{ 0x01ca, "AXTEC" },
1089 	{ 0x01cb, "ShivaNetModem/E" },
1090 	{ 0x01cc, "ShivaLanRover/E" },
1091 	{ 0x01cd, "ShivaLanRover/T" },
1092 	{ 0x01ce, "ShivaUniversal" },
1093 	{ 0x01d8, "CastelleFAXPressServer" },
1094 	{ 0x01da, "CastelleLANPressPrintServer" },
1095 	{ 0x01dc, "CastelleFAX/Xerox7033 FaxServer/ExcelLanFax" },
1096 	{ 0x01f0, "LEGATO" },
1097 	{ 0x01f5, "LEGATO" },
1098 	{ 0x0233, "NMS Agent/NetwareManagementAgent" },
1099 	{ 0x0237, "NMS IPX Discovery/LANternReadWriteChannel" },
1100 	{ 0x0238, "NMS IP Discovery/LANternTrapAlarmChannel" },
1101 	{ 0x023a, "LANtern" },
1102 	{ 0x023c, "MAVERICK" },
1103 	{ 0x023f, "NovellSMDR" },
1104 	{ 0x024e, "NetwareConnect" },
1105 	{ 0x024f, "NASI ServerBroadcast Cisco" },
1106 	{ 0x026a, "NMS ServiceConsole" },
1107 	{ 0x026b, "TimeSynchronizationServer Netware 4.x" },
1108 	{ 0x0278, "DirectoryServer Netware 4.x" },
1109 	{ 0x027b, "NetwareManagementAgent" },
1110 	{ 0x0280, "Novell File and Printer Sharing Service for PC" },
1111 	{ 0x0304, "NovellSAA Gateway" },
1112 	{ 0x0308, "COM/VERMED" },
1113 	{ 0x030a, "GalacticommWorldgroupServer" },
1114 	{ 0x030c, "IntelNetport2/HP JetDirect/HP Quicksilver" },
1115 	{ 0x0320, "AttachmateGateway" },
1116 	{ 0x0327, "MicrosoftDiagnostics" },
1117 	{ 0x0328, "WATCOM SQL Server" },
1118 	{ 0x0335, "MultiTechSystems MultisynchCommServer" },
1119 	{ 0x0343, "Xylogics RemoteAccessServer/LANModem" },
1120 	{ 0x0355, "ArcadaBackupExec" },
1121 	{ 0x0358, "MSLCD1" },
1122 	{ 0x0361, "NETINELO" },
1123 	{ 0x037e, "Powerchute UPS Monitoring" },
1124 	{ 0x037f, "ViruSafeNotify" },
1125 	{ 0x0386, "HP Bridge" },
1126 	{ 0x0387, "HP Hub" },
1127 	{ 0x0394, "NetWare SAA Gateway" },
1128 	{ 0x039b, "LotusNotes" },
1129 	{ 0x03b7, "CertusAntiVirus" },
1130 	{ 0x03c4, "ARCserve4.0" },
1131 	{ 0x03c7, "LANspool3.5" },
1132 	{ 0x03d7, "LexmarkPrinterServer" },
1133 	{ 0x03d8, "LexmarkXLE PrinterServer" },
1134 	{ 0x03dd, "BanyanENS NetwareClient" },
1135 	{ 0x03de, "GuptaSequelBaseServer/NetWareSQL" },
1136 	{ 0x03e1, "UnivelUnixware" },
1137 	{ 0x03e4, "UnivelUnixware" },
1138 	{ 0x03fc, "IntelNetport" },
1139 	{ 0x03fd, "PrintServerQueue" },
1140 	{ 0x040A, "ipnServer" },
1141 	{ 0x040D, "LVERRMAN" },
1142 	{ 0x040E, "LVLIC" },
1143 	{ 0x0414, "NET Silicon (DPI)/Kyocera" },
1144 	{ 0x0429, "SiteLockVirus" },
1145 	{ 0x0432, "UFHELPR???" },
1146 	{ 0x0433, "Synoptics281xAdvancedSNMPAgent" },
1147 	{ 0x0444, "MicrosoftNT SNA Server" },
1148 	{ 0x0448, "Oracle" },
1149 	{ 0x044c, "ARCserve5.01" },
1150 	{ 0x0457, "CanonGP55" },
1151 	{ 0x045a, "QMS Printers" },
1152 	{ 0x045b, "DellSCSI Array" },
1153 	{ 0x0491, "NetBlazerModems" },
1154 	{ 0x04ac, "OnTimeScheduler" },
1155 	{ 0x04b0, "CD-Net" },
1156 	{ 0x0513, "EmulexNQA" },
1157 	{ 0x0520, "SiteLockChecks" },
1158 	{ 0x0529, "SiteLockChecks" },
1159 	{ 0x052d, "CitrixOS2 AppServer" },
1160 	{ 0x0535, "Tektronix" },
1161 	{ 0x0536, "Milan" },
1162 	{ 0x055d, "Attachmate SNA gateway" },
1163 	{ 0x056b, "IBM8235 ModemServer" },
1164 	{ 0x056c, "ShivaLanRover/E PLUS" },
1165 	{ 0x056d, "ShivaLanRover/T PLUS" },
1166 	{ 0x0580, "McAfeeNetShield" },
1167 	{ 0x05B8, "NLM to workstation communication (Revelation Software)" },
1168 	{ 0x05BA, "CompatibleSystemsRouters" },
1169 	{ 0x05BE, "CheyenneHierarchicalStorageManager" },
1170 	{ 0x0606, "JCWatermarkImaging" },
1171 	{ 0x060c, "AXISNetworkPrinter" },
1172 	{ 0x0610, "AdaptecSCSIManagement" },
1173 	{ 0x0621, "IBM AntiVirus" },
1174 	{ 0x0640, "Windows95 RemoteRegistryService" },
1175 	{ 0x064e, "MicrosoftIIS" },
1176 	{ 0x067b, "Microsoft Win95/98 File and Print Sharing for NetWare" },
1177 	{ 0x067c, "Microsoft Win95/98 File and Print Sharing for NetWare" },
1178 	{ 0x076C, "Xerox" },
1179 	{ 0x079b, "ShivaLanRover/E 115" },
1180 	{ 0x079c, "ShivaLanRover/T 115" },
1181 	{ 0x07B4, "CubixWorldDesk" },
1182 	{ 0x07c2, "Quarterdeck IWare Connect V2.x NLM" },
1183 	{ 0x07c1, "Quarterdeck IWare Connect V3.x NLM" },
1184 	{ 0x0810, "ELAN License Server Demo" },
1185 	{ 0x0824, "ShivaLanRoverAccessSwitch/E" },
1186 	{ 0x086a, "ISSC Collector" },
1187 	{ 0x087f, "ISSC DAS AgentAIX" },
1188 	{ 0x0880, "Intel Netport PRO" },
1189 	{ 0x0881, "Intel Netport PRO" },
1190 	{ 0x0b29, "SiteLock" },
1191 	{ 0x0c29, "SiteLockApplications" },
1192 	{ 0x0c2c, "LicensingServer" },
1193 	{ 0x2101, "PerformanceTechnologyInstantInternet" },
1194 	{ 0x2380, "LAI SiteLock" },
1195 	{ 0x238c, "MeetingMaker" },
1196 	{ 0x4808, "SiteLockServer/SiteLockMetering" },
1197 	{ 0x5555, "SiteLockUser" },
1198 	{ 0x6312, "Tapeware" },
1199 	{ 0x6f00, "RabbitGateway" },
1200 	{ 0x7703, "MODEM" },
1201 	{ 0x8002, "NetPortPrinters" },
1202 	{ 0x8008, "WordPerfectNetworkVersion" },
1203 	{ 0x85BE, "Cisco EIGRP" },
1204 	{ 0x8888, "WordPerfectNetworkVersion/QuickNetworkManagement" },
1205 	{ 0x9000, "McAfeeNetShield" },
1206 	{ 0x9604, "CSA-NT_MON" },
1207 	{ 0xb6a8, "OceanIsleReachoutRemoteControl" },
1208 	{ 0xf11f, "SiteLockMetering" },
1209 	{ 0xf1ff, "SiteLock" },
1210 	{ 0xf503, "Microsoft SQL Server" },
1211 	{ 0xF905, "IBM TimeAndPlace" },
1212 	{ 0xfbfb, "TopCallIII FaxServer" },
1213 	{ 0xffff, "AnyService/Wildcard" },
1214 	{ 0, (char *)0 }
1215 };
1216 
1217 static void
1218 init_ipxsaparray(netdissect_options *ndo)
1219 {
1220 	int i;
1221 	struct hnamemem *table;
1222 
1223 	for (i = 0; ipxsap_db[i].s != NULL; i++) {
1224 		u_int j = htons(ipxsap_db[i].v) & (HASHNAMESIZE-1);
1225 		table = &ipxsaptable[j];
1226 		while (table->name)
1227 			table = table->nxt;
1228 		table->name = ipxsap_db[i].s;
1229 		table->addr = htons(ipxsap_db[i].v);
1230 		table->nxt = newhnamemem(ndo);
1231 	}
1232 }
1233 
1234 /*
1235  * Initialize the address to name translation machinery.  We map all
1236  * non-local IP addresses to numeric addresses if ndo->ndo_fflag is true
1237  * (i.e., to prevent blocking on the nameserver).  localnet is the IP address
1238  * of the local network.  mask is its subnet mask.
1239  */
1240 void
1241 init_addrtoname(netdissect_options *ndo, uint32_t localnet, uint32_t mask)
1242 {
1243 	if (ndo->ndo_fflag) {
1244 		f_localnet = localnet;
1245 		f_netmask = mask;
1246 	}
1247 	if (ndo->ndo_nflag)
1248 		/*
1249 		 * Simplest way to suppress names.
1250 		 */
1251 		return;
1252 
1253 	init_etherarray(ndo);
1254 	init_servarray(ndo);
1255 	init_eprotoarray(ndo);
1256 	init_protoidarray(ndo);
1257 	init_ipxsaparray(ndo);
1258 }
1259 
1260 const char *
1261 dnaddr_string(netdissect_options *ndo, u_short dnaddr)
1262 {
1263 	struct hnamemem *tp;
1264 
1265 	for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != NULL;
1266 	     tp = tp->nxt)
1267 		if (tp->addr == dnaddr)
1268 			return (tp->name);
1269 
1270 	tp->addr = dnaddr;
1271 	tp->nxt = newhnamemem(ndo);
1272 	tp->name = dnnum_string(ndo, dnaddr);
1273 
1274 	return(tp->name);
1275 }
1276 
1277 /* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
1278 struct hnamemem *
1279 newhnamemem(netdissect_options *ndo)
1280 {
1281 	struct hnamemem *p;
1282 	static struct hnamemem *ptr = NULL;
1283 	static u_int num = 0;
1284 
1285 	if (num  == 0) {
1286 		num = 64;
1287 		ptr = (struct hnamemem *)calloc(num, sizeof (*ptr));
1288 		if (ptr == NULL)
1289 			(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
1290 					  "%s: calloc", __func__);
1291 	}
1292 	--num;
1293 	p = ptr++;
1294 	return (p);
1295 }
1296 
1297 /* Return a zero'ed h6namemem struct and cuts down on calloc() overhead */
1298 struct h6namemem *
1299 newh6namemem(netdissect_options *ndo)
1300 {
1301 	struct h6namemem *p;
1302 	static struct h6namemem *ptr = NULL;
1303 	static u_int num = 0;
1304 
1305 	if (num  == 0) {
1306 		num = 64;
1307 		ptr = (struct h6namemem *)calloc(num, sizeof (*ptr));
1308 		if (ptr == NULL)
1309 			(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
1310 					  "%s: calloc", __func__);
1311 	}
1312 	--num;
1313 	p = ptr++;
1314 	return (p);
1315 }
1316 
1317 /* Represent TCI part of the 802.1Q 4-octet tag as text. */
1318 const char *
1319 ieee8021q_tci_string(const uint16_t tci)
1320 {
1321 	static char buf[128];
1322 	snprintf(buf, sizeof(buf), "vlan %u, p %u%s",
1323 	         tci & 0xfff,
1324 	         tci >> 13,
1325 	         (tci & 0x1000) ? ", DEI" : "");
1326 	return buf;
1327 }
1328