Home | History | Annotate | Download | only in snoop
      1  3431  carlsonj /*
      2  3431  carlsonj  * CDDL HEADER START
      3  3431  carlsonj  *
      4  3431  carlsonj  * The contents of this file are subject to the terms of the
      5  3431  carlsonj  * Common Development and Distribution License (the "License").
      6  3431  carlsonj  * You may not use this file except in compliance with the License.
      7  3431  carlsonj  *
      8  3431  carlsonj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  3431  carlsonj  * or http://www.opensolaris.org/os/licensing.
     10  3431  carlsonj  * See the License for the specific language governing permissions
     11  3431  carlsonj  * and limitations under the License.
     12  3431  carlsonj  *
     13  3431  carlsonj  * When distributing Covered Code, include this CDDL HEADER in each
     14  3431  carlsonj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  3431  carlsonj  * If applicable, add the following below this CDDL HEADER, with the
     16  3431  carlsonj  * fields enclosed by brackets "[]" replaced with your own identifying
     17  3431  carlsonj  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  3431  carlsonj  *
     19  3431  carlsonj  * CDDL HEADER END
     20  3431  carlsonj  */
     21  3431  carlsonj 
     22  3431  carlsonj /*
     23  3431  carlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     24  3431  carlsonj  * Use is subject to license terms.
     25  3431  carlsonj  */
     26  3431  carlsonj 
     27  3431  carlsonj #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28  3431  carlsonj 
     29  3431  carlsonj /*
     30  3431  carlsonj  * Dynamic Host Configuration Protocol version 6, for IPv6.  Supports
     31  3431  carlsonj  * RFCs 3315, 3319, 3646, 3898, 4075, 4242, 4280, 4580, 4649, and 4704.
     32  3431  carlsonj  */
     33  3431  carlsonj 
     34  3431  carlsonj #include <stdio.h>
     35  3431  carlsonj #include <stdlib.h>
     36  3431  carlsonj #include <string.h>
     37  3431  carlsonj #include <time.h>
     38  3431  carlsonj #include <sys/types.h>
     39  3431  carlsonj #include <sys/socket.h>
     40  3431  carlsonj #include <netinet/in.h>
     41  3431  carlsonj #include <netinet/dhcp6.h>
     42  3431  carlsonj #include <arpa/inet.h>
     43  3431  carlsonj #include <dhcp_impl.h>
     44  3431  carlsonj #include <dhcp_inittab.h>
     45  3431  carlsonj 
     46  3431  carlsonj #include "snoop.h"
     47  3431  carlsonj 
     48  3431  carlsonj static const char *mtype_to_str(uint8_t);
     49  3431  carlsonj static const char *option_to_str(uint8_t);
     50  3431  carlsonj static const char *duidtype_to_str(uint16_t);
     51  3431  carlsonj static const char *status_to_str(uint16_t);
     52  3431  carlsonj static const char *entr_to_str(uint32_t);
     53  3431  carlsonj static const char *reconf_to_str(uint8_t);
     54  3431  carlsonj static const char *authproto_to_str(uint8_t);
     55  3431  carlsonj static const char *authalg_to_str(uint8_t, uint8_t);
     56  3431  carlsonj static const char *authrdm_to_str(uint8_t);
     57  3431  carlsonj static const char *cwhat_to_str(uint8_t);
     58  3431  carlsonj static const char *catype_to_str(uint8_t);
     59  3431  carlsonj static void show_hex(const uint8_t *, int, const char *);
     60  3431  carlsonj static void show_ascii(const uint8_t *, int, const char *);
     61  3431  carlsonj static void show_address(const char *, const void *);
     62  3431  carlsonj static void show_options(const uint8_t *, int);
     63  3431  carlsonj 
     64  3431  carlsonj int
     65  3431  carlsonj interpret_dhcpv6(int flags, const uint8_t *data, int len)
     66  3431  carlsonj {
     67  3431  carlsonj 	int olen = len;
     68  3431  carlsonj 	char *line, *lstart;
     69  3431  carlsonj 	dhcpv6_relay_t d6r;
     70  3431  carlsonj 	dhcpv6_message_t d6m;
     71  3431  carlsonj 	uint_t optlen;
     72  3431  carlsonj 	uint16_t statuscode;
     73  3431  carlsonj 
     74  3431  carlsonj 	if (len <= 0) {
     75  3431  carlsonj 		(void) strlcpy(get_sum_line(), "DHCPv6?", MAXLINE);
     76  3431  carlsonj 		return (0);
     77  3431  carlsonj 	}
     78  3431  carlsonj 	if (flags & F_SUM) {
     79  3431  carlsonj 		uint_t ias;
     80  3431  carlsonj 		dhcpv6_option_t *d6o;
     81  3431  carlsonj 		in6_addr_t link, peer;
     82  3431  carlsonj 		char linkstr[INET6_ADDRSTRLEN];
     83  3431  carlsonj 		char peerstr[INET6_ADDRSTRLEN];
     84  3431  carlsonj 
     85  3431  carlsonj 		line = lstart = get_sum_line();
     86  3431  carlsonj 		line += snprintf(line, MAXLINE, "DHCPv6 %s",
     87  3431  carlsonj 		    mtype_to_str(data[0]));
     88  3431  carlsonj 		if (data[0] == DHCPV6_MSG_RELAY_FORW ||
     89  3431  carlsonj 		    data[0] == DHCPV6_MSG_RELAY_REPL) {
     90  3431  carlsonj 			if (len < sizeof (d6r)) {
     91  3431  carlsonj 				(void) strlcpy(line, "?",
     92  3431  carlsonj 				    MAXLINE - (line - lstart));
     93  3431  carlsonj 				return (olen);
     94  3431  carlsonj 			}
     95  3431  carlsonj 			/* Not much in DHCPv6 is aligned. */
     96  3431  carlsonj 			(void) memcpy(&d6r, data, sizeof (d6r));
     97  3431  carlsonj 			(void) memcpy(&link, d6r.d6r_linkaddr, sizeof (link));
     98  3431  carlsonj 			(void) memcpy(&peer, d6r.d6r_peeraddr, sizeof (peer));
     99  3431  carlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
    100  3431  carlsonj 			    " HC=%d link=%s peer=%s", d6r.d6r_hop_count,
    101  3431  carlsonj 			    inet_ntop(AF_INET6, &link, linkstr,
    102  3431  carlsonj 			    sizeof (linkstr)),
    103  3431  carlsonj 			    inet_ntop(AF_INET6, &peer, peerstr,
    104  3431  carlsonj 			    sizeof (peerstr)));
    105  3431  carlsonj 			data += sizeof (d6r);
    106  3431  carlsonj 			len -= sizeof (d6r);
    107  3431  carlsonj 		} else {
    108  3431  carlsonj 			if (len < sizeof (d6m)) {
    109  3431  carlsonj 				(void) strlcpy(line, "?",
    110  3431  carlsonj 				    MAXLINE - (line - lstart));
    111  3431  carlsonj 				return (olen);
    112  3431  carlsonj 			}
    113  3431  carlsonj 			(void) memcpy(&d6m, data, sizeof (d6m));
    114  3431  carlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
    115  3431  carlsonj 			    " xid=%x", DHCPV6_GET_TRANSID(&d6m));
    116  3431  carlsonj 			data += sizeof (d6m);
    117  3431  carlsonj 			len -= sizeof (d6m);
    118  3431  carlsonj 		}
    119  3431  carlsonj 		ias = 0;
    120  3431  carlsonj 		d6o = NULL;
    121  3431  carlsonj 		while ((d6o = dhcpv6_find_option(data, len, d6o,
    122  3431  carlsonj 		    DHCPV6_OPT_IA_NA, NULL)) != NULL)
    123  3431  carlsonj 			ias++;
    124  3431  carlsonj 		if (ias > 0)
    125  3431  carlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
    126  3431  carlsonj 			    " IAs=%u", ias);
    127  3431  carlsonj 		d6o = dhcpv6_find_option(data, len, NULL,
    128  3431  carlsonj 		    DHCPV6_OPT_STATUS_CODE, &optlen);
    129  3431  carlsonj 		optlen -= sizeof (*d6o);
    130  3431  carlsonj 		if (d6o != NULL && optlen >= sizeof (statuscode)) {
    131  3431  carlsonj 			(void) memcpy(&statuscode, d6o + 1,
    132  3431  carlsonj 			    sizeof (statuscode));
    133  3431  carlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
    134  3431  carlsonj 			    " status=%u", ntohs(statuscode));
    135  3431  carlsonj 			optlen -= sizeof (statuscode);
    136  3431  carlsonj 			if (optlen > 0) {
    137  3431  carlsonj 				line += snprintf(line,
    138  3431  carlsonj 				    MAXLINE - (line - lstart), " \"%.*s\"",
    139  3431  carlsonj 				    optlen, (char *)(d6o + 1) + 2);
    140  3431  carlsonj 			}
    141  3431  carlsonj 		}
    142  3431  carlsonj 		d6o = dhcpv6_find_option(data, len, NULL,
    143  3431  carlsonj 		    DHCPV6_OPT_RELAY_MSG, &optlen);
    144  3431  carlsonj 		optlen -= sizeof (*d6o);
    145  3431  carlsonj 		if (d6o != NULL && optlen >= 1) {
    146  3431  carlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
    147  3431  carlsonj 			    " relay=%s", mtype_to_str(*(uint8_t *)(d6o + 1)));
    148  3431  carlsonj 		}
    149  3431  carlsonj 	} else if (flags & F_DTAIL) {
    150  3431  carlsonj 		show_header("DHCPv6: ",
    151  3431  carlsonj 		    "Dynamic Host Configuration Protocol Version 6", len);
    152  3431  carlsonj 		show_space();
    153  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
    154  3431  carlsonj 		    "Message type (msg-type) = %u (%s)", data[0],
    155  3431  carlsonj 		    mtype_to_str(data[0]));
    156  3431  carlsonj 		if (data[0] == DHCPV6_MSG_RELAY_FORW ||
    157  3431  carlsonj 		    data[0] == DHCPV6_MSG_RELAY_REPL) {
    158  3431  carlsonj 			if (len < sizeof (d6r)) {
    159  3431  carlsonj 				(void) strlcpy(get_line(0, 0), "Truncated",
    160  3431  carlsonj 				    get_line_remain());
    161  3431  carlsonj 				return (olen);
    162  3431  carlsonj 			}
    163  3431  carlsonj 			(void) memcpy(&d6r, data, sizeof (d6r));
    164  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    165  3431  carlsonj 			    "Hop count = %u", d6r.d6r_hop_count);
    166  3431  carlsonj 			show_address("Link address", d6r.d6r_linkaddr);
    167  3431  carlsonj 			show_address("Peer address", d6r.d6r_peeraddr);
    168  3431  carlsonj 			data += sizeof (d6r);
    169  3431  carlsonj 			len -= sizeof (d6r);
    170  3431  carlsonj 		} else {
    171  3431  carlsonj 			if (len < sizeof (d6m)) {
    172  3431  carlsonj 				(void) strlcpy(get_line(0, 0), "Truncated",
    173  3431  carlsonj 				    get_line_remain());
    174  3431  carlsonj 				return (olen);
    175  3431  carlsonj 			}
    176  3431  carlsonj 			(void) memcpy(&d6m, data, sizeof (d6m));
    177  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    178  3431  carlsonj 			    "Transaction ID = %x", DHCPV6_GET_TRANSID(&d6m));
    179  3431  carlsonj 			data += sizeof (d6m);
    180  3431  carlsonj 			len -= sizeof (d6m);
    181  3431  carlsonj 		}
    182  3431  carlsonj 		show_space();
    183  3431  carlsonj 		show_options(data, len);
    184  3431  carlsonj 		show_space();
    185  3431  carlsonj 	}
    186  3431  carlsonj 	return (olen);
    187  3431  carlsonj }
    188  3431  carlsonj 
    189  3431  carlsonj static const char *
    190  3431  carlsonj mtype_to_str(uint8_t mtype)
    191  3431  carlsonj {
    192  3431  carlsonj 	switch (mtype) {
    193  3431  carlsonj 	case DHCPV6_MSG_SOLICIT:
    194  3431  carlsonj 		return ("Solicit");
    195  3431  carlsonj 	case DHCPV6_MSG_ADVERTISE:
    196  3431  carlsonj 		return ("Advertise");
    197  3431  carlsonj 	case DHCPV6_MSG_REQUEST:
    198  3431  carlsonj 		return ("Request");
    199  3431  carlsonj 	case DHCPV6_MSG_CONFIRM:
    200  3431  carlsonj 		return ("Confirm");
    201  3431  carlsonj 	case DHCPV6_MSG_RENEW:
    202  3431  carlsonj 		return ("Renew");
    203  3431  carlsonj 	case DHCPV6_MSG_REBIND:
    204  3431  carlsonj 		return ("Rebind");
    205  3431  carlsonj 	case DHCPV6_MSG_REPLY:
    206  3431  carlsonj 		return ("Reply");
    207  3431  carlsonj 	case DHCPV6_MSG_RELEASE:
    208  3431  carlsonj 		return ("Release");
    209  3431  carlsonj 	case DHCPV6_MSG_DECLINE:
    210  3431  carlsonj 		return ("Decline");
    211  3431  carlsonj 	case DHCPV6_MSG_RECONFIGURE:
    212  3431  carlsonj 		return ("Reconfigure");
    213  3431  carlsonj 	case DHCPV6_MSG_INFO_REQ:
    214  3431  carlsonj 		return ("Information-Request");
    215  3431  carlsonj 	case DHCPV6_MSG_RELAY_FORW:
    216  3431  carlsonj 		return ("Relay-Forward");
    217  3431  carlsonj 	case DHCPV6_MSG_RELAY_REPL:
    218  3431  carlsonj 		return ("Relay-Reply");
    219  3431  carlsonj 	default:
    220  3431  carlsonj 		return ("Unknown");
    221  3431  carlsonj 	}
    222  3431  carlsonj }
    223  3431  carlsonj 
    224  3431  carlsonj static const char *
    225  3431  carlsonj option_to_str(uint8_t mtype)
    226  3431  carlsonj {
    227  3431  carlsonj 	switch (mtype) {
    228  3431  carlsonj 	case DHCPV6_OPT_CLIENTID:
    229  3431  carlsonj 		return ("Client Identifier");
    230  3431  carlsonj 	case DHCPV6_OPT_SERVERID:
    231  3431  carlsonj 		return ("Server Identifier");
    232  3431  carlsonj 	case DHCPV6_OPT_IA_NA:
    233  3431  carlsonj 		return ("Identity Association for Non-temporary Addresses");
    234  3431  carlsonj 	case DHCPV6_OPT_IA_TA:
    235  3431  carlsonj 		return ("Identity Association for Temporary Addresses");
    236  3431  carlsonj 	case DHCPV6_OPT_IAADDR:
    237  3431  carlsonj 		return ("IA Address");
    238  3431  carlsonj 	case DHCPV6_OPT_ORO:
    239  3431  carlsonj 		return ("Option Request");
    240  3431  carlsonj 	case DHCPV6_OPT_PREFERENCE:
    241  3431  carlsonj 		return ("Preference");
    242  3431  carlsonj 	case DHCPV6_OPT_ELAPSED_TIME:
    243  3431  carlsonj 		return ("Elapsed Time");
    244  3431  carlsonj 	case DHCPV6_OPT_RELAY_MSG:
    245  3431  carlsonj 		return ("Relay Message");
    246  3431  carlsonj 	case DHCPV6_OPT_AUTH:
    247  3431  carlsonj 		return ("Authentication");
    248  3431  carlsonj 	case DHCPV6_OPT_UNICAST:
    249  3431  carlsonj 		return ("Server Unicast");
    250  3431  carlsonj 	case DHCPV6_OPT_STATUS_CODE:
    251  3431  carlsonj 		return ("Status Code");
    252  3431  carlsonj 	case DHCPV6_OPT_RAPID_COMMIT:
    253  3431  carlsonj 		return ("Rapid Commit");
    254  3431  carlsonj 	case DHCPV6_OPT_USER_CLASS:
    255  3431  carlsonj 		return ("User Class");
    256  3431  carlsonj 	case DHCPV6_OPT_VENDOR_CLASS:
    257  3431  carlsonj 		return ("Vendor Class");
    258  3431  carlsonj 	case DHCPV6_OPT_VENDOR_OPT:
    259  3431  carlsonj 		return ("Vendor-specific Information");
    260  3431  carlsonj 	case DHCPV6_OPT_INTERFACE_ID:
    261  3431  carlsonj 		return ("Interface-Id");
    262  3431  carlsonj 	case DHCPV6_OPT_RECONF_MSG:
    263  3431  carlsonj 		return ("Reconfigure Message");
    264  3431  carlsonj 	case DHCPV6_OPT_RECONF_ACC:
    265  3431  carlsonj 		return ("Reconfigure Accept");
    266  3431  carlsonj 	case DHCPV6_OPT_SIP_NAMES:
    267  3431  carlsonj 		return ("SIP Servers Domain Name List");
    268  3431  carlsonj 	case DHCPV6_OPT_SIP_ADDR:
    269  3431  carlsonj 		return ("SIP Servers IPv6 Address List");
    270  3431  carlsonj 	case DHCPV6_OPT_DNS_ADDR:
    271  3431  carlsonj 		return ("DNS Recursive Name Server");
    272  3431  carlsonj 	case DHCPV6_OPT_DNS_SEARCH:
    273  3431  carlsonj 		return ("Domain Search List");
    274  3431  carlsonj 	case DHCPV6_OPT_IA_PD:
    275  3431  carlsonj 		return ("Identity Association for Prefix Delegation");
    276  3431  carlsonj 	case DHCPV6_OPT_IAPREFIX:
    277  3431  carlsonj 		return ("IA_PD Prefix");
    278  3431  carlsonj 	case DHCPV6_OPT_NIS_SERVERS:
    279  3431  carlsonj 		return ("Network Information Service Servers");
    280  3431  carlsonj 	case DHCPV6_OPT_NISP_SERVERS:
    281  3431  carlsonj 		return ("Network Information Service V2 Servers");
    282  3431  carlsonj 	case DHCPV6_OPT_NIS_DOMAIN:
    283  3431  carlsonj 		return ("Network Information Service Domain Name");
    284  3431  carlsonj 	case DHCPV6_OPT_NISP_DOMAIN:
    285  3431  carlsonj 		return ("Network Information Service V2 Domain Name");
    286  3431  carlsonj 	case DHCPV6_OPT_SNTP_SERVERS:
    287  3431  carlsonj 		return ("Simple Network Time Protocol Servers");
    288  3431  carlsonj 	case DHCPV6_OPT_INFO_REFTIME:
    289  3431  carlsonj 		return ("Information Refresh Time");
    290  3431  carlsonj 	case DHCPV6_OPT_BCMCS_SRV_D:
    291  3431  carlsonj 		return ("BCMCS Controller Domain Name List");
    292  3431  carlsonj 	case DHCPV6_OPT_BCMCS_SRV_A:
    293  3431  carlsonj 		return ("BCMCS Controller IPv6 Address");
    294  3431  carlsonj 	case DHCPV6_OPT_GEOCONF_CVC:
    295  3431  carlsonj 		return ("Civic Location");
    296  3431  carlsonj 	case DHCPV6_OPT_REMOTE_ID:
    297  3431  carlsonj 		return ("Relay Agent Remote-ID");
    298  3431  carlsonj 	case DHCPV6_OPT_SUBSCRIBER:
    299  3431  carlsonj 		return ("Relay Agent Subscriber-ID");
    300  3431  carlsonj 	case DHCPV6_OPT_CLIENT_FQDN:
    301  3431  carlsonj 		return ("Client FQDN");
    302  3431  carlsonj 	default:
    303  3431  carlsonj 		return ("Unknown");
    304  3431  carlsonj 	}
    305  3431  carlsonj }
    306  3431  carlsonj 
    307  3431  carlsonj static const char *
    308  3431  carlsonj duidtype_to_str(uint16_t dtype)
    309  3431  carlsonj {
    310  3431  carlsonj 	switch (dtype) {
    311  3431  carlsonj 	case DHCPV6_DUID_LLT:
    312  3431  carlsonj 		return ("Link-layer Address Plus Time");
    313  3431  carlsonj 	case DHCPV6_DUID_EN:
    314  3431  carlsonj 		return ("Enterprise Number");
    315  3431  carlsonj 	case DHCPV6_DUID_LL:
    316  3431  carlsonj 		return ("Link-layer Address");
    317  3431  carlsonj 	default:
    318  3431  carlsonj 		return ("Unknown");
    319  3431  carlsonj 	}
    320  3431  carlsonj }
    321  3431  carlsonj 
    322  3431  carlsonj static const char *
    323  3431  carlsonj status_to_str(uint16_t status)
    324  3431  carlsonj {
    325  3431  carlsonj 	switch (status) {
    326  3431  carlsonj 	case DHCPV6_STAT_SUCCESS:
    327  3431  carlsonj 		return ("Success");
    328  3431  carlsonj 	case DHCPV6_STAT_UNSPECFAIL:
    329  3431  carlsonj 		return ("Failure, reason unspecified");
    330  3431  carlsonj 	case DHCPV6_STAT_NOADDRS:
    331  3431  carlsonj 		return ("No addresses for IAs");
    332  3431  carlsonj 	case DHCPV6_STAT_NOBINDING:
    333  3431  carlsonj 		return ("Client binding unavailable");
    334  3431  carlsonj 	case DHCPV6_STAT_NOTONLINK:
    335  3431  carlsonj 		return ("Prefix not on link");
    336  3431  carlsonj 	case DHCPV6_STAT_USEMCAST:
    337  3431  carlsonj 		return ("Use multicast");
    338  3431  carlsonj 	case DHCPV6_STAT_NOPREFIX:
    339  3431  carlsonj 		return ("No prefix available");
    340  3431  carlsonj 	default:
    341  3431  carlsonj 		return ("Unknown");
    342  3431  carlsonj 	}
    343  3431  carlsonj }
    344  3431  carlsonj 
    345  3431  carlsonj static const char *
    346  3431  carlsonj entr_to_str(uint32_t entr)
    347  3431  carlsonj {
    348  3431  carlsonj 	switch (entr) {
    349  3431  carlsonj 	case DHCPV6_SUN_ENT:
    350  3431  carlsonj 		return ("Sun Microsystems");
    351  3431  carlsonj 	default:
    352  3431  carlsonj 		return ("Unknown");
    353  3431  carlsonj 	}
    354  3431  carlsonj }
    355  3431  carlsonj 
    356  3431  carlsonj static const char *
    357  3431  carlsonj reconf_to_str(uint8_t msgtype)
    358  3431  carlsonj {
    359  3431  carlsonj 	switch (msgtype) {
    360  3431  carlsonj 	case DHCPV6_RECONF_RENEW:
    361  3431  carlsonj 		return ("Renew");
    362  3431  carlsonj 	case DHCPV6_RECONF_INFO:
    363  3431  carlsonj 		return ("Information-request");
    364  3431  carlsonj 	default:
    365  3431  carlsonj 		return ("Unknown");
    366  3431  carlsonj 	}
    367  3431  carlsonj }
    368  3431  carlsonj 
    369  3431  carlsonj static const char *
    370  3431  carlsonj authproto_to_str(uint8_t aproto)
    371  3431  carlsonj {
    372  3431  carlsonj 	switch (aproto) {
    373  3431  carlsonj 	case DHCPV6_PROTO_DELAYED:
    374  3431  carlsonj 		return ("Delayed");
    375  3431  carlsonj 	case DHCPV6_PROTO_RECONFIG:
    376  3431  carlsonj 		return ("Reconfigure Key");
    377  3431  carlsonj 	default:
    378  3431  carlsonj 		return ("Unknown");
    379  3431  carlsonj 	}
    380  3431  carlsonj }
    381  3431  carlsonj 
    382  3431  carlsonj static const char *
    383  3431  carlsonj authalg_to_str(uint8_t aproto, uint8_t aalg)
    384  3431  carlsonj {
    385  3431  carlsonj 	switch (aproto) {
    386  3431  carlsonj 	case DHCPV6_PROTO_DELAYED:
    387  3431  carlsonj 	case DHCPV6_PROTO_RECONFIG:
    388  3431  carlsonj 		switch (aalg) {
    389  3431  carlsonj 		case DHCPV6_ALG_HMAC_MD5:
    390  3431  carlsonj 			return ("HMAC-MD5 Signature");
    391  3431  carlsonj 		default:
    392  3431  carlsonj 			return ("Unknown");
    393  3431  carlsonj 		}
    394  3431  carlsonj 		break;
    395  3431  carlsonj 	default:
    396  3431  carlsonj 		return ("Unknown");
    397  3431  carlsonj 	}
    398  3431  carlsonj }
    399  3431  carlsonj 
    400  3431  carlsonj static const char *
    401  3431  carlsonj authrdm_to_str(uint8_t ardm)
    402  3431  carlsonj {
    403  3431  carlsonj 	switch (ardm) {
    404  3431  carlsonj 	case DHCPV6_RDM_MONOCNT:
    405  3431  carlsonj 		return ("Monotonic Counter");
    406  3431  carlsonj 	default:
    407  3431  carlsonj 		return ("Unknown");
    408  3431  carlsonj 	}
    409  3431  carlsonj }
    410  3431  carlsonj 
    411  3431  carlsonj static const char *
    412  3431  carlsonj cwhat_to_str(uint8_t what)
    413  3431  carlsonj {
    414  3431  carlsonj 	switch (what) {
    415  3431  carlsonj 	case DHCPV6_CWHAT_SERVER:
    416  3431  carlsonj 		return ("Server");
    417  3431  carlsonj 	case DHCPV6_CWHAT_NETWORK:
    418  3431  carlsonj 		return ("Network");
    419  3431  carlsonj 	case DHCPV6_CWHAT_CLIENT:
    420  3431  carlsonj 		return ("Client");
    421  3431  carlsonj 	default:
    422  3431  carlsonj 		return ("Unknown");
    423  3431  carlsonj 	}
    424  3431  carlsonj }
    425  3431  carlsonj 
    426  3431  carlsonj static const char *
    427  3431  carlsonj catype_to_str(uint8_t catype)
    428  3431  carlsonj {
    429  3431  carlsonj 	switch (catype) {
    430  3431  carlsonj 	case CIVICADDR_LANG:
    431  3431  carlsonj 		return ("Language; RFC 2277");
    432  3431  carlsonj 	case CIVICADDR_A1:
    433  3431  carlsonj 		return ("National division (state)");
    434  3431  carlsonj 	case CIVICADDR_A2:
    435  3431  carlsonj 		return ("County");
    436  3431  carlsonj 	case CIVICADDR_A3:
    437  3431  carlsonj 		return ("City");
    438  3431  carlsonj 	case CIVICADDR_A4:
    439  3431  carlsonj 		return ("City division");
    440  3431  carlsonj 	case CIVICADDR_A5:
    441  3431  carlsonj 		return ("Neighborhood");
    442  3431  carlsonj 	case CIVICADDR_A6:
    443  3431  carlsonj 		return ("Street group");
    444  3431  carlsonj 	case CIVICADDR_PRD:
    445  3431  carlsonj 		return ("Leading street direction");
    446  3431  carlsonj 	case CIVICADDR_POD:
    447  3431  carlsonj 		return ("Trailing street suffix");
    448  3431  carlsonj 	case CIVICADDR_STS:
    449  3431  carlsonj 		return ("Street suffix or type");
    450  3431  carlsonj 	case CIVICADDR_HNO:
    451  3431  carlsonj 		return ("House number");
    452  3431  carlsonj 	case CIVICADDR_HNS:
    453  3431  carlsonj 		return ("House number suffix");
    454  3431  carlsonj 	case CIVICADDR_LMK:
    455  3431  carlsonj 		return ("Landmark");
    456  3431  carlsonj 	case CIVICADDR_LOC:
    457  3431  carlsonj 		return ("Additional location information");
    458  3431  carlsonj 	case CIVICADDR_NAM:
    459  3431  carlsonj 		return ("Name/occupant");
    460  3431  carlsonj 	case CIVICADDR_PC:
    461  3431  carlsonj 		return ("Postal Code/ZIP");
    462  3431  carlsonj 	case CIVICADDR_BLD:
    463  3431  carlsonj 		return ("Building");
    464  3431  carlsonj 	case CIVICADDR_UNIT:
    465  3431  carlsonj 		return ("Unit/apt/suite");
    466  3431  carlsonj 	case CIVICADDR_FLR:
    467  3431  carlsonj 		return ("Floor");
    468  3431  carlsonj 	case CIVICADDR_ROOM:
    469  3431  carlsonj 		return ("Room number");
    470  3431  carlsonj 	case CIVICADDR_TYPE:
    471  3431  carlsonj 		return ("Place type");
    472  3431  carlsonj 	case CIVICADDR_PCN:
    473  3431  carlsonj 		return ("Postal community name");
    474  3431  carlsonj 	case CIVICADDR_POBOX:
    475  3431  carlsonj 		return ("Post office box");
    476  3431  carlsonj 	case CIVICADDR_ADDL:
    477  3431  carlsonj 		return ("Additional code");
    478  3431  carlsonj 	case CIVICADDR_SEAT:
    479  3431  carlsonj 		return ("Seat/desk");
    480  3431  carlsonj 	case CIVICADDR_ROAD:
    481  3431  carlsonj 		return ("Primary road or street");
    482  3431  carlsonj 	case CIVICADDR_RSEC:
    483  3431  carlsonj 		return ("Road section");
    484  3431  carlsonj 	case CIVICADDR_RBRA:
    485  3431  carlsonj 		return ("Road branch");
    486  3431  carlsonj 	case CIVICADDR_RSBR:
    487  3431  carlsonj 		return ("Road sub-branch");
    488  3431  carlsonj 	case CIVICADDR_SPRE:
    489  3431  carlsonj 		return ("Street name pre-modifier");
    490  3431  carlsonj 	case CIVICADDR_SPOST:
    491  3431  carlsonj 		return ("Street name post-modifier");
    492  3431  carlsonj 	case CIVICADDR_SCRIPT:
    493  3431  carlsonj 		return ("Script");
    494  3431  carlsonj 	default:
    495  3431  carlsonj 		return ("Unknown");
    496  3431  carlsonj 	}
    497  3431  carlsonj }
    498  3431  carlsonj 
    499  3431  carlsonj static void
    500  3431  carlsonj show_hex(const uint8_t *data, int len, const char *name)
    501  3431  carlsonj {
    502  3431  carlsonj 	char buffer[16 * 3 + 1];
    503  3431  carlsonj 	int nlen;
    504  3431  carlsonj 	int i;
    505  3431  carlsonj 	char sep;
    506  3431  carlsonj 
    507  3431  carlsonj 	nlen = strlen(name);
    508  3431  carlsonj 	sep = '=';
    509  3431  carlsonj 	while (len > 0) {
    510  3431  carlsonj 		for (i = 0; i < 16 && i < len; i++)
    511  3431  carlsonj 			(void) snprintf(buffer + 3 * i, 4, " %02x", *data++);
    512  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(), "%*s %c%s",
    513  3431  carlsonj 		    nlen, name, sep, buffer);
    514  3431  carlsonj 		name = "";
    515  3431  carlsonj 		sep = ' ';
    516  3431  carlsonj 		len -= i;
    517  3431  carlsonj 	}
    518  3431  carlsonj }
    519  3431  carlsonj 
    520  3431  carlsonj static void
    521  3431  carlsonj show_ascii(const uint8_t *data, int len, const char *name)
    522  3431  carlsonj {
    523  3431  carlsonj 	char buffer[64], *bp;
    524  3431  carlsonj 	int nlen;
    525  3431  carlsonj 	int i;
    526  3431  carlsonj 	char sep;
    527  3431  carlsonj 
    528  3431  carlsonj 	nlen = strlen(name);
    529  3431  carlsonj 	sep = '=';
    530  3431  carlsonj 	while (len > 0) {
    531  3431  carlsonj 		bp = buffer;
    532  3431  carlsonj 		for (i = 0; i < sizeof (buffer) - 4 && len > 0; len--) {
    533  3431  carlsonj 			if (!isascii(*data) || !isprint(*data))
    534  3431  carlsonj 				bp += snprintf(bp, 5, "\\%03o", *data++);
    535  3431  carlsonj 			else
    536  3431  carlsonj 				*bp++;
    537  3431  carlsonj 		}
    538  3431  carlsonj 		*bp = '\0';
    539  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
    540  3431  carlsonj 		    "%*s %c \"%s\"", nlen, name, sep, buffer);
    541  3431  carlsonj 		sep = ' ';
    542  3431  carlsonj 		name = "";
    543  3431  carlsonj 	}
    544  3431  carlsonj }
    545  3431  carlsonj 
    546  3431  carlsonj static void
    547  3431  carlsonj show_address(const char *addrname, const void *aptr)
    548  3431  carlsonj {
    549  3431  carlsonj 	char *hname;
    550  3431  carlsonj 	char addrstr[INET6_ADDRSTRLEN];
    551  3431  carlsonj 	in6_addr_t addr;
    552  3431  carlsonj 
    553  3431  carlsonj 	(void) memcpy(&addr, aptr, sizeof (in6_addr_t));
    554  3431  carlsonj 	(void) inet_ntop(AF_INET6, &addr, addrstr, sizeof (addrstr));
    555  3431  carlsonj 	hname = addrtoname(AF_INET6, &addr);
    556  3431  carlsonj 	if (strcmp(hname, addrstr) == 0) {
    557  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(), "%s = %s",
    558  3431  carlsonj 		    addrname, addrstr);
    559  3431  carlsonj 	} else {
    560  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
    561  3431  carlsonj 		    "%s = %s (%s)", addrname, addrstr, hname);
    562  3431  carlsonj 	}
    563  3431  carlsonj }
    564  3431  carlsonj 
    565  3431  carlsonj static void
    566  3431  carlsonj nest_options(const uint8_t *data, uint_t olen, char *prefix, char *title)
    567  3431  carlsonj {
    568  3431  carlsonj 	char *str, *oldnest, *oldprefix;
    569  3431  carlsonj 
    570  3431  carlsonj 	if (olen <= 0)
    571  3431  carlsonj 		return;
    572  3431  carlsonj 	oldprefix = prot_prefix;
    573  3431  carlsonj 	oldnest = prot_nest_prefix;
    574  3431  carlsonj 	str = malloc(strlen(prot_nest_prefix) + strlen(prot_prefix) + 1);
    575  3431  carlsonj 	if (str == NULL) {
    576  3431  carlsonj 		prot_nest_prefix = prot_prefix;
    577  3431  carlsonj 	} else {
    578  3431  carlsonj 		(void) sprintf(str, "%s%s", prot_nest_prefix, prot_prefix);
    579  3431  carlsonj 		prot_nest_prefix = str;
    580  3431  carlsonj 	}
    581  3431  carlsonj 	show_header(prefix, title, 0);
    582  3431  carlsonj 	show_options(data, olen);
    583  3431  carlsonj 	free(str);
    584  3431  carlsonj 	prot_prefix = oldprefix;
    585  3431  carlsonj 	prot_nest_prefix = oldnest;
    586  3431  carlsonj }
    587  3431  carlsonj 
    588  3431  carlsonj static void
    589  3431  carlsonj show_options(const uint8_t *data, int len)
    590  3431  carlsonj {
    591  3431  carlsonj 	dhcpv6_option_t d6o;
    592  3431  carlsonj 	uint_t olen, retlen;
    593  3431  carlsonj 	uint16_t val16;
    594  3431  carlsonj 	uint16_t type;
    595  3431  carlsonj 	uint32_t val32;
    596  3431  carlsonj 	const uint8_t *ostart;
    597  3431  carlsonj 	char *str, *sp;
    598  3431  carlsonj 	char *oldnest;
    599  3431  carlsonj 
    600  3431  carlsonj 	/*
    601  3431  carlsonj 	 * Be very careful with negative numbers; ANSI signed/unsigned
    602  3431  carlsonj 	 * comparison doesn't work as expected.
    603  3431  carlsonj 	 */
    604  3431  carlsonj 	while (len >= (signed)sizeof (d6o)) {
    605  3431  carlsonj 		(void) memcpy(&d6o, data, sizeof (d6o));
    606  3431  carlsonj 		d6o.d6o_code = ntohs(d6o.d6o_code);
    607  3431  carlsonj 		d6o.d6o_len = olen = ntohs(d6o.d6o_len);
    608  3431  carlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
    609  3431  carlsonj 		    "Option Code = %u (%s)", d6o.d6o_code,
    610  3431  carlsonj 		    option_to_str(d6o.d6o_code));
    611  3431  carlsonj 		ostart = data += sizeof (d6o);
    612  3431  carlsonj 		len -= sizeof (d6o);
    613  3431  carlsonj 		if (olen > len) {
    614  3431  carlsonj 			(void) strlcpy(get_line(0, 0), "Option truncated",
    615  3431  carlsonj 			    get_line_remain());
    616  3431  carlsonj 			olen = len;
    617  3431  carlsonj 		}
    618  3431  carlsonj 		switch (d6o.d6o_code) {
    619  3431  carlsonj 		case DHCPV6_OPT_CLIENTID:
    620  3431  carlsonj 		case DHCPV6_OPT_SERVERID:
    621  3431  carlsonj 			if (olen < sizeof (val16))
    622  3431  carlsonj 				break;
    623  3431  carlsonj 			(void) memcpy(&val16, data, sizeof (val16));
    624  3431  carlsonj 			data += sizeof (val16);
    625  3431  carlsonj 			olen -= sizeof (val16);
    626  3431  carlsonj 			type = ntohs(val16);
    627  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    628  3431  carlsonj 			    "  DUID Type = %u (%s)", type,
    629  3431  carlsonj 			    duidtype_to_str(type));
    630  3431  carlsonj 			if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
    631  3431  carlsonj 				if (olen < sizeof (val16))
    632  3431  carlsonj 					break;
    633  3431  carlsonj 				(void) memcpy(&val16, data, sizeof (val16));
    634  3431  carlsonj 				data += sizeof (val16);
    635  3431  carlsonj 				olen -= sizeof (val16);
    636  3431  carlsonj 				val16 = ntohs(val16);
    637  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    638  3431  carlsonj 				    get_line_remain(),
    639  3431  carlsonj 				    "  Hardware Type = %u (%s)", val16,
    640  3431  carlsonj 				    arp_htype(type));
    641  3431  carlsonj 			}
    642  3431  carlsonj 			if (type == DHCPV6_DUID_LLT) {
    643  3431  carlsonj 				time_t timevalue;
    644  3431  carlsonj 
    645  3431  carlsonj 				if (olen < sizeof (val32))
    646  3431  carlsonj 					break;
    647  3431  carlsonj 				(void) memcpy(&val32, data, sizeof (val32));
    648  3431  carlsonj 				data += sizeof (val32);
    649  3431  carlsonj 				olen -= sizeof (val32);
    650  3431  carlsonj 				timevalue = ntohl(val32) + DUID_TIME_BASE;
    651  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    652  3431  carlsonj 				    get_line_remain(),
    653  3431  carlsonj 				    "  Time = %lu (%.24s)", ntohl(val32),
    654  3431  carlsonj 				    ctime(&timevalue));
    655  3431  carlsonj 			}
    656  3431  carlsonj 			if (type == DHCPV6_DUID_EN) {
    657  3431  carlsonj 				if (olen < sizeof (val32))
    658  3431  carlsonj 					break;
    659  3431  carlsonj 				(void) memcpy(&val32, data, sizeof (val32));
    660  3431  carlsonj 				data += sizeof (val32);
    661  3431  carlsonj 				olen -= sizeof (val32);
    662  3431  carlsonj 				val32 = ntohl(val32);
    663  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    664  3431  carlsonj 				    get_line_remain(),
    665  3431  carlsonj 				    "  Enterprise Number = %lu (%s)", val32,
    666  3431  carlsonj 				    entr_to_str(val32));
    667  3431  carlsonj 			}
    668  3431  carlsonj 			if (olen == 0)
    669  3431  carlsonj 				break;
    670  3431  carlsonj 			if ((str = malloc(olen * 3)) == NULL)
    671  3431  carlsonj 				pr_err("interpret_dhcpv6: no mem");
    672  3431  carlsonj 			sp = str + snprintf(str, 3, "%02x", *data++);
    673  3431  carlsonj 			while (--olen > 0) {
    674  3431  carlsonj 				*sp++ = (type == DHCPV6_DUID_LLT ||
    675  3431  carlsonj 				    type == DHCPV6_DUID_LL) ? ':' : ' ';
    676  3431  carlsonj 				sp = sp + snprintf(sp, 3, "%02x", *data++);
    677  3431  carlsonj 			}
    678  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    679  3431  carlsonj 			    (type == DHCPV6_DUID_LLT ||
    680  3431  carlsonj 			    type == DHCPV6_DUID_LL) ?
    681  3431  carlsonj 			    "  Link Layer Address = %s" :
    682  3431  carlsonj 			    "  Identifier = %s", str);
    683  3431  carlsonj 			free(str);
    684  3431  carlsonj 			break;
    685  3431  carlsonj 		case DHCPV6_OPT_IA_NA:
    686  3431  carlsonj 		case DHCPV6_OPT_IA_PD: {
    687  3431  carlsonj 			dhcpv6_ia_na_t d6in;
    688  3431  carlsonj 
    689  3431  carlsonj 			if (olen < sizeof (d6in) - sizeof (d6o))
    690  3431  carlsonj 				break;
    691  3431  carlsonj 			(void) memcpy(&d6in, data - sizeof (d6o),
    692  3431  carlsonj 			    sizeof (d6in));
    693  3431  carlsonj 			data += sizeof (d6in) - sizeof (d6o);
    694  3431  carlsonj 			olen -= sizeof (d6in) - sizeof (d6o);
    695  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    696  3431  carlsonj 			    "  IAID = %u", ntohl(d6in.d6in_iaid));
    697  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    698  3431  carlsonj 			    "  T1 (renew) = %u seconds", ntohl(d6in.d6in_t1));
    699  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    700  3431  carlsonj 			    "  T2 (rebind) = %u seconds", ntohl(d6in.d6in_t2));
    701  3431  carlsonj 			nest_options(data, olen, "IA: ",
    702  3431  carlsonj 			    "Identity Association");
    703  3431  carlsonj 			break;
    704  3431  carlsonj 		}
    705  3431  carlsonj 		case DHCPV6_OPT_IA_TA: {
    706  3431  carlsonj 			dhcpv6_ia_ta_t d6it;
    707  3431  carlsonj 
    708  3431  carlsonj 			if (olen < sizeof (d6it) - sizeof (d6o))
    709  3431  carlsonj 				break;
    710  3431  carlsonj 			(void) memcpy(&d6it, data - sizeof (d6o),
    711  3431  carlsonj 			    sizeof (d6it));
    712  3431  carlsonj 			data += sizeof (d6it) - sizeof (d6o);
    713  3431  carlsonj 			olen -= sizeof (d6it) - sizeof (d6o);
    714  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    715  3431  carlsonj 			    "  IAID = %u", ntohl(d6it.d6it_iaid));
    716  3431  carlsonj 			nest_options(data, olen, "IA: ",
    717  3431  carlsonj 			    "Identity Association");
    718  3431  carlsonj 			break;
    719  3431  carlsonj 		}
    720  3431  carlsonj 		case DHCPV6_OPT_IAADDR: {
    721  3431  carlsonj 			dhcpv6_iaaddr_t d6ia;
    722  3431  carlsonj 
    723  3431  carlsonj 			if (olen < sizeof (d6ia) - sizeof (d6o))
    724  3431  carlsonj 				break;
    725  3431  carlsonj 			(void) memcpy(&d6ia, data - sizeof (d6o),
    726  3431  carlsonj 			    sizeof (d6ia));
    727  3431  carlsonj 			data += sizeof (d6ia) - sizeof (d6o);
    728  3431  carlsonj 			olen -= sizeof (d6ia) - sizeof (d6o);
    729  3431  carlsonj 			show_address("  Address", &d6ia.d6ia_addr);
    730  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    731  3431  carlsonj 			    "  Preferred lifetime = %u seconds",
    732  3431  carlsonj 			    ntohl(d6ia.d6ia_preflife));
    733  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    734  3431  carlsonj 			    "  Valid lifetime = %u seconds",
    735  3431  carlsonj 			    ntohl(d6ia.d6ia_vallife));
    736  3431  carlsonj 			nest_options(data, olen, "ADDR: ", "Address");
    737  3431  carlsonj 			break;
    738  3431  carlsonj 		}
    739  3431  carlsonj 		case DHCPV6_OPT_ORO:
    740  3431  carlsonj 			while (olen >= sizeof (val16)) {
    741  3431  carlsonj 				(void) memcpy(&val16, data, sizeof (val16));
    742  3431  carlsonj 				val16 = ntohs(val16);
    743  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    744  3431  carlsonj 				    get_line_remain(),
    745  3431  carlsonj 				    "  Requested Option Code = %u (%s)", val16,
    746  3431  carlsonj 				    option_to_str(val16));
    747  3431  carlsonj 				data += sizeof (val16);
    748  3431  carlsonj 				olen -= sizeof (val16);
    749  3431  carlsonj 			}
    750  3431  carlsonj 			break;
    751  3431  carlsonj 		case DHCPV6_OPT_PREFERENCE:
    752  3431  carlsonj 			if (olen > 0) {
    753  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    754  3431  carlsonj 				    get_line_remain(),
    755  3431  carlsonj 				    *data == 255 ?
    756  3431  carlsonj 				    "  Preference = %u (immediate)" :
    757  3431  carlsonj 				    "  Preference = %u", *data);
    758  3431  carlsonj 			}
    759  3431  carlsonj 			break;
    760  3431  carlsonj 		case DHCPV6_OPT_ELAPSED_TIME:
    761  3431  carlsonj 			if (olen == sizeof (val16)) {
    762  3431  carlsonj 				(void) memcpy(&val16, data, sizeof (val16));
    763  3431  carlsonj 				val16 = ntohs(val16);
    764  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    765  3431  carlsonj 				    get_line_remain(),
    766  3431  carlsonj 				    "  Elapsed Time = %u.%02u seconds",
    767  3431  carlsonj 				    val16 / 100, val16 % 100);
    768  3431  carlsonj 			}
    769  3431  carlsonj 			break;
    770  3431  carlsonj 		case DHCPV6_OPT_RELAY_MSG:
    771  3431  carlsonj 			if (olen > 0) {
    772  3431  carlsonj 				oldnest = prot_nest_prefix;
    773  3431  carlsonj 				prot_nest_prefix = prot_prefix;
    774  3431  carlsonj 				retlen = interpret_dhcpv6(F_DTAIL, data, olen);
    775  3431  carlsonj 				prot_prefix = prot_nest_prefix;
    776  3431  carlsonj 				prot_nest_prefix = oldnest;
    777  3431  carlsonj 			}
    778  3431  carlsonj 			break;
    779  3431  carlsonj 		case DHCPV6_OPT_AUTH: {
    780  3431  carlsonj 			dhcpv6_auth_t d6a;
    781  3431  carlsonj 
    782  3431  carlsonj 			if (olen < DHCPV6_AUTH_SIZE - sizeof (d6o))
    783  3431  carlsonj 				break;
    784  3431  carlsonj 			(void) memcpy(&d6a, data - sizeof (d6o),
    785  3431  carlsonj 			    DHCPV6_AUTH_SIZE);
    786  3431  carlsonj 			data += DHCPV6_AUTH_SIZE - sizeof (d6o);
    787  3431  carlsonj 			olen += DHCPV6_AUTH_SIZE - sizeof (d6o);
    788  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    789  3431  carlsonj 			    "  Protocol = %u (%s)", d6a.d6a_proto,
    790  3431  carlsonj 			    authproto_to_str(d6a.d6a_proto));
    791  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    792  3431  carlsonj 			    "  Algorithm = %u (%s)", d6a.d6a_alg,
    793  3431  carlsonj 			    authalg_to_str(d6a.d6a_proto, d6a.d6a_alg));
    794  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    795  3431  carlsonj 			    "  Replay Detection Method = %u (%s)", d6a.d6a_rdm,
    796  3431  carlsonj 			    authrdm_to_str(d6a.d6a_rdm));
    797  3431  carlsonj 			show_hex(d6a.d6a_replay, sizeof (d6a.d6a_replay),
    798  3431  carlsonj 			    "  RDM Data");
    799  3431  carlsonj 			if (olen > 0)
    800  3431  carlsonj 				show_hex(data, olen, "  Auth Info");
    801  3431  carlsonj 			break;
    802  3431  carlsonj 		}
    803  3431  carlsonj 		case DHCPV6_OPT_UNICAST:
    804  3431  carlsonj 			if (olen >= sizeof (in6_addr_t))
    805  3431  carlsonj 				show_address("  Server Address", data);
    806  3431  carlsonj 			break;
    807  3431  carlsonj 		case DHCPV6_OPT_STATUS_CODE:
    808  3431  carlsonj 			if (olen < sizeof (val16))
    809  3431  carlsonj 				break;
    810  3431  carlsonj 			(void) memcpy(&val16, data, sizeof (val16));
    811  3431  carlsonj 			val16 = ntohs(val16);
    812  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    813  3431  carlsonj 			    "  Status Code = %u (%s)", val16,
    814  3431  carlsonj 			    status_to_str(val16));
    815  3431  carlsonj 			data += sizeof (val16);
    816  3431  carlsonj 			olen -= sizeof (val16);
    817  3431  carlsonj 			if (olen > 0)
    818  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    819  3431  carlsonj 				    get_line_remain(), "  Text = \"%.*s\"",
    820  3431  carlsonj 				    olen, data);
    821  3431  carlsonj 			break;
    822  3431  carlsonj 		case DHCPV6_OPT_VENDOR_CLASS:
    823  3431  carlsonj 			if (olen < sizeof (val32))
    824  3431  carlsonj 				break;
    825  3431  carlsonj 			(void) memcpy(&val32, data, sizeof (val32));
    826  3431  carlsonj 			data += sizeof (val32);
    827  3431  carlsonj 			olen -= sizeof (val32);
    828  3431  carlsonj 			val32 = ntohl(val32);
    829  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    830  3431  carlsonj 			    "  Enterprise Number = %lu (%s)", val32,
    831  3431  carlsonj 			    entr_to_str(val32));
    832  3431  carlsonj 			/* FALLTHROUGH */
    833  3431  carlsonj 		case DHCPV6_OPT_USER_CLASS:
    834  3431  carlsonj 			while (olen >= sizeof (val16)) {
    835  3431  carlsonj 				(void) memcpy(&val16, data, sizeof (val16));
    836  3431  carlsonj 				data += sizeof (val16);
    837  3431  carlsonj 				olen -= sizeof (val16);
    838  3431  carlsonj 				val16 = ntohs(val16);
    839  3431  carlsonj 				if (val16 > olen) {
    840  3431  carlsonj 					(void) strlcpy(get_line(0, 0),
    841  3431  carlsonj 					    "  Truncated class",
    842  3431  carlsonj 					    get_line_remain());
    843  3431  carlsonj 					val16 = olen;
    844  3431  carlsonj 				}
    845  3431  carlsonj 				show_hex(data, olen, "  Class");
    846  3431  carlsonj 				data += val16;
    847  3431  carlsonj 				olen -= val16;
    848  3431  carlsonj 			}
    849  3431  carlsonj 			break;
    850  3431  carlsonj 		case DHCPV6_OPT_VENDOR_OPT: {
    851  3431  carlsonj 			dhcpv6_option_t sd6o;
    852  3431  carlsonj 
    853  3431  carlsonj 			if (olen < sizeof (val32))
    854  3431  carlsonj 				break;
    855  3431  carlsonj 			(void) memcpy(&val32, data, sizeof (val32));
    856  3431  carlsonj 			data += sizeof (val32);
    857  3431  carlsonj 			olen -= sizeof (val32);
    858  3431  carlsonj 			val32 = ntohl(val32);
    859  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    860  3431  carlsonj 			    "  Enterprise Number = %lu (%s)", val32,
    861  3431  carlsonj 			    entr_to_str(val32));
    862  3431  carlsonj 			while (olen >= sizeof (sd6o)) {
    863  3431  carlsonj 				(void) memcpy(&sd6o, data, sizeof (sd6o));
    864  3431  carlsonj 				sd6o.d6o_code = ntohs(sd6o.d6o_code);
    865  3431  carlsonj 				sd6o.d6o_len = ntohs(sd6o.d6o_len);
    866  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    867  3431  carlsonj 				    get_line_remain(),
    868  3431  carlsonj 				    "  Vendor Option Code = %u", d6o.d6o_code);
    869  3431  carlsonj 				data += sizeof (d6o);
    870  3431  carlsonj 				olen -= sizeof (d6o);
    871  3431  carlsonj 				if (sd6o.d6o_len > olen) {
    872  3431  carlsonj 					(void) strlcpy(get_line(0, 0),
    873  3431  carlsonj 					    "  Vendor Option truncated",
    874  3431  carlsonj 					    get_line_remain());
    875  3431  carlsonj 					sd6o.d6o_len = olen;
    876  3431  carlsonj 				}
    877  3431  carlsonj 				if (sd6o.d6o_len > 0) {
    878  3431  carlsonj 					show_hex(data, sd6o.d6o_len,
    879  3431  carlsonj 					    "    Data");
    880  3431  carlsonj 					data += sd6o.d6o_len;
    881  3431  carlsonj 					olen -= sd6o.d6o_len;
    882  3431  carlsonj 				}
    883  3431  carlsonj 			}
    884  3431  carlsonj 			break;
    885  3431  carlsonj 		}
    886  3431  carlsonj 		case DHCPV6_OPT_REMOTE_ID:
    887  3431  carlsonj 			if (olen < sizeof (val32))
    888  3431  carlsonj 				break;
    889  3431  carlsonj 			(void) memcpy(&val32, data, sizeof (val32));
    890  3431  carlsonj 			data += sizeof (val32);
    891  3431  carlsonj 			olen -= sizeof (val32);
    892  3431  carlsonj 			val32 = ntohl(val32);
    893  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    894  3431  carlsonj 			    "  Enterprise Number = %lu (%s)", val32,
    895  3431  carlsonj 			    entr_to_str(val32));
    896  3431  carlsonj 			/* FALLTHROUGH */
    897  3431  carlsonj 		case DHCPV6_OPT_INTERFACE_ID:
    898  3431  carlsonj 		case DHCPV6_OPT_SUBSCRIBER:
    899  3431  carlsonj 			if (olen > 0)
    900  3431  carlsonj 				show_hex(data, olen, "  ID");
    901  3431  carlsonj 			break;
    902  3431  carlsonj 		case DHCPV6_OPT_RECONF_MSG:
    903  3431  carlsonj 			if (olen > 0) {
    904  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    905  3431  carlsonj 				    get_line_remain(),
    906  3431  carlsonj 				    "  Message Type = %u (%s)", *data,
    907  3431  carlsonj 				    reconf_to_str(*data));
    908  3431  carlsonj 			}
    909  3431  carlsonj 			break;
    910  3431  carlsonj 		case DHCPV6_OPT_SIP_NAMES:
    911  3431  carlsonj 		case DHCPV6_OPT_DNS_SEARCH:
    912  3431  carlsonj 		case DHCPV6_OPT_NIS_DOMAIN:
    913  3431  carlsonj 		case DHCPV6_OPT_NISP_DOMAIN:
    914  3431  carlsonj 		case DHCPV6_OPT_BCMCS_SRV_D: {
    915  3431  carlsonj 			dhcp_symbol_t *symp;
    916  3431  carlsonj 			char *sp2;
    917  3431  carlsonj 
    918  3431  carlsonj 			symp = inittab_getbycode(
    919  3431  carlsonj 			    ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
    920  3431  carlsonj 			    d6o.d6o_code);
    921  3431  carlsonj 			if (symp != NULL) {
    922  3431  carlsonj 				str = inittab_decode(symp, data, olen, B_TRUE);
    923  3431  carlsonj 				if (str != NULL) {
    924  3431  carlsonj 					sp = str;
    925  3431  carlsonj 					do {
    926  3431  carlsonj 						sp2 = strchr(sp, ' ');
    927  3431  carlsonj 						if (sp2 != NULL)
    928  3431  carlsonj 							*sp2++ = '\0';
    929  3431  carlsonj 						(void) snprintf(get_line(0, 0),
    930  3431  carlsonj 						    get_line_remain(),
    931  3431  carlsonj 						    "  Name = %s", sp);
    932  3431  carlsonj 					} while ((sp = sp2) != NULL);
    933  3431  carlsonj 					free(str);
    934  3431  carlsonj 				}
    935  3431  carlsonj 				free(symp);
    936  3431  carlsonj 			}
    937  3431  carlsonj 			break;
    938  3431  carlsonj 		}
    939  3431  carlsonj 		case DHCPV6_OPT_SIP_ADDR:
    940  3431  carlsonj 		case DHCPV6_OPT_DNS_ADDR:
    941  3431  carlsonj 		case DHCPV6_OPT_NIS_SERVERS:
    942  3431  carlsonj 		case DHCPV6_OPT_NISP_SERVERS:
    943  3431  carlsonj 		case DHCPV6_OPT_SNTP_SERVERS:
    944  3431  carlsonj 		case DHCPV6_OPT_BCMCS_SRV_A:
    945  3431  carlsonj 			while (olen >= sizeof (in6_addr_t)) {
    946  3431  carlsonj 				show_address("  Address", data);
    947  3431  carlsonj 				data += sizeof (in6_addr_t);
    948  3431  carlsonj 				olen -= sizeof (in6_addr_t);
    949  3431  carlsonj 			}
    950  3431  carlsonj 			break;
    951  3431  carlsonj 		case DHCPV6_OPT_IAPREFIX: {
    952  3431  carlsonj 			dhcpv6_iaprefix_t d6ip;
    953  3431  carlsonj 
    954  3431  carlsonj 			if (olen < DHCPV6_IAPREFIX_SIZE - sizeof (d6o))
    955  3431  carlsonj 				break;
    956  3431  carlsonj 			(void) memcpy(&d6ip, data - sizeof (d6o),
    957  3431  carlsonj 			    DHCPV6_IAPREFIX_SIZE);
    958  3431  carlsonj 			data += DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
    959  3431  carlsonj 			olen -= DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
    960  3431  carlsonj 			show_address("  Prefix", d6ip.d6ip_addr);
    961  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    962  3431  carlsonj 			    "  Preferred lifetime = %u seconds",
    963  3431  carlsonj 			    ntohl(d6ip.d6ip_preflife));
    964  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    965  3431  carlsonj 			    "  Valid lifetime = %u seconds",
    966  3431  carlsonj 			    ntohl(d6ip.d6ip_vallife));
    967  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    968  3431  carlsonj 			    "  Prefix length = %u", d6ip.d6ip_preflen);
    969  3431  carlsonj 			nest_options(data, olen, "ADDR: ", "Address");
    970  3431  carlsonj 			break;
    971  3431  carlsonj 		}
    972  3431  carlsonj 		case DHCPV6_OPT_INFO_REFTIME:
    973  3431  carlsonj 			if (olen < sizeof (val32))
    974  3431  carlsonj 				break;
    975  3431  carlsonj 			(void) memcpy(&val32, data, sizeof (val32));
    976  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    977  3431  carlsonj 			    "  Refresh Time = %lu seconds", ntohl(val32));
    978  3431  carlsonj 			break;
    979  3431  carlsonj 		case DHCPV6_OPT_GEOCONF_CVC: {
    980  3431  carlsonj 			dhcpv6_civic_t d6c;
    981  3431  carlsonj 			int solen;
    982  3431  carlsonj 
    983  3431  carlsonj 			if (olen < DHCPV6_CIVIC_SIZE - sizeof (d6o))
    984  3431  carlsonj 				break;
    985  3431  carlsonj 			(void) memcpy(&d6c, data - sizeof (d6o),
    986  3431  carlsonj 			    DHCPV6_CIVIC_SIZE);
    987  3431  carlsonj 			data += DHCPV6_CIVIC_SIZE - sizeof (d6o);
    988  3431  carlsonj 			olen -= DHCPV6_CIVIC_SIZE - sizeof (d6o);
    989  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    990  3431  carlsonj 			    "  What Location = %u (%s)", d6c.d6c_what,
    991  3431  carlsonj 			    cwhat_to_str(d6c.d6c_what));
    992  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
    993  3431  carlsonj 			    "  Country Code = %.*s", sizeof (d6c.d6c_cc),
    994  3431  carlsonj 			    d6c.d6c_cc);
    995  3431  carlsonj 			while (olen >= 2) {
    996  3431  carlsonj 				(void) snprintf(get_line(0, 0),
    997  3431  carlsonj 				    get_line_remain(),
    998  3431  carlsonj 				    "  CA Element = %u (%s)", *data,
    999  3431  carlsonj 				    catype_to_str(*data));
   1000  3431  carlsonj 				solen = data[1];
   1001  3431  carlsonj 				data += 2;
   1002  3431  carlsonj 				olen -= 2;
   1003  3431  carlsonj 				if (solen > olen) {
   1004  3431  carlsonj 					(void) strlcpy(get_line(0, 0),
   1005  3431  carlsonj 					    "  CA Element truncated",
   1006  3431  carlsonj 					    get_line_remain());
   1007  3431  carlsonj 					solen = olen;
   1008  3431  carlsonj 				}
   1009  3431  carlsonj 				if (solen > 0) {
   1010  3431  carlsonj 					show_ascii(data, solen, "  CA Data");
   1011  3431  carlsonj 					data += solen;
   1012  3431  carlsonj 					olen -= solen;
   1013  3431  carlsonj 				}
   1014  3431  carlsonj 			}
   1015  3431  carlsonj 			break;
   1016  3431  carlsonj 		}
   1017  3431  carlsonj 		case DHCPV6_OPT_CLIENT_FQDN: {
   1018  3431  carlsonj 			dhcp_symbol_t *symp;
   1019  3431  carlsonj 
   1020  3431  carlsonj 			if (olen == 0)
   1021  3431  carlsonj 				break;
   1022  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1023  3431  carlsonj 			    "  Flags = %02x", *data);
   1024  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1025  3431  carlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_S,
   1026  3431  carlsonj 			    "Perform AAAA RR updates", "No AAAA RR updates"));
   1027  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1028  3431  carlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_O,
   1029  3431  carlsonj 			    "Server override updates",
   1030  3431  carlsonj 			    "No server override updates"));
   1031  3431  carlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1032  3431  carlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_N,
   1033  3431  carlsonj 			    "Server performs no updates",
   1034  3431  carlsonj 			    "Server performs updates"));
   1035  3431  carlsonj 			symp = inittab_getbycode(
   1036  3431  carlsonj 			    ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
   1037  3431  carlsonj 			    d6o.d6o_code);
   1038  3431  carlsonj 			if (symp != NULL) {
   1039  3431  carlsonj 				str = inittab_decode(symp, data, olen, B_TRUE);
   1040  3431  carlsonj 				if (str != NULL) {
   1041  3431  carlsonj 					(void) snprintf(get_line(0, 0),
   1042  3431  carlsonj 					    get_line_remain(),
   1043  3431  carlsonj 					    "  FQDN = %s", str);
   1044  3431  carlsonj 					free(str);
   1045  3431  carlsonj 				}
   1046  3431  carlsonj 				free(symp);
   1047  3431  carlsonj 			}
   1048  3431  carlsonj 			break;
   1049  3431  carlsonj 		}
   1050  3431  carlsonj 		}
   1051  3431  carlsonj 		data = ostart + d6o.d6o_len;
   1052  3431  carlsonj 		len -= d6o.d6o_len;
   1053  3431  carlsonj 	}
   1054  3431  carlsonj 	if (len != 0) {
   1055  3431  carlsonj 		(void) strlcpy(get_line(0, 0), "Option entry truncated",
   1056  3431  carlsonj 		    get_line_remain());
   1057  3431  carlsonj 	}
   1058  3431  carlsonj }
   1059