File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / trafshow / addrtoname.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:55:18 2012 UTC (12 years, 3 months ago) by misho
Branches: trafshow, MAIN
CVS tags: v5_2_3p0, v5_2_3, HEAD
trafshow

/*
 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * distributions including binary code include the above copyright notice and
 * this paragraph in its entirety in the documentation or other materials
 * provided with the distribution, and (3) all advertising materials mentioning
 * features or use of this software display the following acknowledgement:
 * ``This product includes software developed by the University of California,
 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
 * the University nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior
 * written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *  Internet, ethernet, port, and protocol string to address
 *  and address to string conversion routines

#ifndef lint
static const char rcsid[] _U_ =
    "@(#) $Header: /usr/local/www/users/anoncvs/cvs/embedaddon/trafshow/addrtoname.c,v 1.1.1.1 2012/02/21 16:55:18 misho Exp $ (LBL)";
#endif
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ctype.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/types.h>                  /* concession to AIX */
#include <sys/time.h>
#include <sys/socket.h>
#ifdef	linux
#include <linux/if.h>
#else
#include <net/if.h>
#endif
#include <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef	HAVE_NET_IF_DL_H
#include <net/if_dl.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#include <time.h>
#endif

#include <arpa/inet.h>

#include <pcap.h>
#include <pcap-namedb.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "addrtoname.h"
#include "ethertype.h"
#include "domain_resolver.h"

#ifndef NTOHL
#define NTOHL(x)	(x) = ntohl(x)
#define NTOHS(x)	(x) = ntohs(x)
#define HTONL(x)	(x) = htonl(x)
#define HTONS(x)	(x) = htons(x)
#endif

/* dirty fake */
#define	error(s)	{ perror(s); exit(1); }

struct tok {
	int v;			/* value */
	const char *s;		/* string */
};

/*
 * hash tables for whatever-to-name translations
 *
 * XXX there has to be error checks against strdup(3) failure
 */

#define HASHNAMESIZE 4096

struct hnamemem {
	int resolving;
	u_int32_t addr;
	const char *name;
	struct hnamemem *nxt;
};

struct hnamemem hnametable[HASHNAMESIZE];
struct hnamemem tporttable[HASHNAMESIZE];
struct hnamemem uporttable[HASHNAMESIZE];
struct hnamemem servtable[HASHNAMESIZE];
struct hnamemem iprototable[HASHNAMESIZE];
struct hnamemem etypetable[HASHNAMESIZE];
struct hnamemem dnaddrtable[HASHNAMESIZE];
struct hnamemem llcsaptable[HASHNAMESIZE];
struct hnamemem ipxsaptable[HASHNAMESIZE];
struct hnamemem icmptable[HASHNAMESIZE];
#ifdef INET6
struct hnamemem icmpv6table[HASHNAMESIZE];
#endif

#ifdef INET6
struct h6namemem {
	struct in6_addr addr;
	char *name;
	struct h6namemem *nxt;
};

struct h6namemem h6nametable[HASHNAMESIZE];
#endif /* INET6 */

struct enamemem {
	u_short e_addr0;
	u_short e_addr1;
	u_short e_addr2;
	const char *e_name;
	u_char *e_nsap;			/* used only for nsaptable[] */
#define e_bs e_nsap			/* for bytestringtable */
	struct enamemem *e_nxt;
};

struct enamemem enametable[HASHNAMESIZE];
struct enamemem nsaptable[HASHNAMESIZE];
struct enamemem bytestringtable[HASHNAMESIZE];

struct protoidmem {
	u_int32_t p_oui;
	u_short p_proto;
	const char *p_name;
	struct protoidmem *p_nxt;
};

struct protoidmem protoidtable[HASHNAMESIZE];

char *
satoa(sa, dst, size)
	const struct sockaddr *sa;
	char *dst;
	int size;
{
	const char *cp = 0;
#ifdef INET6
	char buf[100];
#endif
	if (!sa || !dst || size < 1)
		return 0;
	if (sa->sa_family == AF_INET) {
		cp = intoa(((struct sockaddr_in *)sa)->sin_addr.s_addr);
	}
#ifdef INET6
	else if (sa->sa_family == AF_INET6) {
		cp = inet_ntop(AF_INET6,
			       &((struct sockaddr_in6 *)sa)->sin6_addr,
			       buf, sizeof(buf));
	}
#endif
#if defined(AF_LINK) && defined(LLADDR)
	else if (sa->sa_family == AF_LINK) {
		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
		if (sdl->sdl_alen > 0)
			cp = linkaddr_string((u_char *)LLADDR(sdl), sdl->sdl_alen);
	}
#endif
	if (!cp) return 0;
	(void)strncpy(dst, cp, size);
	dst[size-1] = '\0';
	return dst;
}

/*
 * A faster replacement for inet_ntoa().
 */
const char *
intoa(u_int32_t addr)
{
	register char *cp;
	register u_int byte;
	register int n;
	static char buf[sizeof(".xxx.xxx.xxx.xxx")];

	NTOHL(addr);
	cp = &buf[sizeof buf];
	*--cp = '\0';

	n = 4;
	do {
		byte = addr & 0xff;
		*--cp = byte % 10 + '0';
		byte /= 10;
		if (byte > 0) {
			*--cp = byte % 10 + '0';
			byte /= 10;
			if (byte > 0)
				*--cp = byte + '0';
		}
		*--cp = '.';
		addr >>= 8;
	} while (--n > 0);

	return cp + 1;
}

extern int nflag;

static void
name_resolved(unused, dd)
	void *unused;
	DOMAIN_DATA *dd;
{
	register struct hnamemem *p;

	/* sanity check */
	if (unused || !dd) return;

	p = &hnametable[dd->addr & (HASHNAMESIZE-1)];
	for (; p->nxt; p = p->nxt) {
		if (p->addr == dd->addr) {
			if (p->name) free((char *)p->name);
			p->name = strdup(dd->name);
			p->resolving = 2;
			break;
		}
	}
	domain_data_free(&dd, 0);
}

/*
 * Return a name for the IP address pointed to by ap.  This address
 * is assumed to be in network byte order.
 */
const char *
getname(const u_char *ap)
{
	u_int32_t addr;
	register struct hnamemem *p;
	int found;

	memcpy(&addr, ap, sizeof(addr));

	/*
	 * Do not print names if -n was given.
	 */
	if (nflag)
		return intoa(addr);

	found = 0;
	p = &hnametable[addr & (HASHNAMESIZE-1)];
	for (; p->nxt; p = p->nxt) {
		if (p->addr == addr) {
			found++;
			break;
		}
	}
	if (!found) {
		p->addr = addr;
		p->nxt = newhnamemem();
		p->name = strdup(intoa(addr));
	}
	if (!p->resolving) {
		if (domain_resolve_name(addr, 0, name_resolved) < 0)
			p->resolving = -1;
		else	p->resolving = 1;
	}
	return (p->name);
}

#ifdef INET6
/*
 * Return a name for the IP6 address pointed to by ap.  This address
 * is assumed to be in network byte order.
 */
const char *
getname6(const u_char *ap)
{
	struct hostent *hp;
	struct in6_addr addr;
	static struct h6namemem *p;		/* static for longjmp() */
	const char *cp;
	char ntop_buf[INET6_ADDRSTRLEN];

	memcpy(&addr, ap, sizeof(addr));

	/*
	 * Do not print names if -n was given.
	 */
	if (nflag)
		return inet_ntop(AF_INET6, &addr, ntop_buf, sizeof(ntop_buf));

	p = &h6nametable[*(u_int16_t *)&addr.s6_addr[14] & (HASHNAMESIZE-1)];
	for (; p->nxt; p = p->nxt) {
		if (memcmp(&p->addr, &addr, sizeof(addr)) == 0)
			return (p->name);
	}
	p->addr = addr;
	p->nxt = newh6namemem();

	hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET6);
	if (hp) {
		p->name = strdup(hp->h_name);
		return (p->name);
	}
	cp = inet_ntop(AF_INET6, &addr, ntop_buf, sizeof(ntop_buf));
	if (!cp) return 0;
	p->name = strdup(cp);
	return (p->name);
}
#endif /* INET6 */

static char hex[] = "0123456789abcdef";


/* Find the hash node that corresponds the ether address 'ep' */

static inline struct enamemem *
lookup_emem(const u_char *ep)
{
	register u_int i, j, k;
	struct enamemem *tp;

	k = (ep[0] << 8) | ep[1];
	j = (ep[2] << 8) | ep[3];
	i = (ep[4] << 8) | ep[5];

	tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
	while (tp->e_nxt)
		if (tp->e_addr0 == i &&
		    tp->e_addr1 == j &&
		    tp->e_addr2 == k)
			return tp;
		else
			tp = tp->e_nxt;
	tp->e_addr0 = i;
	tp->e_addr1 = j;
	tp->e_addr2 = k;
	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
	if (tp->e_nxt == NULL)
		error("lookup_emem: calloc");

	return tp;
}

/*
 * Find the hash node that corresponds to the bytestring 'bs'
 * with length 'nlen'
 */

static inline struct enamemem *
lookup_bytestring(register const u_char *bs, const unsigned int nlen)
{
	struct enamemem *tp;
	register u_int i, j, k;

	if (nlen >= 6) {
		k = (bs[0] << 8) | bs[1];
		j = (bs[2] << 8) | bs[3];
		i = (bs[4] << 8) | bs[5];
	} else if (nlen >= 4) {
		k = (bs[0] << 8) | bs[1];
		j = (bs[2] << 8) | bs[3];
		i = 0;
	} else
		i = j = k = 0;

	tp = &bytestringtable[(i ^ j) & (HASHNAMESIZE-1)];
	while (tp->e_nxt)
		if (tp->e_addr0 == i &&
		    tp->e_addr1 == j &&
		    tp->e_addr2 == k &&
		    memcmp((const char *)bs, (const char *)(tp->e_bs), nlen) == 0)
			return tp;
		else
			tp = tp->e_nxt;

	tp->e_addr0 = i;
	tp->e_addr1 = j;
	tp->e_addr2 = k;

	tp->e_bs = (u_char *) calloc(1, nlen + 1);
	memcpy(tp->e_bs, bs, nlen);
	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
	if (tp->e_nxt == NULL)
		error("lookup_bytestring: calloc");

	return tp;
}

/* Find the hash node that corresponds the NSAP 'nsap' */

static inline struct enamemem *
lookup_nsap(register const u_char *nsap)
{
	register u_int i, j, k;
	unsigned int nlen = *nsap;
	struct enamemem *tp;
	const u_char *ensap = nsap + nlen - 6;

	if (nlen > 6) {
		k = (ensap[0] << 8) | ensap[1];
		j = (ensap[2] << 8) | ensap[3];
		i = (ensap[4] << 8) | ensap[5];
	}
	else
		i = j = k = 0;

	tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
	while (tp->e_nxt)
		if (tp->e_addr0 == i &&
		    tp->e_addr1 == j &&
		    tp->e_addr2 == k &&
		    tp->e_nsap[0] == nlen &&
		    memcmp((const char *)&(nsap[1]),
			(char *)&(tp->e_nsap[1]), nlen) == 0)
			return tp;
		else
			tp = tp->e_nxt;
	tp->e_addr0 = i;
	tp->e_addr1 = j;
	tp->e_addr2 = k;
	tp->e_nsap = (u_char *)malloc(nlen + 1);
	if (tp->e_nsap == NULL)
		error("lookup_nsap: malloc");
	memcpy((char *)tp->e_nsap, (const char *)nsap, nlen + 1);
	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
	if (tp->e_nxt == NULL)
		error("lookup_nsap: calloc");

	return tp;
}

/* Find the hash node that corresponds the protoid 'pi'. */

static inline struct protoidmem *
lookup_protoid(const u_char *pi)
{
	register u_int i, j;
	struct protoidmem *tp;

	/* 5 octets won't be aligned */
	i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
	j =   (pi[3] << 8) + pi[4];
	/* XXX should be endian-insensitive, but do big-endian testing  XXX */

	tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
	while (tp->p_nxt)
		if (tp->p_oui == i && tp->p_proto == j)
			return tp;
		else
			tp = tp->p_nxt;
	tp->p_oui = i;
	tp->p_proto = j;
	tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
	if (tp->p_nxt == NULL)
		error("lookup_protoid: calloc");

	return tp;
}

const char *
etheraddr_string(register const u_char *ep)
{
	register u_int i;
	register char *cp;
	register struct enamemem *tp;
	char buf[sizeof("00:00:00:00:00:00")];

	tp = lookup_emem(ep);
	if (tp->e_name)
		return (tp->e_name);
#ifdef USE_ETHER_NTOHOST
	if (!nflag) {
		char buf2[128];
		if (ether_ntohost(buf2, (const struct ether_addr *)ep) == 0) {
			tp->e_name = strdup(buf2);
			return (tp->e_name);
		}
	}
#endif
	cp = buf;
        *cp++ = hex[*ep >> 4 ];
	*cp++ = hex[*ep++ & 0xf];
	for (i = 5; (int)--i >= 0;) {
		*cp++ = ':';
                *cp++ = hex[*ep >> 4 ];
		*cp++ = hex[*ep++ & 0xf];
	}
	*cp = '\0';
	tp->e_name = strdup(buf);
	return (tp->e_name);
}

const char *
linkaddr_string(const u_char *ep, const unsigned int len)
{
	register u_int i, j;
	register char *cp;
	register struct enamemem *tp;

	if (!ep || len < 1) return "";

#ifdef	notdef
	if (len == 6)	/* XXX not totally correct... */
		return etheraddr_string(ep);
#endif

	tp = lookup_bytestring(ep, len);
	if (tp->e_name)
		return (tp->e_name);

	tp->e_name = cp = (char *)malloc(len*3);
	if (tp->e_name == NULL)
		error("linkaddr_string: malloc");
	if ((j = *ep >> 4) != 0)
		*cp++ = hex[j];
	*cp++ = hex[*ep++ & 0xf];
	for (i = len-1; i > 0 ; --i) {
		*cp++ = ':';
		if ((j = *ep >> 4) != 0)
			*cp++ = hex[j];
		*cp++ = hex[*ep++ & 0xf];
	}
	*cp = '\0';
	return (tp->e_name);
}

const char *
ethertype_string(u_short type)
{
	register char *cp;
	register struct hnamemem *tp;
	register u_int32_t i = type;
	char buf[sizeof("0000")];

	for (tp = &etypetable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	cp = buf;
	NTOHS(type);
	*cp++ = toupper(hex[type >> 12 & 0xf]);
	*cp++ = toupper(hex[type >> 8 & 0xf]);
	*cp++ = toupper(hex[type >> 4 & 0xf]);
	*cp++ = toupper(hex[type & 0xf]);
	*cp++ = '\0';
	tp->name = strdup(buf);
	return (tp->name);
}

const char *
protoid_string(register const u_char *pi)
{
	register u_int i, j;
	register char *cp;
	register struct protoidmem *tp;
	char buf[sizeof("00:00:00:00:00")];

	tp = lookup_protoid(pi);
	if (tp->p_name)
		return tp->p_name;

	cp = buf;
	if ((j = *pi >> 4) != 0)
		*cp++ = hex[j];
	*cp++ = hex[*pi++ & 0xf];
	for (i = 4; (int)--i >= 0;) {
		*cp++ = ':';
		if ((j = *pi >> 4) != 0)
			*cp++ = hex[j];
		*cp++ = hex[*pi++ & 0xf];
	}
	*cp = '\0';
	tp->p_name = strdup(buf);
	return (tp->p_name);
}

const char *
llcsap_string(u_char sap)
{
	register struct hnamemem *tp;
	register u_int32_t i = sap;
	char buf[sizeof("sap-00")];

	for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	snprintf(buf, sizeof(buf), "sap-%02x", sap & 0xff);
	tp->name = strdup(buf);
	return (tp->name);
}

const char *
isonsap_string(const u_char *nsap)
{
	register u_int i, nlen = nsap[0];
	register char *cp;
	register struct enamemem *tp;

	tp = lookup_nsap(nsap);
	if (tp->e_name)
		return tp->e_name;

	tp->e_name = cp = (char *)malloc(nlen * 2 + 2);
	if (cp == NULL)
		error("isonsap_string: malloc");

	nsap++;
	*cp++ = '/';
	for (i = nlen; (int)--i >= 0;) {
		*cp++ = hex[*nsap >> 4];
		*cp++ = hex[*nsap++ & 0xf];
	}
	*cp = '\0';
	return (tp->e_name);
}

const char *
tcpport_string(u_short port)
{
	register struct hnamemem *tp;
	register u_int32_t i = port;
	char buf[sizeof("00000")];

	for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) {
		if (tp->addr == i)
			return (tp->name);
	}
	tp->addr = i;
	tp->nxt = newhnamemem();

	(void)snprintf(buf, sizeof(buf), "%u", i);
	tp->name = strdup(buf);
	return (tp->name);
}

const char *
udpport_string(u_short port)
{
	register struct hnamemem *tp;
	register u_int32_t i = port;
	char buf[sizeof("00000")];

	for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) {
		if (tp->addr == i)
			return (tp->name);
	}
	tp->addr = i;
	tp->nxt = newhnamemem();

	(void)snprintf(buf, sizeof(buf), "%u", i);
	tp->name = strdup(buf);
	return (tp->name);
}

int
isservport(u_short port)
{
	register struct hnamemem *tp;
        register u_int32_t i = port;

	for (tp = &servtable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) {
		if (tp->addr == i)
			return 1;
	}
	return 0;
}

const char *
ipxsap_string(u_short port)
{
	register char *cp;
	register struct hnamemem *tp;
	register u_int32_t i = port;
	char buf[sizeof("0000")];

	for (tp = &ipxsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	cp = buf;
	NTOHS(port);
	*cp++ = toupper(hex[port >> 12 & 0xf]);
	*cp++ = toupper(hex[port >> 8 & 0xf]);
	*cp++ = toupper(hex[port >> 4 & 0xf]);
	*cp++ = toupper(hex[port & 0xf]);
	*cp++ = '\0';
	tp->name = strdup(buf);
	return (tp->name);
}

static void
init_servarray(void)
{
	struct servent *sv;
	register struct hnamemem *table;
	register int i;

	while ((sv = getservent()) != NULL) {
		int port = ntohs(sv->s_port);
		i = port & (HASHNAMESIZE-1);

		table = &servtable[i];
		if (table->addr != port) {
			while (table->addr)
				table = table->nxt;
			table->addr = port;
			table->nxt = newhnamemem();
		}

		if (strcmp(sv->s_proto, "tcp") == 0)
			table = &tporttable[i];
		else if (strcmp(sv->s_proto, "udp") == 0)
			table = &uporttable[i];
		else	continue;

		while (table->name)
			table = table->nxt;
		table->name = strdup(sv->s_name);
		table->addr = port;
		table->nxt = newhnamemem();
	}
	endservent();
}

static struct tok ethertype_db[] = {
	{ ETHERTYPE_IP,             "ip"	},
	{ ETHERTYPE_MPLS,           "mpls"	},
	{ ETHERTYPE_MPLS_MULTI,     "mpls-mc"	},
	{ ETHERTYPE_IPV6,           "ipv6"	},
	{ ETHERTYPE_8021Q,          "dot1q"	},
	{ ETHERTYPE_VMAN,           "vman"	},
	{ ETHERTYPE_PUP,            "pup"	},
	{ ETHERTYPE_ARP,            "arp"	},
	{ ETHERTYPE_REVARP ,        "rarp"	},
	{ ETHERTYPE_NS,             "ns"	},
	{ ETHERTYPE_SPRITE,         "sprite"	},
	{ ETHERTYPE_TRAIL,          "trail"	},
	{ ETHERTYPE_CDP,            "cdp"	},
	{ ETHERTYPE_MOPDL,          "mop-dl"	},
	{ ETHERTYPE_MOPRC,          "mop-rc"	},
	{ ETHERTYPE_DN,             "dn"	},
	{ ETHERTYPE_LAT,            "lat"	},
	{ ETHERTYPE_SCA,            "sca"	},
	{ ETHERTYPE_LANBRIDGE,      "lanbridge"	},
	{ ETHERTYPE_DECDNS,         "dec-dns"	},
	{ ETHERTYPE_DECDTS,         "dec-dts"	},
	{ ETHERTYPE_VEXP,           "vexp"	},
	{ ETHERTYPE_VPROD,          "vprod"	},
	{ ETHERTYPE_ATALK,          "atalk"	},
	{ ETHERTYPE_AARP,           "atalk-arp"	},
	{ ETHERTYPE_IPX,            "ipx"	},
	{ ETHERTYPE_PPP,            "ppp"	},
	{ ETHERTYPE_PPPOED,         "pppoe-d"	},
	{ ETHERTYPE_PPPOES,         "pppoe-s"	},
	{ ETHERTYPE_LOOPBACK,       "loopback"	},
	{ 0, NULL }
};

static void
init_etypearray(void)
{
	register int i;
	register struct hnamemem *table;

	for (i = 0; ethertype_db[i].s; i++) {
		int j = htons(ethertype_db[i].v) & (HASHNAMESIZE-1);
		table = &etypetable[j];
		while (table->name)
			table = table->nxt;
		table->name = ethertype_db[i].s;
		table->addr = htons(ethertype_db[i].v);
		table->nxt = newhnamemem();
	}
}

static struct protoidlist {
	const u_char protoid[5];
	const char *name;
} protoidlist[] = {
	{{ 0x00, 0x00, 0x0c, 0x01, 0x07 }, "CiscoMLS" },
	{{ 0x00, 0x00, 0x0c, 0x20, 0x00 }, "CiscoCDP" },
	{{ 0x00, 0x00, 0x0c, 0x20, 0x01 }, "CiscoCGMP" },
	{{ 0x00, 0x00, 0x0c, 0x20, 0x03 }, "CiscoVTP" },
	{{ 0x00, 0xe0, 0x2b, 0x00, 0xbb }, "ExtremeEDP" },
	{{ 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
};

/*
 * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
 * types.
 */
static void
init_protoidarray(void)
{
	register int i;
	register struct protoidmem *tp;
	struct protoidlist *pl;
	u_char protoid[5];

	protoid[0] = 0;
	protoid[1] = 0;
	protoid[2] = 0;
	for (i = 0; ethertype_db[i].s; i++) {
		u_short etype = htons(ethertype_db[i].v);

		memcpy((char *)&protoid[3], (char *)&etype, 2);
		tp = lookup_protoid(protoid);
		tp->p_name = strdup(ethertype_db[i].s);
	}
	/* Hardwire some SNAP proto ID names */
	for (pl = protoidlist; pl->name != NULL; ++pl) {
		tp = lookup_protoid(pl->protoid);
		/* Don't override existing name */
		if (tp->p_name != NULL)
			continue;

		tp->p_name = pl->name;
	}
}

static struct etherlist {
	const u_char addr[6];
	const char *name;
} etherlist[] = {
	{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "ethernet" },
	{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "broadcast" },
	{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
};

/*
 * Initialize the ethers hash table.  We take two different approaches
 * depending on whether or not the system provides the ethers name
 * service.  If it does, we just wire in a few names at startup,
 * and etheraddr_string() fills in the table on demand.  If it doesn't,
 * then we suck in the entire /etc/ethers file at startup.  The idea
 * is that parsing the local file will be fast, but spinning through
 * all the ethers entries via NIS & next_etherent might be very slow.
 *
 * XXX pcap_next_etherent doesn't belong in the pcap interface, but
 * since the pcap module already does name-to-address translation,
 * it's already does most of the work for the ethernet address-to-name
 * translation, so we just pcap_next_etherent as a convenience.
 */
static void
init_etherarray(void)
{
	register struct etherlist *el;
	register struct enamemem *tp;
#ifdef USE_ETHER_NTOHOST
	char name[256];
#else
	register struct pcap_etherent *ep;
	register FILE *fp;

	/* Suck in entire ethers file */
	fp = fopen(PCAP_ETHERS_FILE, "r");
	if (fp != NULL) {
		while ((ep = pcap_next_etherent(fp)) != NULL) {
			tp = lookup_emem(ep->addr);
			tp->e_name = strdup(ep->name);
		}
		(void)fclose(fp);
	}
#endif

	/* Hardwire some ethernet names */
	for (el = etherlist; el->name != NULL; ++el) {
		tp = lookup_emem(el->addr);
		/* Don't override existing name */
		if (tp->e_name != NULL)
			continue;

#ifdef USE_ETHER_NTOHOST
                /* Use yp/nis version of name if available */
                if (ether_ntohost(name, (const struct ether_addr *)el->addr) == 0) {
                        tp->e_name = strdup(name);
			continue;
		}
#endif
		tp->e_name = el->name;
	}
}

static struct tok llcsap_db[] = {
	/* IEEE SAPs */
	{ 0x00,	"null"		},
	{ 0x02,	"isap"		},
	{ 0x03,	"gsap"		},
	{ 0x06,	"ip-sap"	},
	{ 0x0e,	"proway-nm"	},
	{ 0x42,	"stp"		},
	{ 0x4e,	"rs511"		},
	{ 0x5e,	"isi-ip"	},
	{ 0x7e,	"x25-plp"	},
	{ 0x80,	"3com"		},
	{ 0x8e,	"proway"	},
	{ 0xaa,	"snap"		},
	{ 0xbc,	"banyan"	},
	{ 0xe0,	"ipx"		},
	{ 0xf0,	"netbeui"	},
	{ 0xf4,	"lanman"	},
	{ 0xfe,	"iso-clns"	},
	{ 0xff,	"raw-ipx"	}, /* known as raw 802.3 packet */
	/* IBM SAPs */
	{ 0x04,	"isna"		},
	{ 0x05,	"gsna"		},
	{ 0xd4,	"resource"	},
	{ 0xdc,	"dyn-arp"	},
	{ 0xf0,	"netbios"	},
	{ 0xf8,	"irpl"		},
	{ 0xf4,	"ilan"		},
	{ 0xf5,	"glan"		},
	{ 0xfc,	"discovery"	},
	{ 0, NULL }
};

static void
init_llcsaparray(void)
{
	register int i;
	register struct hnamemem *table;

	for (i = 0; llcsap_db[i].s != NULL; i++) {
		table = &llcsaptable[llcsap_db[i].v];
		while (table->name)
			table = table->nxt;
		table->name = llcsap_db[i].s;
		table->addr = llcsap_db[i].v;
		table->nxt = newhnamemem();
	}
}

static struct tok ipxsap_db[] = {
	{ 0x0000, "Unknown" },
	{ 0x0001, "User" },
	{ 0x0002, "User Group" },
	{ 0x0003, "PrintQueue" },
	{ 0x0004, "FileServer" },
	{ 0x0005, "JobServer" },
	{ 0x0006, "Gateway" },
	{ 0x0007, "PrintServer" },
	{ 0x0008, "ArchiveQueue" },
	{ 0x0009, "ArchiveServer" },
	{ 0x000a, "JobQueue" },
	{ 0x000b, "Administration" },
	{ 0x000F, "Novell TI-RPC" },
	{ 0x0017, "Diagnostics" },
	{ 0x0020, "NetBIOS" },
	{ 0x0021, "NAS SNA Gateway" },
	{ 0x0023, "NACS AsyncGateway" },
	{ 0x0024, "RemoteBridge/RoutingService" },
	{ 0x0026, "BridgeServer" },
	{ 0x0027, "TCP/IP Gateway" },
	{ 0x0028, "Point-to-point X.25 BridgeServer" },
	{ 0x0029, "3270 Gateway" },
	{ 0x002a, "CHI Corp" },
	{ 0x002c, "PC Chalkboard" },
	{ 0x002d, "TimeSynchServer" },
	{ 0x002e, "ARCserve5.0/PalindromeBackup" },
	{ 0x0045, "DI3270 Gateway" },
	{ 0x0047, "AdvertisingPrintServer" },
	{ 0x004a, "NetBlazerModems" },
	{ 0x004b, "BtrieveVAP" },
	{ 0x004c, "NetwareSQL" },
	{ 0x004d, "XtreeNetwork" },
	{ 0x0050, "BtrieveVAP4.11" },
	{ 0x0052, "QuickLink" },
	{ 0x0053, "PrintQueueUser" },
	{ 0x0058, "Multipoint X.25 Router" },
	{ 0x0060, "STLB/NLM" },
	{ 0x0064, "ARCserve" },
	{ 0x0066, "ARCserve3.0" },
	{ 0x0072, "WAN CopyUtility" },
	{ 0x007a, "TES-NetwareVMS" },
	{ 0x0092, "WATCOM Debugger/EmeraldTapeBackupServer" },
	{ 0x0095, "DDA OBGYN" },
	{ 0x0098, "NetwareAccessServer" },
	{ 0x009a, "Netware for VMS II/NamedPipeServer" },
	{ 0x009b, "NetwareAccessServer" },
	{ 0x009e, "PortableNetwareServer/SunLinkNVT" },
	{ 0x00a1, "PowerchuteAPC UPS" },
	{ 0x00aa, "LAWserve" },
	{ 0x00ac, "CompaqIDA StatusMonitor" },
	{ 0x0100, "PIPE STAIL" },
	{ 0x0102, "LAN ProtectBindery" },
	{ 0x0103, "OracleDataBaseServer" },
	{ 0x0107, "Netware386/RSPX RemoteConsole" },
	{ 0x010f, "NovellSNA Gateway" },
	{ 0x0111, "TestServer" },
	{ 0x0112, "HP PrintServer" },
	{ 0x0114, "CSA MUX" },
	{ 0x0115, "CSA LCA" },
	{ 0x0116, "CSA CM" },
	{ 0x0117, "CSA SMA" },
	{ 0x0118, "CSA DBA" },
	{ 0x0119, "CSA NMA" },
	{ 0x011a, "CSA SSA" },
	{ 0x011b, "CSA STATUS" },
	{ 0x011e, "CSA APPC" },
	{ 0x0126, "SNA TEST SSA Profile" },
	{ 0x012a, "CSA TRACE" },
	{ 0x012b, "NetwareSAA" },
	{ 0x012e, "IKARUS VirusScan" },
	{ 0x0130, "CommunicationsExecutive" },
	{ 0x0133, "NNS DomainServer/NetwareNamingServicesDomain" },
	{ 0x0135, "NetwareNamingServicesProfile" },
	{ 0x0137, "Netware386 PrintQueue/NNS PrintQueue" },
	{ 0x0141, "LAN SpoolServer" },
	{ 0x0152, "IRMALAN Gateway" },
	{ 0x0154, "NamedPipeServer" },
	{ 0x0166, "NetWareManagement" },
	{ 0x0168, "Intel PICKIT CommServer/Intel CAS TalkServer" },
	{ 0x0173, "Compaq" },
	{ 0x0174, "Compaq SNMP Agent" },
	{ 0x0175, "Compaq" },
	{ 0x0180, "XTreeServer/XTreeTools" },
	{ 0x018A, "NASI ServicesBroadcastServer" },
	{ 0x01b0, "GARP Gateway" },
	{ 0x01b1, "Binfview" },
	{ 0x01bf, "IntelLanDeskManager" },
	{ 0x01ca, "AXTEC" },
	{ 0x01cb, "ShivaNetModem/E" },
	{ 0x01cc, "ShivaLanRover/E" },
	{ 0x01cd, "ShivaLanRover/T" },
	{ 0x01ce, "ShivaUniversal" },
	{ 0x01d8, "CastelleFAXPressServer" },
	{ 0x01da, "CastelleLANPressPrintServer" },
	{ 0x01dc, "CastelleFAX/Xerox7033 FaxServer/ExcelLanFax" },
	{ 0x01f0, "LEGATO" },
	{ 0x01f5, "LEGATO" },
	{ 0x0233, "NMS Agent/NetwareManagementAgent" },
	{ 0x0237, "NMS IPX Discovery/LANternReadWriteChannel" },
	{ 0x0238, "NMS IP Discovery/LANternTrapAlarmChannel" },
	{ 0x023a, "LANtern" },
	{ 0x023c, "MAVERICK" },
	{ 0x023f, "NovellSMDR" },
	{ 0x024e, "NetwareConnect" },
	{ 0x024f, "NASI ServerBroadcast Cisco" },
	{ 0x026a, "NMS ServiceConsole" },
	{ 0x026b, "TimeSynchronizationServer Netware 4.x" },
	{ 0x0278, "DirectoryServer Netware 4.x" },
	{ 0x027b, "NetwareManagementAgent" },
	{ 0x0280, "Novell File and Printer Sharing Service for PC" },
	{ 0x0304, "NovellSAA Gateway" },
	{ 0x0308, "COM/VERMED" },
	{ 0x030a, "GalacticommWorldgroupServer" },
	{ 0x030c, "IntelNetport2/HP JetDirect/HP Quicksilver" },
	{ 0x0320, "AttachmateGateway" },
	{ 0x0327, "MicrosoftDiagnostiocs" },
	{ 0x0328, "WATCOM SQL Server" },
	{ 0x0335, "MultiTechSystems MultisynchCommServer" },
	{ 0x0343, "Xylogics RemoteAccessServer/LANModem" },
	{ 0x0355, "ArcadaBackupExec" },
	{ 0x0358, "MSLCD1" },
	{ 0x0361, "NETINELO" },
	{ 0x037e, "Powerchute UPS Monitoring" },
	{ 0x037f, "ViruSafeNotify" },
	{ 0x0386, "HP Bridge" },
	{ 0x0387, "HP Hub" },
	{ 0x0394, "NetWare SAA Gateway" },
	{ 0x039b, "LotusNotes" },
	{ 0x03b7, "CertusAntiVirus" },
	{ 0x03c4, "ARCserve4.0" },
	{ 0x03c7, "LANspool3.5" },
	{ 0x03d7, "LexmarkPrinterServer" },
	{ 0x03d8, "LexmarkXLE PrinterServer" },
	{ 0x03dd, "BanyanENS NetwareClient" },
	{ 0x03de, "GuptaSequelBaseServer/NetWareSQL" },
	{ 0x03e1, "UnivelUnixware" },
	{ 0x03e4, "UnivelUnixware" },
	{ 0x03fc, "IntelNetport" },
	{ 0x03fd, "PrintServerQueue" },
	{ 0x040A, "ipnServer" },
	{ 0x040D, "LVERRMAN" },
	{ 0x040E, "LVLIC" },
	{ 0x0414, "NET Silicon (DPI)/Kyocera" },
	{ 0x0429, "SiteLockVirus" },
	{ 0x0432, "UFHELPR???" },
	{ 0x0433, "Synoptics281xAdvancedSNMPAgent" },
	{ 0x0444, "MicrosoftNT SNA Server" },
	{ 0x0448, "Oracle" },
	{ 0x044c, "ARCserve5.01" },
	{ 0x0457, "CanonGP55" },
	{ 0x045a, "QMS Printers" },
	{ 0x045b, "DellSCSI Array" },
	{ 0x0491, "NetBlazerModems" },
	{ 0x04ac, "OnTimeScheduler" },
	{ 0x04b0, "CD-Net" },
	{ 0x0513, "EmulexNQA" },
	{ 0x0520, "SiteLockChecks" },
	{ 0x0529, "SiteLockChecks" },
	{ 0x052d, "CitrixOS2 AppServer" },
	{ 0x0535, "Tektronix" },
	{ 0x0536, "Milan" },
	{ 0x055d, "Attachmate SNA gateway" },
	{ 0x056b, "IBM8235 ModemServer" },
	{ 0x056c, "ShivaLanRover/E PLUS" },
	{ 0x056d, "ShivaLanRover/T PLUS" },
	{ 0x0580, "McAfeeNetShield" },
	{ 0x05B8, "NLM to workstation communication (Revelation Software)" },
	{ 0x05BA, "CompatibleSystemsRouters" },
	{ 0x05BE, "CheyenneHierarchicalStorageManager" },
	{ 0x0606, "JCWatermarkImaging" },
	{ 0x060c, "AXISNetworkPrinter" },
	{ 0x0610, "AdaptecSCSIManagement" },
	{ 0x0621, "IBM AntiVirus" },
	{ 0x0640, "Windows95 RemoteRegistryService" },
	{ 0x064e, "MicrosoftIIS" },
	{ 0x067b, "Microsoft Win95/98 File and Print Sharing for NetWare" },
	{ 0x067c, "Microsoft Win95/98 File and Print Sharing for NetWare" },
	{ 0x076C, "Xerox" },
	{ 0x079b, "ShivaLanRover/E 115" },
	{ 0x079c, "ShivaLanRover/T 115" },
	{ 0x07B4, "CubixWorldDesk" },
	{ 0x07c2, "Quarterdeck IWare Connect V2.x NLM" },
	{ 0x07c1, "Quarterdeck IWare Connect V3.x NLM" },
	{ 0x0810, "ELAN License Server Demo" },
	{ 0x0824, "ShivaLanRoverAccessSwitch/E" },
	{ 0x086a, "ISSC Collector" },
	{ 0x087f, "ISSC DAS AgentAIX" },
	{ 0x0880, "Intel Netport PRO" },
	{ 0x0881, "Intel Netport PRO" },
	{ 0x0b29, "SiteLock" },
	{ 0x0c29, "SiteLockApplications" },
	{ 0x0c2c, "LicensingServer" },
	{ 0x2101, "PerformanceTechnologyInstantInternet" },
	{ 0x2380, "LAI SiteLock" },
	{ 0x238c, "MeetingMaker" },
	{ 0x4808, "SiteLockServer/SiteLockMetering" },
	{ 0x5555, "SiteLockUser" },
	{ 0x6312, "Tapeware" },
	{ 0x6f00, "RabbitGateway" },
	{ 0x7703, "MODEM" },
	{ 0x8002, "NetPortPrinters" },
	{ 0x8008, "WordPerfectNetworkVersion" },
	{ 0x85BE, "Cisco EIGRP" },
	{ 0x8888, "WordPerfectNetworkVersion/QuickNetworkManagement" },
	{ 0x9000, "McAfeeNetShield" },
	{ 0x9604, "CSA-NT_MON" },
	{ 0xb6a8, "OceanIsleReachoutRemoteControl" },
	{ 0xf11f, "SiteLockMetering" },
	{ 0xf1ff, "SiteLock" },
	{ 0xf503, "Microsoft SQL Server" },
	{ 0xF905, "IBM TimeAndPlace" },
	{ 0xfbfb, "TopCallIII FaxServer" },
	{ 0xffff, "AnyService/Wildcard" },
	{ 0, (char *)0 }
};

static void
init_ipxsaparray(void)
{
	register int i;
	register struct hnamemem *table;

	for (i = 0; ipxsap_db[i].s != NULL; i++) {
		int j = htons(ipxsap_db[i].v) & (HASHNAMESIZE-1);
		table = &ipxsaptable[j];
		while (table->name)
			table = table->nxt;
		table->name = ipxsap_db[i].s;
		table->addr = htons(ipxsap_db[i].v);
		table->nxt = newhnamemem();
	}
}

const char *
ipproto_string(u_char proto)
{
	register struct hnamemem *tp;
	register u_int32_t i = proto;
	char buf[sizeof("00000")];

	for (tp = &iprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	(void)snprintf(buf, sizeof(buf), "%u", i);
	tp->name = strdup(buf);
	return (tp->name);
}

static void
init_iprotoarray(void)
{
	struct protoent *pe;
	register struct hnamemem *tp;
	register u_int32_t i;

	while ((pe = getprotoent()) != NULL) {
		i = pe->p_proto;
		for (tp = &iprototable[i & (HASHNAMESIZE-1)];
		     tp->name; tp = tp->nxt) ;

		tp->name = strdup(pe->p_name);
		tp->addr = i;
		tp->nxt = newhnamemem();
	}
	endprotoent();
}

static struct tok icmp_db[] = {
	{ 0x0000,	"echo-reply"	},
	{ 0x0300,	"unrch-net"	},
	{ 0x0301,	"unrch-host"	},
	{ 0x0302,	"unrch-proto"	},
	{ 0x0303,	"unrch-port"	},
	{ 0x0304,	"need-frag"	},
	{ 0x0305,	"src-fail"	},
	{ 0x0306,	"bad-net"	},
	{ 0x0307,	"bad-host"	},
	{ 0x0308,	"isolated"	},
	{ 0x0309,	"net-prhbt"	},
	{ 0x030a,	"host-prhbt"	},
	{ 0x030b,	"bad-ntos"	},
	{ 0x030c,	"bad-htos"	},
	{ 0x030d,	"filtered"	},
	{ 0x030e,	"no-prec"	},
	{ 0x030f,	"prec-cut"	},
	{ 0x0400,	"quench"	},
	{ 0x0500,	"redir-net"	},
	{ 0x0501,	"redir-hst"	},
	{ 0x0502,	"redir-ntos"	},
	{ 0x0503,	"redir-htos"	},
	{ 0x0800,	"echo-reqst"	},
	{ 0x0900,	"advert"	},
	{ 0x0a00,	"solicit"	},
	{ 0x0b00,	"ttl-exceed"	},
	{ 0x0b01,	"frg-exceed"	},
	{ 0x0c00,	"err-atptr"	},
	{ 0x0c01,	"optabsent"	},
	{ 0x0c02,	"bad-len"	},
	{ 0x0d00,	"time-reqst"	},
	{ 0x0e00,	"time-reply"	},
	{ 0x0f00,	"info-reqst"	},
	{ 0x1000,	"info-reply"	},
	{ 0x1100,	"mask-reqst"	},
	{ 0x1200,	"mask-reply"	},
	{ 0, NULL }
};

static void
init_icmparray(void)
{
	register int i;
	register struct hnamemem *table;

	for (i = 0; icmp_db[i].s != NULL; i++) {
		table = &icmptable[icmp_db[i].v & (HASHNAMESIZE-1)];
		while (table->name)
			table = table->nxt;
		table->name = icmp_db[i].s;
		table->addr = icmp_db[i].v;
		table->nxt = newhnamemem();
	}
}

const char *
icmp_string(u_short code)
{
	register struct hnamemem *tp;
	register u_int32_t i = code;
	char buf[sizeof("0000")];

	for (tp = &icmptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	snprintf(buf, sizeof(buf), "%04x", code);
	tp->name = strdup(buf);
	return (tp->name);
}

#ifdef INET6
static struct tok icmpv6_db[] = {
	{ 0x0100,	"no-route"	},
	{ 0x0101,	"adm-prhbt"	},
	{ 0x0102,	"not-nghbr"	},
	{ 0x0103,	"addr-unrch"	},
	{ 0x0104,	"bad-port"	},
	{ 0x0200,	"pkt-toobig"	},
	{ 0x0300,	"hop-exceed"	},
	{ 0x0301,	"frg-exceed"	},
	{ 0x0400,	"bad-hdr"	},
	{ 0x0401,	"unkn-nhdr"	},
	{ 0x0402,	"unkn-opt"	},
	{ 0x8000,	"echo-reqst"	},
	{ 0x8100,	"echo-repl"	},
	{ 0x8200,	"membr-qry"	},
	{ 0x8300,	"membr-rprt"	},
	{ 0x8400,	"membr-red"	},
	{ 0x8500,	"router-sol"	},
	{ 0x8600,	"router-adv"	},
	{ 0x8700,	"nghbr-sol"	},
	{ 0x8800,	"nghbr-adv"	},
	{ 0x8900,	"redirect"	},
	{ 0, NULL }
};

static void
init_icmpv6array(void)
{
	register int i;
	register struct hnamemem *table;

	for (i = 0; icmpv6_db[i].s != NULL; i++) {
		table = &icmpv6table[icmpv6_db[i].v & (HASHNAMESIZE-1)];
		while (table->name)
			table = table->nxt;
		table->name = icmpv6_db[i].s;
		table->addr = icmpv6_db[i].v;
		table->nxt = newhnamemem();
	}
}

const char *
icmpv6_string(u_short code)
{
	register struct hnamemem *tp;
	register u_int32_t i = code;
	char buf[sizeof("0000")];

	for (tp = &icmpv6table[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
		if (tp->addr == i)
			return (tp->name);

	tp->addr = i;
	tp->nxt = newhnamemem();

	snprintf(buf, sizeof(buf), "%04x", code);
	tp->name = strdup(buf);
	return (tp->name);
}
#endif

/*
 * Initialize the address to name translation machinery.  We map all
 * non-local IP addresses to numeric addresses if fflag is true (i.e.,
 * to prevent blocking on the nameserver).  localnet is the IP address
 * of the local network.  mask is its subnet mask.
 */
void
init_addrtoname()
{
#ifdef	notdef
	if (nflag)
		/*
		 * Simplest way to suppress names.
		 */
		return;
#endif
	init_etherarray();
	init_servarray();
	init_etypearray();
	init_llcsaparray();
	init_protoidarray();
	init_ipxsaparray();
	init_iprotoarray();
	init_icmparray();
#ifdef INET6
	init_icmpv6array();
#endif
}

#ifdef	notdef
const char *
dnaddr_string(u_short dnaddr)
{
	register struct hnamemem *tp;

	for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0;
	     tp = tp->nxt)
		if (tp->addr == dnaddr)
			return (tp->name);

	tp->addr = dnaddr;
	tp->nxt = newhnamemem();
	if (nflag)
		tp->name = dnnum_string(dnaddr);
	else
		tp->name = dnname_string(dnaddr);

	return(tp->name);
}
#endif

/* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
struct hnamemem *
newhnamemem(void)
{
	register struct hnamemem *p;
	static struct hnamemem *ptr = NULL;
	static u_int num = 0;

	if (num  <= 0) {
		num = 64;
		ptr = (struct hnamemem *)calloc(num, sizeof (*ptr));
		if (ptr == NULL)
			error("newhnamemem: calloc");
	}
	--num;
	p = ptr++;
	return (p);
}

#ifdef INET6
/* Return a zero'ed h6namemem struct and cuts down on calloc() overhead */
struct h6namemem *
newh6namemem(void)
{
	register struct h6namemem *p;
	static struct h6namemem *ptr = NULL;
	static u_int num = 0;

	if (num  <= 0) {
		num = 64;
		ptr = (struct h6namemem *)calloc(num, sizeof (*ptr));
		if (ptr == NULL)
			error("newh6namemem: calloc");
	}
	--num;
	p = ptr++;
	return (p);
}
#endif /* INET6 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>