/*
 * Copyright (c) 1991-1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ident	"@(#)trace.c 1.2	99/10/08 SMI"

#include "defs.h"
#include "tables.h"

static void	print_opt(struct nd_opt_hdr *opt, int len);

void
print_route_sol(char *str, struct phyint *pi,
    struct nd_router_solicit *rs, int len, struct sockaddr_in6 *addr)
{
	struct nd_opt_hdr *opt;
	char abuf[INET6_ADDRSTRLEN];

	logdebug("%s %s (%d bytes) on %s\n", str,
	    inet_ntop(addr->sin6_family, (void *)&addr->sin6_addr,
	    abuf, sizeof (abuf)),
	    len, pi->pi_name);

	len -= sizeof (*rs);
	opt = (struct nd_opt_hdr *)&rs[1];
	print_opt(opt, len);
}

void
print_route_adv(char *str, struct phyint *pi,
    struct nd_router_advert *ra, int len, struct sockaddr_in6 *addr)
{
	struct nd_opt_hdr *opt;
	char abuf[INET6_ADDRSTRLEN];

	logdebug("%s %s (%d bytes) on %s\n", str,
	    inet_ntop(addr->sin6_family, (void *)&addr->sin6_addr,
	    abuf, sizeof (abuf)),
	    len, pi->pi_name);
	logdebug("\tMax hop limit: %u\n", ra->nd_ra_curhoplimit);
	logdebug("\tManaged address configuration: %s\n",
	    (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ?
	    "Set" : "Not set");
	logdebug("\tOther configuration flag: %s\n",
	    (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ?
	    "Set" : "Not set");
	logdebug("\tRouter lifetime: %u\n", ntohs(ra->nd_ra_router_lifetime));
	logdebug("\tReachable timer: %lu\n", ntohl(ra->nd_ra_reachable));
	logdebug("\tReachable retrans timer: %lu\n",
	    ntohl(ra->nd_ra_retransmit));

	len -= sizeof (*ra);
	opt = (struct nd_opt_hdr *)&ra[1];
	print_opt(opt, len);
}

static void
print_opt(struct nd_opt_hdr *opt, int len)
{
	struct nd_opt_prefix_info *po;
	struct nd_opt_mtu *mo;
	struct nd_opt_lla *lo;
	int optlen;
	char abuf[INET6_ADDRSTRLEN];
	char llabuf[BUFSIZ];

	while (len >= sizeof (struct nd_opt_hdr)) {
		optlen = opt->nd_opt_len * 8;
		if (optlen == 0) {
			logdebug("Zero length option!\n");
			break;
		}
		switch (opt->nd_opt_type) {
		case ND_OPT_PREFIX_INFORMATION:
			po = (struct nd_opt_prefix_info *)opt;
			if (optlen != sizeof (*po) ||
			    optlen > len)
				break;

			logdebug("\tPrefix: %s/%u\n",
			    inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix,
			    abuf, sizeof (abuf)),
			    po->nd_opt_pi_prefix_len);
			logdebug("\t\tOn link flag:%s\n",
			    (po->nd_opt_pi_flags_reserved &
			    ND_OPT_PI_FLAG_ONLINK) ?
			    "Set" : "Not set");
			logdebug("\t\tAuto addrconf flag:%s\n",
			    (po->nd_opt_pi_flags_reserved &
			    ND_OPT_PI_FLAG_AUTO) ?
			    "Set" : "Not set");
			logdebug("\t\tValid time: %u\n",
			    ntohl(po->nd_opt_pi_valid_time));
			logdebug("\t\tPreferred time: %u\n",
			    ntohl(po->nd_opt_pi_preferred_time));
			break;
		case ND_OPT_MTU:
			mo = (struct nd_opt_mtu *)opt;
			if (optlen != sizeof (*mo) ||
			    optlen > len)
				break;
			logdebug("\tMTU: %d\n",
			    ntohl(mo->nd_opt_mtu_mtu));
			break;
		case ND_OPT_SOURCE_LINKADDR:
			lo = (struct nd_opt_lla *)opt;
			if (optlen < 8 ||
			    optlen > len)
				break;
			(void) fmt_lla(llabuf, sizeof (llabuf),
			    lo->nd_opt_lla_hdw_addr,
			    optlen - sizeof (nd_opt_hdr_t));
			logdebug("\tSource LLA: len %d <%s>\n",
			    optlen - sizeof (nd_opt_hdr_t),
			    llabuf);
			break;
		case ND_OPT_TARGET_LINKADDR:
			lo = (struct nd_opt_lla *)opt;
			if (optlen < 8||
			    optlen > len)
				break;
			(void) fmt_lla(llabuf, sizeof (llabuf),
			    lo->nd_opt_lla_hdw_addr,
			    optlen - sizeof (nd_opt_hdr_t));
			logdebug("\tTarget LLA: len %d <%s>\n",
			    optlen - sizeof (nd_opt_hdr_t),
			    llabuf);
			break;
		case ND_OPT_REDIRECTED_HEADER:
			logdebug("\tRedirected header option!\n");
			break;
		default:
			logdebug("Unknown option %d (0x%x)\n",
			    opt->nd_opt_type, opt->nd_opt_type);
			break;
		}
		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
		len -= optlen;
	}
}

char *
fmt_lla(char *llabuf, int bufsize, uchar_t *lla, int llalen)
{
	int i;
	char *cp = llabuf;

	for (i = 0; i < llalen; i++) {
		if (i == llalen - 1) /* Last byte? */
			(void) snprintf(cp, bufsize, "%02x", lla[i] & 0xFF);
		else
			(void) snprintf(cp, bufsize, "%02x:", lla[i] & 0xFF);
		bufsize -= strlen(cp);
		cp += strlen(cp);
	}
	return (llabuf);
}
