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