13431Scarlsonj /*
23431Scarlsonj * CDDL HEADER START
33431Scarlsonj *
43431Scarlsonj * The contents of this file are subject to the terms of the
53431Scarlsonj * Common Development and Distribution License (the "License").
63431Scarlsonj * You may not use this file except in compliance with the License.
73431Scarlsonj *
83431Scarlsonj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93431Scarlsonj * or http://www.opensolaris.org/os/licensing.
103431Scarlsonj * See the License for the specific language governing permissions
113431Scarlsonj * and limitations under the License.
123431Scarlsonj *
133431Scarlsonj * When distributing Covered Code, include this CDDL HEADER in each
143431Scarlsonj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153431Scarlsonj * If applicable, add the following below this CDDL HEADER, with the
163431Scarlsonj * fields enclosed by brackets "[]" replaced with your own identifying
173431Scarlsonj * information: Portions Copyright [yyyy] [name of copyright owner]
183431Scarlsonj *
193431Scarlsonj * CDDL HEADER END
203431Scarlsonj */
213431Scarlsonj
223431Scarlsonj /*
23*11262SRajagopal.Andra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
243431Scarlsonj * Use is subject to license terms.
253431Scarlsonj */
263431Scarlsonj
273431Scarlsonj /*
283431Scarlsonj * Dynamic Host Configuration Protocol version 6, for IPv6. Supports
293431Scarlsonj * RFCs 3315, 3319, 3646, 3898, 4075, 4242, 4280, 4580, 4649, and 4704.
303431Scarlsonj */
313431Scarlsonj
323431Scarlsonj #include <stdio.h>
333431Scarlsonj #include <stdlib.h>
343431Scarlsonj #include <string.h>
353431Scarlsonj #include <time.h>
363431Scarlsonj #include <sys/types.h>
373431Scarlsonj #include <sys/socket.h>
383431Scarlsonj #include <netinet/in.h>
393431Scarlsonj #include <netinet/dhcp6.h>
403431Scarlsonj #include <arpa/inet.h>
413431Scarlsonj #include <dhcp_impl.h>
423431Scarlsonj #include <dhcp_inittab.h>
433431Scarlsonj
443431Scarlsonj #include "snoop.h"
453431Scarlsonj
463431Scarlsonj static const char *mtype_to_str(uint8_t);
473431Scarlsonj static const char *option_to_str(uint8_t);
483431Scarlsonj static const char *duidtype_to_str(uint16_t);
493431Scarlsonj static const char *status_to_str(uint16_t);
503431Scarlsonj static const char *entr_to_str(uint32_t);
513431Scarlsonj static const char *reconf_to_str(uint8_t);
523431Scarlsonj static const char *authproto_to_str(uint8_t);
533431Scarlsonj static const char *authalg_to_str(uint8_t, uint8_t);
543431Scarlsonj static const char *authrdm_to_str(uint8_t);
553431Scarlsonj static const char *cwhat_to_str(uint8_t);
563431Scarlsonj static const char *catype_to_str(uint8_t);
573431Scarlsonj static void show_hex(const uint8_t *, int, const char *);
583431Scarlsonj static void show_ascii(const uint8_t *, int, const char *);
593431Scarlsonj static void show_address(const char *, const void *);
603431Scarlsonj static void show_options(const uint8_t *, int);
613431Scarlsonj
623431Scarlsonj int
interpret_dhcpv6(int flags,const uint8_t * data,int len)633431Scarlsonj interpret_dhcpv6(int flags, const uint8_t *data, int len)
643431Scarlsonj {
653431Scarlsonj int olen = len;
663431Scarlsonj char *line, *lstart;
673431Scarlsonj dhcpv6_relay_t d6r;
683431Scarlsonj dhcpv6_message_t d6m;
693431Scarlsonj uint_t optlen;
703431Scarlsonj uint16_t statuscode;
713431Scarlsonj
723431Scarlsonj if (len <= 0) {
733431Scarlsonj (void) strlcpy(get_sum_line(), "DHCPv6?", MAXLINE);
743431Scarlsonj return (0);
753431Scarlsonj }
763431Scarlsonj if (flags & F_SUM) {
773431Scarlsonj uint_t ias;
783431Scarlsonj dhcpv6_option_t *d6o;
793431Scarlsonj in6_addr_t link, peer;
803431Scarlsonj char linkstr[INET6_ADDRSTRLEN];
813431Scarlsonj char peerstr[INET6_ADDRSTRLEN];
823431Scarlsonj
833431Scarlsonj line = lstart = get_sum_line();
843431Scarlsonj line += snprintf(line, MAXLINE, "DHCPv6 %s",
853431Scarlsonj mtype_to_str(data[0]));
863431Scarlsonj if (data[0] == DHCPV6_MSG_RELAY_FORW ||
873431Scarlsonj data[0] == DHCPV6_MSG_RELAY_REPL) {
883431Scarlsonj if (len < sizeof (d6r)) {
893431Scarlsonj (void) strlcpy(line, "?",
903431Scarlsonj MAXLINE - (line - lstart));
913431Scarlsonj return (olen);
923431Scarlsonj }
933431Scarlsonj /* Not much in DHCPv6 is aligned. */
943431Scarlsonj (void) memcpy(&d6r, data, sizeof (d6r));
953431Scarlsonj (void) memcpy(&link, d6r.d6r_linkaddr, sizeof (link));
963431Scarlsonj (void) memcpy(&peer, d6r.d6r_peeraddr, sizeof (peer));
973431Scarlsonj line += snprintf(line, MAXLINE - (line - lstart),
983431Scarlsonj " HC=%d link=%s peer=%s", d6r.d6r_hop_count,
993431Scarlsonj inet_ntop(AF_INET6, &link, linkstr,
1003431Scarlsonj sizeof (linkstr)),
1013431Scarlsonj inet_ntop(AF_INET6, &peer, peerstr,
1023431Scarlsonj sizeof (peerstr)));
1033431Scarlsonj data += sizeof (d6r);
1043431Scarlsonj len -= sizeof (d6r);
1053431Scarlsonj } else {
1063431Scarlsonj if (len < sizeof (d6m)) {
1073431Scarlsonj (void) strlcpy(line, "?",
1083431Scarlsonj MAXLINE - (line - lstart));
1093431Scarlsonj return (olen);
1103431Scarlsonj }
1113431Scarlsonj (void) memcpy(&d6m, data, sizeof (d6m));
1123431Scarlsonj line += snprintf(line, MAXLINE - (line - lstart),
1133431Scarlsonj " xid=%x", DHCPV6_GET_TRANSID(&d6m));
1143431Scarlsonj data += sizeof (d6m);
1153431Scarlsonj len -= sizeof (d6m);
1163431Scarlsonj }
1173431Scarlsonj ias = 0;
1183431Scarlsonj d6o = NULL;
1193431Scarlsonj while ((d6o = dhcpv6_find_option(data, len, d6o,
1203431Scarlsonj DHCPV6_OPT_IA_NA, NULL)) != NULL)
1213431Scarlsonj ias++;
1223431Scarlsonj if (ias > 0)
1233431Scarlsonj line += snprintf(line, MAXLINE - (line - lstart),
1243431Scarlsonj " IAs=%u", ias);
1253431Scarlsonj d6o = dhcpv6_find_option(data, len, NULL,
1263431Scarlsonj DHCPV6_OPT_STATUS_CODE, &optlen);
1273431Scarlsonj optlen -= sizeof (*d6o);
1283431Scarlsonj if (d6o != NULL && optlen >= sizeof (statuscode)) {
1293431Scarlsonj (void) memcpy(&statuscode, d6o + 1,
1303431Scarlsonj sizeof (statuscode));
1313431Scarlsonj line += snprintf(line, MAXLINE - (line - lstart),
1323431Scarlsonj " status=%u", ntohs(statuscode));
1333431Scarlsonj optlen -= sizeof (statuscode);
1343431Scarlsonj if (optlen > 0) {
1353431Scarlsonj line += snprintf(line,
1363431Scarlsonj MAXLINE - (line - lstart), " \"%.*s\"",
1373431Scarlsonj optlen, (char *)(d6o + 1) + 2);
1383431Scarlsonj }
1393431Scarlsonj }
1403431Scarlsonj d6o = dhcpv6_find_option(data, len, NULL,
1413431Scarlsonj DHCPV6_OPT_RELAY_MSG, &optlen);
1423431Scarlsonj optlen -= sizeof (*d6o);
1433431Scarlsonj if (d6o != NULL && optlen >= 1) {
1443431Scarlsonj line += snprintf(line, MAXLINE - (line - lstart),
1453431Scarlsonj " relay=%s", mtype_to_str(*(uint8_t *)(d6o + 1)));
1463431Scarlsonj }
1473431Scarlsonj } else if (flags & F_DTAIL) {
1483431Scarlsonj show_header("DHCPv6: ",
1493431Scarlsonj "Dynamic Host Configuration Protocol Version 6", len);
1503431Scarlsonj show_space();
1513431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
1523431Scarlsonj "Message type (msg-type) = %u (%s)", data[0],
1533431Scarlsonj mtype_to_str(data[0]));
1543431Scarlsonj if (data[0] == DHCPV6_MSG_RELAY_FORW ||
1553431Scarlsonj data[0] == DHCPV6_MSG_RELAY_REPL) {
1563431Scarlsonj if (len < sizeof (d6r)) {
1573431Scarlsonj (void) strlcpy(get_line(0, 0), "Truncated",
1583431Scarlsonj get_line_remain());
1593431Scarlsonj return (olen);
1603431Scarlsonj }
1613431Scarlsonj (void) memcpy(&d6r, data, sizeof (d6r));
1623431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
1633431Scarlsonj "Hop count = %u", d6r.d6r_hop_count);
1643431Scarlsonj show_address("Link address", d6r.d6r_linkaddr);
1653431Scarlsonj show_address("Peer address", d6r.d6r_peeraddr);
1663431Scarlsonj data += sizeof (d6r);
1673431Scarlsonj len -= sizeof (d6r);
1683431Scarlsonj } else {
1693431Scarlsonj if (len < sizeof (d6m)) {
1703431Scarlsonj (void) strlcpy(get_line(0, 0), "Truncated",
1713431Scarlsonj get_line_remain());
1723431Scarlsonj return (olen);
1733431Scarlsonj }
1743431Scarlsonj (void) memcpy(&d6m, data, sizeof (d6m));
1753431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
1763431Scarlsonj "Transaction ID = %x", DHCPV6_GET_TRANSID(&d6m));
1773431Scarlsonj data += sizeof (d6m);
1783431Scarlsonj len -= sizeof (d6m);
1793431Scarlsonj }
1803431Scarlsonj show_space();
1813431Scarlsonj show_options(data, len);
1823431Scarlsonj show_space();
1833431Scarlsonj }
1843431Scarlsonj return (olen);
1853431Scarlsonj }
1863431Scarlsonj
1873431Scarlsonj static const char *
mtype_to_str(uint8_t mtype)1883431Scarlsonj mtype_to_str(uint8_t mtype)
1893431Scarlsonj {
1903431Scarlsonj switch (mtype) {
1913431Scarlsonj case DHCPV6_MSG_SOLICIT:
1923431Scarlsonj return ("Solicit");
1933431Scarlsonj case DHCPV6_MSG_ADVERTISE:
1943431Scarlsonj return ("Advertise");
1953431Scarlsonj case DHCPV6_MSG_REQUEST:
1963431Scarlsonj return ("Request");
1973431Scarlsonj case DHCPV6_MSG_CONFIRM:
1983431Scarlsonj return ("Confirm");
1993431Scarlsonj case DHCPV6_MSG_RENEW:
2003431Scarlsonj return ("Renew");
2013431Scarlsonj case DHCPV6_MSG_REBIND:
2023431Scarlsonj return ("Rebind");
2033431Scarlsonj case DHCPV6_MSG_REPLY:
2043431Scarlsonj return ("Reply");
2053431Scarlsonj case DHCPV6_MSG_RELEASE:
2063431Scarlsonj return ("Release");
2073431Scarlsonj case DHCPV6_MSG_DECLINE:
2083431Scarlsonj return ("Decline");
2093431Scarlsonj case DHCPV6_MSG_RECONFIGURE:
2103431Scarlsonj return ("Reconfigure");
2113431Scarlsonj case DHCPV6_MSG_INFO_REQ:
2123431Scarlsonj return ("Information-Request");
2133431Scarlsonj case DHCPV6_MSG_RELAY_FORW:
2143431Scarlsonj return ("Relay-Forward");
2153431Scarlsonj case DHCPV6_MSG_RELAY_REPL:
2163431Scarlsonj return ("Relay-Reply");
2173431Scarlsonj default:
2183431Scarlsonj return ("Unknown");
2193431Scarlsonj }
2203431Scarlsonj }
2213431Scarlsonj
2223431Scarlsonj static const char *
option_to_str(uint8_t mtype)2233431Scarlsonj option_to_str(uint8_t mtype)
2243431Scarlsonj {
2253431Scarlsonj switch (mtype) {
2263431Scarlsonj case DHCPV6_OPT_CLIENTID:
2273431Scarlsonj return ("Client Identifier");
2283431Scarlsonj case DHCPV6_OPT_SERVERID:
2293431Scarlsonj return ("Server Identifier");
2303431Scarlsonj case DHCPV6_OPT_IA_NA:
2313431Scarlsonj return ("Identity Association for Non-temporary Addresses");
2323431Scarlsonj case DHCPV6_OPT_IA_TA:
2333431Scarlsonj return ("Identity Association for Temporary Addresses");
2343431Scarlsonj case DHCPV6_OPT_IAADDR:
2353431Scarlsonj return ("IA Address");
2363431Scarlsonj case DHCPV6_OPT_ORO:
2373431Scarlsonj return ("Option Request");
2383431Scarlsonj case DHCPV6_OPT_PREFERENCE:
2393431Scarlsonj return ("Preference");
2403431Scarlsonj case DHCPV6_OPT_ELAPSED_TIME:
2413431Scarlsonj return ("Elapsed Time");
2423431Scarlsonj case DHCPV6_OPT_RELAY_MSG:
2433431Scarlsonj return ("Relay Message");
2443431Scarlsonj case DHCPV6_OPT_AUTH:
2453431Scarlsonj return ("Authentication");
2463431Scarlsonj case DHCPV6_OPT_UNICAST:
2473431Scarlsonj return ("Server Unicast");
2483431Scarlsonj case DHCPV6_OPT_STATUS_CODE:
2493431Scarlsonj return ("Status Code");
2503431Scarlsonj case DHCPV6_OPT_RAPID_COMMIT:
2513431Scarlsonj return ("Rapid Commit");
2523431Scarlsonj case DHCPV6_OPT_USER_CLASS:
2533431Scarlsonj return ("User Class");
2543431Scarlsonj case DHCPV6_OPT_VENDOR_CLASS:
2553431Scarlsonj return ("Vendor Class");
2563431Scarlsonj case DHCPV6_OPT_VENDOR_OPT:
2573431Scarlsonj return ("Vendor-specific Information");
2583431Scarlsonj case DHCPV6_OPT_INTERFACE_ID:
2593431Scarlsonj return ("Interface-Id");
2603431Scarlsonj case DHCPV6_OPT_RECONF_MSG:
2613431Scarlsonj return ("Reconfigure Message");
2623431Scarlsonj case DHCPV6_OPT_RECONF_ACC:
2633431Scarlsonj return ("Reconfigure Accept");
2643431Scarlsonj case DHCPV6_OPT_SIP_NAMES:
2653431Scarlsonj return ("SIP Servers Domain Name List");
2663431Scarlsonj case DHCPV6_OPT_SIP_ADDR:
2673431Scarlsonj return ("SIP Servers IPv6 Address List");
2683431Scarlsonj case DHCPV6_OPT_DNS_ADDR:
2693431Scarlsonj return ("DNS Recursive Name Server");
2703431Scarlsonj case DHCPV6_OPT_DNS_SEARCH:
2713431Scarlsonj return ("Domain Search List");
2723431Scarlsonj case DHCPV6_OPT_IA_PD:
2733431Scarlsonj return ("Identity Association for Prefix Delegation");
2743431Scarlsonj case DHCPV6_OPT_IAPREFIX:
2753431Scarlsonj return ("IA_PD Prefix");
2763431Scarlsonj case DHCPV6_OPT_NIS_SERVERS:
2773431Scarlsonj return ("Network Information Service Servers");
2783431Scarlsonj case DHCPV6_OPT_NIS_DOMAIN:
2793431Scarlsonj return ("Network Information Service Domain Name");
2803431Scarlsonj case DHCPV6_OPT_SNTP_SERVERS:
2813431Scarlsonj return ("Simple Network Time Protocol Servers");
2823431Scarlsonj case DHCPV6_OPT_INFO_REFTIME:
2833431Scarlsonj return ("Information Refresh Time");
2843431Scarlsonj case DHCPV6_OPT_BCMCS_SRV_D:
2853431Scarlsonj return ("BCMCS Controller Domain Name List");
2863431Scarlsonj case DHCPV6_OPT_BCMCS_SRV_A:
2873431Scarlsonj return ("BCMCS Controller IPv6 Address");
2883431Scarlsonj case DHCPV6_OPT_GEOCONF_CVC:
2893431Scarlsonj return ("Civic Location");
2903431Scarlsonj case DHCPV6_OPT_REMOTE_ID:
2913431Scarlsonj return ("Relay Agent Remote-ID");
2923431Scarlsonj case DHCPV6_OPT_SUBSCRIBER:
2933431Scarlsonj return ("Relay Agent Subscriber-ID");
2943431Scarlsonj case DHCPV6_OPT_CLIENT_FQDN:
2953431Scarlsonj return ("Client FQDN");
2963431Scarlsonj default:
2973431Scarlsonj return ("Unknown");
2983431Scarlsonj }
2993431Scarlsonj }
3003431Scarlsonj
3013431Scarlsonj static const char *
duidtype_to_str(uint16_t dtype)3023431Scarlsonj duidtype_to_str(uint16_t dtype)
3033431Scarlsonj {
3043431Scarlsonj switch (dtype) {
3053431Scarlsonj case DHCPV6_DUID_LLT:
3063431Scarlsonj return ("Link-layer Address Plus Time");
3073431Scarlsonj case DHCPV6_DUID_EN:
3083431Scarlsonj return ("Enterprise Number");
3093431Scarlsonj case DHCPV6_DUID_LL:
3103431Scarlsonj return ("Link-layer Address");
3113431Scarlsonj default:
3123431Scarlsonj return ("Unknown");
3133431Scarlsonj }
3143431Scarlsonj }
3153431Scarlsonj
3163431Scarlsonj static const char *
status_to_str(uint16_t status)3173431Scarlsonj status_to_str(uint16_t status)
3183431Scarlsonj {
3193431Scarlsonj switch (status) {
3203431Scarlsonj case DHCPV6_STAT_SUCCESS:
3213431Scarlsonj return ("Success");
3223431Scarlsonj case DHCPV6_STAT_UNSPECFAIL:
3233431Scarlsonj return ("Failure, reason unspecified");
3243431Scarlsonj case DHCPV6_STAT_NOADDRS:
3253431Scarlsonj return ("No addresses for IAs");
3263431Scarlsonj case DHCPV6_STAT_NOBINDING:
3273431Scarlsonj return ("Client binding unavailable");
3283431Scarlsonj case DHCPV6_STAT_NOTONLINK:
3293431Scarlsonj return ("Prefix not on link");
3303431Scarlsonj case DHCPV6_STAT_USEMCAST:
3313431Scarlsonj return ("Use multicast");
3323431Scarlsonj case DHCPV6_STAT_NOPREFIX:
3333431Scarlsonj return ("No prefix available");
3343431Scarlsonj default:
3353431Scarlsonj return ("Unknown");
3363431Scarlsonj }
3373431Scarlsonj }
3383431Scarlsonj
3393431Scarlsonj static const char *
entr_to_str(uint32_t entr)3403431Scarlsonj entr_to_str(uint32_t entr)
3413431Scarlsonj {
3423431Scarlsonj switch (entr) {
3433431Scarlsonj case DHCPV6_SUN_ENT:
3443431Scarlsonj return ("Sun Microsystems");
3453431Scarlsonj default:
3463431Scarlsonj return ("Unknown");
3473431Scarlsonj }
3483431Scarlsonj }
3493431Scarlsonj
3503431Scarlsonj static const char *
reconf_to_str(uint8_t msgtype)3513431Scarlsonj reconf_to_str(uint8_t msgtype)
3523431Scarlsonj {
3533431Scarlsonj switch (msgtype) {
3543431Scarlsonj case DHCPV6_RECONF_RENEW:
3553431Scarlsonj return ("Renew");
3563431Scarlsonj case DHCPV6_RECONF_INFO:
3573431Scarlsonj return ("Information-request");
3583431Scarlsonj default:
3593431Scarlsonj return ("Unknown");
3603431Scarlsonj }
3613431Scarlsonj }
3623431Scarlsonj
3633431Scarlsonj static const char *
authproto_to_str(uint8_t aproto)3643431Scarlsonj authproto_to_str(uint8_t aproto)
3653431Scarlsonj {
3663431Scarlsonj switch (aproto) {
3673431Scarlsonj case DHCPV6_PROTO_DELAYED:
3683431Scarlsonj return ("Delayed");
3693431Scarlsonj case DHCPV6_PROTO_RECONFIG:
3703431Scarlsonj return ("Reconfigure Key");
3713431Scarlsonj default:
3723431Scarlsonj return ("Unknown");
3733431Scarlsonj }
3743431Scarlsonj }
3753431Scarlsonj
3763431Scarlsonj static const char *
authalg_to_str(uint8_t aproto,uint8_t aalg)3773431Scarlsonj authalg_to_str(uint8_t aproto, uint8_t aalg)
3783431Scarlsonj {
3793431Scarlsonj switch (aproto) {
3803431Scarlsonj case DHCPV6_PROTO_DELAYED:
3813431Scarlsonj case DHCPV6_PROTO_RECONFIG:
3823431Scarlsonj switch (aalg) {
3833431Scarlsonj case DHCPV6_ALG_HMAC_MD5:
3843431Scarlsonj return ("HMAC-MD5 Signature");
3853431Scarlsonj default:
3863431Scarlsonj return ("Unknown");
3873431Scarlsonj }
3883431Scarlsonj break;
3893431Scarlsonj default:
3903431Scarlsonj return ("Unknown");
3913431Scarlsonj }
3923431Scarlsonj }
3933431Scarlsonj
3943431Scarlsonj static const char *
authrdm_to_str(uint8_t ardm)3953431Scarlsonj authrdm_to_str(uint8_t ardm)
3963431Scarlsonj {
3973431Scarlsonj switch (ardm) {
3983431Scarlsonj case DHCPV6_RDM_MONOCNT:
3993431Scarlsonj return ("Monotonic Counter");
4003431Scarlsonj default:
4013431Scarlsonj return ("Unknown");
4023431Scarlsonj }
4033431Scarlsonj }
4043431Scarlsonj
4053431Scarlsonj static const char *
cwhat_to_str(uint8_t what)4063431Scarlsonj cwhat_to_str(uint8_t what)
4073431Scarlsonj {
4083431Scarlsonj switch (what) {
4093431Scarlsonj case DHCPV6_CWHAT_SERVER:
4103431Scarlsonj return ("Server");
4113431Scarlsonj case DHCPV6_CWHAT_NETWORK:
4123431Scarlsonj return ("Network");
4133431Scarlsonj case DHCPV6_CWHAT_CLIENT:
4143431Scarlsonj return ("Client");
4153431Scarlsonj default:
4163431Scarlsonj return ("Unknown");
4173431Scarlsonj }
4183431Scarlsonj }
4193431Scarlsonj
4203431Scarlsonj static const char *
catype_to_str(uint8_t catype)4213431Scarlsonj catype_to_str(uint8_t catype)
4223431Scarlsonj {
4233431Scarlsonj switch (catype) {
4243431Scarlsonj case CIVICADDR_LANG:
4253431Scarlsonj return ("Language; RFC 2277");
4263431Scarlsonj case CIVICADDR_A1:
4273431Scarlsonj return ("National division (state)");
4283431Scarlsonj case CIVICADDR_A2:
4293431Scarlsonj return ("County");
4303431Scarlsonj case CIVICADDR_A3:
4313431Scarlsonj return ("City");
4323431Scarlsonj case CIVICADDR_A4:
4333431Scarlsonj return ("City division");
4343431Scarlsonj case CIVICADDR_A5:
4353431Scarlsonj return ("Neighborhood");
4363431Scarlsonj case CIVICADDR_A6:
4373431Scarlsonj return ("Street group");
4383431Scarlsonj case CIVICADDR_PRD:
4393431Scarlsonj return ("Leading street direction");
4403431Scarlsonj case CIVICADDR_POD:
4413431Scarlsonj return ("Trailing street suffix");
4423431Scarlsonj case CIVICADDR_STS:
4433431Scarlsonj return ("Street suffix or type");
4443431Scarlsonj case CIVICADDR_HNO:
4453431Scarlsonj return ("House number");
4463431Scarlsonj case CIVICADDR_HNS:
4473431Scarlsonj return ("House number suffix");
4483431Scarlsonj case CIVICADDR_LMK:
4493431Scarlsonj return ("Landmark");
4503431Scarlsonj case CIVICADDR_LOC:
4513431Scarlsonj return ("Additional location information");
4523431Scarlsonj case CIVICADDR_NAM:
4533431Scarlsonj return ("Name/occupant");
4543431Scarlsonj case CIVICADDR_PC:
4553431Scarlsonj return ("Postal Code/ZIP");
4563431Scarlsonj case CIVICADDR_BLD:
4573431Scarlsonj return ("Building");
4583431Scarlsonj case CIVICADDR_UNIT:
4593431Scarlsonj return ("Unit/apt/suite");
4603431Scarlsonj case CIVICADDR_FLR:
4613431Scarlsonj return ("Floor");
4623431Scarlsonj case CIVICADDR_ROOM:
4633431Scarlsonj return ("Room number");
4643431Scarlsonj case CIVICADDR_TYPE:
4653431Scarlsonj return ("Place type");
4663431Scarlsonj case CIVICADDR_PCN:
4673431Scarlsonj return ("Postal community name");
4683431Scarlsonj case CIVICADDR_POBOX:
4693431Scarlsonj return ("Post office box");
4703431Scarlsonj case CIVICADDR_ADDL:
4713431Scarlsonj return ("Additional code");
4723431Scarlsonj case CIVICADDR_SEAT:
4733431Scarlsonj return ("Seat/desk");
4743431Scarlsonj case CIVICADDR_ROAD:
4753431Scarlsonj return ("Primary road or street");
4763431Scarlsonj case CIVICADDR_RSEC:
4773431Scarlsonj return ("Road section");
4783431Scarlsonj case CIVICADDR_RBRA:
4793431Scarlsonj return ("Road branch");
4803431Scarlsonj case CIVICADDR_RSBR:
4813431Scarlsonj return ("Road sub-branch");
4823431Scarlsonj case CIVICADDR_SPRE:
4833431Scarlsonj return ("Street name pre-modifier");
4843431Scarlsonj case CIVICADDR_SPOST:
4853431Scarlsonj return ("Street name post-modifier");
4863431Scarlsonj case CIVICADDR_SCRIPT:
4873431Scarlsonj return ("Script");
4883431Scarlsonj default:
4893431Scarlsonj return ("Unknown");
4903431Scarlsonj }
4913431Scarlsonj }
4923431Scarlsonj
4933431Scarlsonj static void
show_hex(const uint8_t * data,int len,const char * name)4943431Scarlsonj show_hex(const uint8_t *data, int len, const char *name)
4953431Scarlsonj {
4963431Scarlsonj char buffer[16 * 3 + 1];
4973431Scarlsonj int nlen;
4983431Scarlsonj int i;
4993431Scarlsonj char sep;
5003431Scarlsonj
5013431Scarlsonj nlen = strlen(name);
5023431Scarlsonj sep = '=';
5033431Scarlsonj while (len > 0) {
5043431Scarlsonj for (i = 0; i < 16 && i < len; i++)
5053431Scarlsonj (void) snprintf(buffer + 3 * i, 4, " %02x", *data++);
5063431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(), "%*s %c%s",
5073431Scarlsonj nlen, name, sep, buffer);
5083431Scarlsonj name = "";
5093431Scarlsonj sep = ' ';
5103431Scarlsonj len -= i;
5113431Scarlsonj }
5123431Scarlsonj }
5133431Scarlsonj
5143431Scarlsonj static void
show_ascii(const uint8_t * data,int len,const char * name)5153431Scarlsonj show_ascii(const uint8_t *data, int len, const char *name)
5163431Scarlsonj {
5173431Scarlsonj char buffer[64], *bp;
5183431Scarlsonj int nlen;
5193431Scarlsonj int i;
5203431Scarlsonj char sep;
5213431Scarlsonj
5223431Scarlsonj nlen = strlen(name);
5233431Scarlsonj sep = '=';
5243431Scarlsonj while (len > 0) {
5253431Scarlsonj bp = buffer;
5263431Scarlsonj for (i = 0; i < sizeof (buffer) - 4 && len > 0; len--) {
5273431Scarlsonj if (!isascii(*data) || !isprint(*data))
5283431Scarlsonj bp += snprintf(bp, 5, "\\%03o", *data++);
5293431Scarlsonj else
5303431Scarlsonj *bp++;
5313431Scarlsonj }
5323431Scarlsonj *bp = '\0';
5333431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
5343431Scarlsonj "%*s %c \"%s\"", nlen, name, sep, buffer);
5353431Scarlsonj sep = ' ';
5363431Scarlsonj name = "";
5373431Scarlsonj }
5383431Scarlsonj }
5393431Scarlsonj
5403431Scarlsonj static void
show_address(const char * addrname,const void * aptr)5413431Scarlsonj show_address(const char *addrname, const void *aptr)
5423431Scarlsonj {
5433431Scarlsonj char *hname;
5443431Scarlsonj char addrstr[INET6_ADDRSTRLEN];
5453431Scarlsonj in6_addr_t addr;
5463431Scarlsonj
5473431Scarlsonj (void) memcpy(&addr, aptr, sizeof (in6_addr_t));
5483431Scarlsonj (void) inet_ntop(AF_INET6, &addr, addrstr, sizeof (addrstr));
5493431Scarlsonj hname = addrtoname(AF_INET6, &addr);
5503431Scarlsonj if (strcmp(hname, addrstr) == 0) {
5513431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(), "%s = %s",
5523431Scarlsonj addrname, addrstr);
5533431Scarlsonj } else {
5543431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
5553431Scarlsonj "%s = %s (%s)", addrname, addrstr, hname);
5563431Scarlsonj }
5573431Scarlsonj }
5583431Scarlsonj
5593431Scarlsonj static void
nest_options(const uint8_t * data,uint_t olen,char * prefix,char * title)5603431Scarlsonj nest_options(const uint8_t *data, uint_t olen, char *prefix, char *title)
5613431Scarlsonj {
5623431Scarlsonj char *str, *oldnest, *oldprefix;
5633431Scarlsonj
5643431Scarlsonj if (olen <= 0)
5653431Scarlsonj return;
5663431Scarlsonj oldprefix = prot_prefix;
5673431Scarlsonj oldnest = prot_nest_prefix;
5683431Scarlsonj str = malloc(strlen(prot_nest_prefix) + strlen(prot_prefix) + 1);
5693431Scarlsonj if (str == NULL) {
5703431Scarlsonj prot_nest_prefix = prot_prefix;
5713431Scarlsonj } else {
5723431Scarlsonj (void) sprintf(str, "%s%s", prot_nest_prefix, prot_prefix);
5733431Scarlsonj prot_nest_prefix = str;
5743431Scarlsonj }
5753431Scarlsonj show_header(prefix, title, 0);
5763431Scarlsonj show_options(data, olen);
5773431Scarlsonj free(str);
5783431Scarlsonj prot_prefix = oldprefix;
5793431Scarlsonj prot_nest_prefix = oldnest;
5803431Scarlsonj }
5813431Scarlsonj
5823431Scarlsonj static void
show_options(const uint8_t * data,int len)5833431Scarlsonj show_options(const uint8_t *data, int len)
5843431Scarlsonj {
5853431Scarlsonj dhcpv6_option_t d6o;
5863431Scarlsonj uint_t olen, retlen;
5873431Scarlsonj uint16_t val16;
5883431Scarlsonj uint16_t type;
5893431Scarlsonj uint32_t val32;
5903431Scarlsonj const uint8_t *ostart;
5913431Scarlsonj char *str, *sp;
5923431Scarlsonj char *oldnest;
5933431Scarlsonj
5943431Scarlsonj /*
5953431Scarlsonj * Be very careful with negative numbers; ANSI signed/unsigned
5963431Scarlsonj * comparison doesn't work as expected.
5973431Scarlsonj */
5983431Scarlsonj while (len >= (signed)sizeof (d6o)) {
5993431Scarlsonj (void) memcpy(&d6o, data, sizeof (d6o));
6003431Scarlsonj d6o.d6o_code = ntohs(d6o.d6o_code);
6013431Scarlsonj d6o.d6o_len = olen = ntohs(d6o.d6o_len);
6023431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6033431Scarlsonj "Option Code = %u (%s)", d6o.d6o_code,
6043431Scarlsonj option_to_str(d6o.d6o_code));
6053431Scarlsonj ostart = data += sizeof (d6o);
6063431Scarlsonj len -= sizeof (d6o);
6073431Scarlsonj if (olen > len) {
6083431Scarlsonj (void) strlcpy(get_line(0, 0), "Option truncated",
6093431Scarlsonj get_line_remain());
6103431Scarlsonj olen = len;
6113431Scarlsonj }
6123431Scarlsonj switch (d6o.d6o_code) {
6133431Scarlsonj case DHCPV6_OPT_CLIENTID:
6143431Scarlsonj case DHCPV6_OPT_SERVERID:
6153431Scarlsonj if (olen < sizeof (val16))
6163431Scarlsonj break;
6173431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
6183431Scarlsonj data += sizeof (val16);
6193431Scarlsonj olen -= sizeof (val16);
6203431Scarlsonj type = ntohs(val16);
6213431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6223431Scarlsonj " DUID Type = %u (%s)", type,
6233431Scarlsonj duidtype_to_str(type));
6243431Scarlsonj if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
6253431Scarlsonj if (olen < sizeof (val16))
6263431Scarlsonj break;
6273431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
6283431Scarlsonj data += sizeof (val16);
6293431Scarlsonj olen -= sizeof (val16);
6303431Scarlsonj val16 = ntohs(val16);
6313431Scarlsonj (void) snprintf(get_line(0, 0),
6323431Scarlsonj get_line_remain(),
6333431Scarlsonj " Hardware Type = %u (%s)", val16,
6343431Scarlsonj arp_htype(type));
6353431Scarlsonj }
6363431Scarlsonj if (type == DHCPV6_DUID_LLT) {
6373431Scarlsonj time_t timevalue;
6383431Scarlsonj
6393431Scarlsonj if (olen < sizeof (val32))
6403431Scarlsonj break;
6413431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
6423431Scarlsonj data += sizeof (val32);
6433431Scarlsonj olen -= sizeof (val32);
6443431Scarlsonj timevalue = ntohl(val32) + DUID_TIME_BASE;
6453431Scarlsonj (void) snprintf(get_line(0, 0),
6463431Scarlsonj get_line_remain(),
6473431Scarlsonj " Time = %lu (%.24s)", ntohl(val32),
6483431Scarlsonj ctime(&timevalue));
6493431Scarlsonj }
6503431Scarlsonj if (type == DHCPV6_DUID_EN) {
6513431Scarlsonj if (olen < sizeof (val32))
6523431Scarlsonj break;
6533431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
6543431Scarlsonj data += sizeof (val32);
6553431Scarlsonj olen -= sizeof (val32);
6563431Scarlsonj val32 = ntohl(val32);
6573431Scarlsonj (void) snprintf(get_line(0, 0),
6583431Scarlsonj get_line_remain(),
6593431Scarlsonj " Enterprise Number = %lu (%s)", val32,
6603431Scarlsonj entr_to_str(val32));
6613431Scarlsonj }
6623431Scarlsonj if (olen == 0)
6633431Scarlsonj break;
6643431Scarlsonj if ((str = malloc(olen * 3)) == NULL)
6653431Scarlsonj pr_err("interpret_dhcpv6: no mem");
6663431Scarlsonj sp = str + snprintf(str, 3, "%02x", *data++);
6673431Scarlsonj while (--olen > 0) {
6683431Scarlsonj *sp++ = (type == DHCPV6_DUID_LLT ||
6693431Scarlsonj type == DHCPV6_DUID_LL) ? ':' : ' ';
6703431Scarlsonj sp = sp + snprintf(sp, 3, "%02x", *data++);
6713431Scarlsonj }
6723431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6733431Scarlsonj (type == DHCPV6_DUID_LLT ||
6743431Scarlsonj type == DHCPV6_DUID_LL) ?
6753431Scarlsonj " Link Layer Address = %s" :
6763431Scarlsonj " Identifier = %s", str);
6773431Scarlsonj free(str);
6783431Scarlsonj break;
6793431Scarlsonj case DHCPV6_OPT_IA_NA:
6803431Scarlsonj case DHCPV6_OPT_IA_PD: {
6813431Scarlsonj dhcpv6_ia_na_t d6in;
6823431Scarlsonj
6833431Scarlsonj if (olen < sizeof (d6in) - sizeof (d6o))
6843431Scarlsonj break;
6853431Scarlsonj (void) memcpy(&d6in, data - sizeof (d6o),
6863431Scarlsonj sizeof (d6in));
6873431Scarlsonj data += sizeof (d6in) - sizeof (d6o);
6883431Scarlsonj olen -= sizeof (d6in) - sizeof (d6o);
6893431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6903431Scarlsonj " IAID = %u", ntohl(d6in.d6in_iaid));
6913431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6923431Scarlsonj " T1 (renew) = %u seconds", ntohl(d6in.d6in_t1));
6933431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
6943431Scarlsonj " T2 (rebind) = %u seconds", ntohl(d6in.d6in_t2));
6953431Scarlsonj nest_options(data, olen, "IA: ",
6963431Scarlsonj "Identity Association");
6973431Scarlsonj break;
6983431Scarlsonj }
6993431Scarlsonj case DHCPV6_OPT_IA_TA: {
7003431Scarlsonj dhcpv6_ia_ta_t d6it;
7013431Scarlsonj
7023431Scarlsonj if (olen < sizeof (d6it) - sizeof (d6o))
7033431Scarlsonj break;
7043431Scarlsonj (void) memcpy(&d6it, data - sizeof (d6o),
7053431Scarlsonj sizeof (d6it));
7063431Scarlsonj data += sizeof (d6it) - sizeof (d6o);
7073431Scarlsonj olen -= sizeof (d6it) - sizeof (d6o);
7083431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7093431Scarlsonj " IAID = %u", ntohl(d6it.d6it_iaid));
7103431Scarlsonj nest_options(data, olen, "IA: ",
7113431Scarlsonj "Identity Association");
7123431Scarlsonj break;
7133431Scarlsonj }
7143431Scarlsonj case DHCPV6_OPT_IAADDR: {
7153431Scarlsonj dhcpv6_iaaddr_t d6ia;
7163431Scarlsonj
7173431Scarlsonj if (olen < sizeof (d6ia) - sizeof (d6o))
7183431Scarlsonj break;
7193431Scarlsonj (void) memcpy(&d6ia, data - sizeof (d6o),
7203431Scarlsonj sizeof (d6ia));
7213431Scarlsonj data += sizeof (d6ia) - sizeof (d6o);
7223431Scarlsonj olen -= sizeof (d6ia) - sizeof (d6o);
7233431Scarlsonj show_address(" Address", &d6ia.d6ia_addr);
7243431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7253431Scarlsonj " Preferred lifetime = %u seconds",
7263431Scarlsonj ntohl(d6ia.d6ia_preflife));
7273431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7283431Scarlsonj " Valid lifetime = %u seconds",
7293431Scarlsonj ntohl(d6ia.d6ia_vallife));
7303431Scarlsonj nest_options(data, olen, "ADDR: ", "Address");
7313431Scarlsonj break;
7323431Scarlsonj }
7333431Scarlsonj case DHCPV6_OPT_ORO:
7343431Scarlsonj while (olen >= sizeof (val16)) {
7353431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
7363431Scarlsonj val16 = ntohs(val16);
7373431Scarlsonj (void) snprintf(get_line(0, 0),
7383431Scarlsonj get_line_remain(),
7393431Scarlsonj " Requested Option Code = %u (%s)", val16,
7403431Scarlsonj option_to_str(val16));
7413431Scarlsonj data += sizeof (val16);
7423431Scarlsonj olen -= sizeof (val16);
7433431Scarlsonj }
7443431Scarlsonj break;
7453431Scarlsonj case DHCPV6_OPT_PREFERENCE:
7463431Scarlsonj if (olen > 0) {
7473431Scarlsonj (void) snprintf(get_line(0, 0),
7483431Scarlsonj get_line_remain(),
7493431Scarlsonj *data == 255 ?
7503431Scarlsonj " Preference = %u (immediate)" :
7513431Scarlsonj " Preference = %u", *data);
7523431Scarlsonj }
7533431Scarlsonj break;
7543431Scarlsonj case DHCPV6_OPT_ELAPSED_TIME:
7553431Scarlsonj if (olen == sizeof (val16)) {
7563431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
7573431Scarlsonj val16 = ntohs(val16);
7583431Scarlsonj (void) snprintf(get_line(0, 0),
7593431Scarlsonj get_line_remain(),
7603431Scarlsonj " Elapsed Time = %u.%02u seconds",
7613431Scarlsonj val16 / 100, val16 % 100);
7623431Scarlsonj }
7633431Scarlsonj break;
7643431Scarlsonj case DHCPV6_OPT_RELAY_MSG:
7653431Scarlsonj if (olen > 0) {
7663431Scarlsonj oldnest = prot_nest_prefix;
7673431Scarlsonj prot_nest_prefix = prot_prefix;
7683431Scarlsonj retlen = interpret_dhcpv6(F_DTAIL, data, olen);
7693431Scarlsonj prot_prefix = prot_nest_prefix;
7703431Scarlsonj prot_nest_prefix = oldnest;
7713431Scarlsonj }
7723431Scarlsonj break;
7733431Scarlsonj case DHCPV6_OPT_AUTH: {
7743431Scarlsonj dhcpv6_auth_t d6a;
7753431Scarlsonj
7763431Scarlsonj if (olen < DHCPV6_AUTH_SIZE - sizeof (d6o))
7773431Scarlsonj break;
7783431Scarlsonj (void) memcpy(&d6a, data - sizeof (d6o),
7793431Scarlsonj DHCPV6_AUTH_SIZE);
7803431Scarlsonj data += DHCPV6_AUTH_SIZE - sizeof (d6o);
7813431Scarlsonj olen += DHCPV6_AUTH_SIZE - sizeof (d6o);
7823431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7833431Scarlsonj " Protocol = %u (%s)", d6a.d6a_proto,
7843431Scarlsonj authproto_to_str(d6a.d6a_proto));
7853431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7863431Scarlsonj " Algorithm = %u (%s)", d6a.d6a_alg,
7873431Scarlsonj authalg_to_str(d6a.d6a_proto, d6a.d6a_alg));
7883431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
7893431Scarlsonj " Replay Detection Method = %u (%s)", d6a.d6a_rdm,
7903431Scarlsonj authrdm_to_str(d6a.d6a_rdm));
7913431Scarlsonj show_hex(d6a.d6a_replay, sizeof (d6a.d6a_replay),
7923431Scarlsonj " RDM Data");
7933431Scarlsonj if (olen > 0)
7943431Scarlsonj show_hex(data, olen, " Auth Info");
7953431Scarlsonj break;
7963431Scarlsonj }
7973431Scarlsonj case DHCPV6_OPT_UNICAST:
7983431Scarlsonj if (olen >= sizeof (in6_addr_t))
7993431Scarlsonj show_address(" Server Address", data);
8003431Scarlsonj break;
8013431Scarlsonj case DHCPV6_OPT_STATUS_CODE:
8023431Scarlsonj if (olen < sizeof (val16))
8033431Scarlsonj break;
8043431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
8053431Scarlsonj val16 = ntohs(val16);
8063431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
8073431Scarlsonj " Status Code = %u (%s)", val16,
8083431Scarlsonj status_to_str(val16));
8093431Scarlsonj data += sizeof (val16);
8103431Scarlsonj olen -= sizeof (val16);
8113431Scarlsonj if (olen > 0)
8123431Scarlsonj (void) snprintf(get_line(0, 0),
8133431Scarlsonj get_line_remain(), " Text = \"%.*s\"",
8143431Scarlsonj olen, data);
8153431Scarlsonj break;
8163431Scarlsonj case DHCPV6_OPT_VENDOR_CLASS:
8173431Scarlsonj if (olen < sizeof (val32))
8183431Scarlsonj break;
8193431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
8203431Scarlsonj data += sizeof (val32);
8213431Scarlsonj olen -= sizeof (val32);
8223431Scarlsonj val32 = ntohl(val32);
8233431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
8243431Scarlsonj " Enterprise Number = %lu (%s)", val32,
8253431Scarlsonj entr_to_str(val32));
8263431Scarlsonj /* FALLTHROUGH */
8273431Scarlsonj case DHCPV6_OPT_USER_CLASS:
8283431Scarlsonj while (olen >= sizeof (val16)) {
8293431Scarlsonj (void) memcpy(&val16, data, sizeof (val16));
8303431Scarlsonj data += sizeof (val16);
8313431Scarlsonj olen -= sizeof (val16);
8323431Scarlsonj val16 = ntohs(val16);
8333431Scarlsonj if (val16 > olen) {
8343431Scarlsonj (void) strlcpy(get_line(0, 0),
8353431Scarlsonj " Truncated class",
8363431Scarlsonj get_line_remain());
8373431Scarlsonj val16 = olen;
8383431Scarlsonj }
8393431Scarlsonj show_hex(data, olen, " Class");
8403431Scarlsonj data += val16;
8413431Scarlsonj olen -= val16;
8423431Scarlsonj }
8433431Scarlsonj break;
8443431Scarlsonj case DHCPV6_OPT_VENDOR_OPT: {
8453431Scarlsonj dhcpv6_option_t sd6o;
8463431Scarlsonj
8473431Scarlsonj if (olen < sizeof (val32))
8483431Scarlsonj break;
8493431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
8503431Scarlsonj data += sizeof (val32);
8513431Scarlsonj olen -= sizeof (val32);
8523431Scarlsonj val32 = ntohl(val32);
8533431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
8543431Scarlsonj " Enterprise Number = %lu (%s)", val32,
8553431Scarlsonj entr_to_str(val32));
8563431Scarlsonj while (olen >= sizeof (sd6o)) {
8573431Scarlsonj (void) memcpy(&sd6o, data, sizeof (sd6o));
8583431Scarlsonj sd6o.d6o_code = ntohs(sd6o.d6o_code);
8593431Scarlsonj sd6o.d6o_len = ntohs(sd6o.d6o_len);
8603431Scarlsonj (void) snprintf(get_line(0, 0),
8613431Scarlsonj get_line_remain(),
8623431Scarlsonj " Vendor Option Code = %u", d6o.d6o_code);
8633431Scarlsonj data += sizeof (d6o);
8643431Scarlsonj olen -= sizeof (d6o);
8653431Scarlsonj if (sd6o.d6o_len > olen) {
8663431Scarlsonj (void) strlcpy(get_line(0, 0),
8673431Scarlsonj " Vendor Option truncated",
8683431Scarlsonj get_line_remain());
8693431Scarlsonj sd6o.d6o_len = olen;
8703431Scarlsonj }
8713431Scarlsonj if (sd6o.d6o_len > 0) {
8723431Scarlsonj show_hex(data, sd6o.d6o_len,
8733431Scarlsonj " Data");
8743431Scarlsonj data += sd6o.d6o_len;
8753431Scarlsonj olen -= sd6o.d6o_len;
8763431Scarlsonj }
8773431Scarlsonj }
8783431Scarlsonj break;
8793431Scarlsonj }
8803431Scarlsonj case DHCPV6_OPT_REMOTE_ID:
8813431Scarlsonj if (olen < sizeof (val32))
8823431Scarlsonj break;
8833431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
8843431Scarlsonj data += sizeof (val32);
8853431Scarlsonj olen -= sizeof (val32);
8863431Scarlsonj val32 = ntohl(val32);
8873431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
8883431Scarlsonj " Enterprise Number = %lu (%s)", val32,
8893431Scarlsonj entr_to_str(val32));
8903431Scarlsonj /* FALLTHROUGH */
8913431Scarlsonj case DHCPV6_OPT_INTERFACE_ID:
8923431Scarlsonj case DHCPV6_OPT_SUBSCRIBER:
8933431Scarlsonj if (olen > 0)
8943431Scarlsonj show_hex(data, olen, " ID");
8953431Scarlsonj break;
8963431Scarlsonj case DHCPV6_OPT_RECONF_MSG:
8973431Scarlsonj if (olen > 0) {
8983431Scarlsonj (void) snprintf(get_line(0, 0),
8993431Scarlsonj get_line_remain(),
9003431Scarlsonj " Message Type = %u (%s)", *data,
9013431Scarlsonj reconf_to_str(*data));
9023431Scarlsonj }
9033431Scarlsonj break;
9043431Scarlsonj case DHCPV6_OPT_SIP_NAMES:
9053431Scarlsonj case DHCPV6_OPT_DNS_SEARCH:
9063431Scarlsonj case DHCPV6_OPT_NIS_DOMAIN:
9073431Scarlsonj case DHCPV6_OPT_BCMCS_SRV_D: {
9083431Scarlsonj dhcp_symbol_t *symp;
9093431Scarlsonj char *sp2;
9103431Scarlsonj
9113431Scarlsonj symp = inittab_getbycode(
9123431Scarlsonj ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
9133431Scarlsonj d6o.d6o_code);
9143431Scarlsonj if (symp != NULL) {
9153431Scarlsonj str = inittab_decode(symp, data, olen, B_TRUE);
9163431Scarlsonj if (str != NULL) {
9173431Scarlsonj sp = str;
9183431Scarlsonj do {
9193431Scarlsonj sp2 = strchr(sp, ' ');
9203431Scarlsonj if (sp2 != NULL)
9213431Scarlsonj *sp2++ = '\0';
9223431Scarlsonj (void) snprintf(get_line(0, 0),
9233431Scarlsonj get_line_remain(),
9243431Scarlsonj " Name = %s", sp);
9253431Scarlsonj } while ((sp = sp2) != NULL);
9263431Scarlsonj free(str);
9273431Scarlsonj }
9283431Scarlsonj free(symp);
9293431Scarlsonj }
9303431Scarlsonj break;
9313431Scarlsonj }
9323431Scarlsonj case DHCPV6_OPT_SIP_ADDR:
9333431Scarlsonj case DHCPV6_OPT_DNS_ADDR:
9343431Scarlsonj case DHCPV6_OPT_NIS_SERVERS:
9353431Scarlsonj case DHCPV6_OPT_SNTP_SERVERS:
9363431Scarlsonj case DHCPV6_OPT_BCMCS_SRV_A:
9373431Scarlsonj while (olen >= sizeof (in6_addr_t)) {
9383431Scarlsonj show_address(" Address", data);
9393431Scarlsonj data += sizeof (in6_addr_t);
9403431Scarlsonj olen -= sizeof (in6_addr_t);
9413431Scarlsonj }
9423431Scarlsonj break;
9433431Scarlsonj case DHCPV6_OPT_IAPREFIX: {
9443431Scarlsonj dhcpv6_iaprefix_t d6ip;
9453431Scarlsonj
9463431Scarlsonj if (olen < DHCPV6_IAPREFIX_SIZE - sizeof (d6o))
9473431Scarlsonj break;
9483431Scarlsonj (void) memcpy(&d6ip, data - sizeof (d6o),
9493431Scarlsonj DHCPV6_IAPREFIX_SIZE);
9503431Scarlsonj data += DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
9513431Scarlsonj olen -= DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
9523431Scarlsonj show_address(" Prefix", d6ip.d6ip_addr);
9533431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9543431Scarlsonj " Preferred lifetime = %u seconds",
9553431Scarlsonj ntohl(d6ip.d6ip_preflife));
9563431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9573431Scarlsonj " Valid lifetime = %u seconds",
9583431Scarlsonj ntohl(d6ip.d6ip_vallife));
9593431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9603431Scarlsonj " Prefix length = %u", d6ip.d6ip_preflen);
9613431Scarlsonj nest_options(data, olen, "ADDR: ", "Address");
9623431Scarlsonj break;
9633431Scarlsonj }
9643431Scarlsonj case DHCPV6_OPT_INFO_REFTIME:
9653431Scarlsonj if (olen < sizeof (val32))
9663431Scarlsonj break;
9673431Scarlsonj (void) memcpy(&val32, data, sizeof (val32));
9683431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9693431Scarlsonj " Refresh Time = %lu seconds", ntohl(val32));
9703431Scarlsonj break;
9713431Scarlsonj case DHCPV6_OPT_GEOCONF_CVC: {
9723431Scarlsonj dhcpv6_civic_t d6c;
9733431Scarlsonj int solen;
9743431Scarlsonj
9753431Scarlsonj if (olen < DHCPV6_CIVIC_SIZE - sizeof (d6o))
9763431Scarlsonj break;
9773431Scarlsonj (void) memcpy(&d6c, data - sizeof (d6o),
9783431Scarlsonj DHCPV6_CIVIC_SIZE);
9793431Scarlsonj data += DHCPV6_CIVIC_SIZE - sizeof (d6o);
9803431Scarlsonj olen -= DHCPV6_CIVIC_SIZE - sizeof (d6o);
9813431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9823431Scarlsonj " What Location = %u (%s)", d6c.d6c_what,
9833431Scarlsonj cwhat_to_str(d6c.d6c_what));
9843431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
9853431Scarlsonj " Country Code = %.*s", sizeof (d6c.d6c_cc),
9863431Scarlsonj d6c.d6c_cc);
9873431Scarlsonj while (olen >= 2) {
9883431Scarlsonj (void) snprintf(get_line(0, 0),
9893431Scarlsonj get_line_remain(),
9903431Scarlsonj " CA Element = %u (%s)", *data,
9913431Scarlsonj catype_to_str(*data));
9923431Scarlsonj solen = data[1];
9933431Scarlsonj data += 2;
9943431Scarlsonj olen -= 2;
9953431Scarlsonj if (solen > olen) {
9963431Scarlsonj (void) strlcpy(get_line(0, 0),
9973431Scarlsonj " CA Element truncated",
9983431Scarlsonj get_line_remain());
9993431Scarlsonj solen = olen;
10003431Scarlsonj }
10013431Scarlsonj if (solen > 0) {
10023431Scarlsonj show_ascii(data, solen, " CA Data");
10033431Scarlsonj data += solen;
10043431Scarlsonj olen -= solen;
10053431Scarlsonj }
10063431Scarlsonj }
10073431Scarlsonj break;
10083431Scarlsonj }
10093431Scarlsonj case DHCPV6_OPT_CLIENT_FQDN: {
10103431Scarlsonj dhcp_symbol_t *symp;
10113431Scarlsonj
10123431Scarlsonj if (olen == 0)
10133431Scarlsonj break;
10143431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
10153431Scarlsonj " Flags = %02x", *data);
10163431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
10173431Scarlsonj " %s", getflag(*data, DHCPV6_FQDNF_S,
10183431Scarlsonj "Perform AAAA RR updates", "No AAAA RR updates"));
10193431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
10203431Scarlsonj " %s", getflag(*data, DHCPV6_FQDNF_O,
10213431Scarlsonj "Server override updates",
10223431Scarlsonj "No server override updates"));
10233431Scarlsonj (void) snprintf(get_line(0, 0), get_line_remain(),
10243431Scarlsonj " %s", getflag(*data, DHCPV6_FQDNF_N,
10253431Scarlsonj "Server performs no updates",
10263431Scarlsonj "Server performs updates"));
10273431Scarlsonj symp = inittab_getbycode(
10283431Scarlsonj ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
10293431Scarlsonj d6o.d6o_code);
10303431Scarlsonj if (symp != NULL) {
10313431Scarlsonj str = inittab_decode(symp, data, olen, B_TRUE);
10323431Scarlsonj if (str != NULL) {
10333431Scarlsonj (void) snprintf(get_line(0, 0),
10343431Scarlsonj get_line_remain(),
10353431Scarlsonj " FQDN = %s", str);
10363431Scarlsonj free(str);
10373431Scarlsonj }
10383431Scarlsonj free(symp);
10393431Scarlsonj }
10403431Scarlsonj break;
10413431Scarlsonj }
10423431Scarlsonj }
10433431Scarlsonj data = ostart + d6o.d6o_len;
10443431Scarlsonj len -= d6o.d6o_len;
10453431Scarlsonj }
10463431Scarlsonj if (len != 0) {
10473431Scarlsonj (void) strlcpy(get_line(0, 0), "Option entry truncated",
10483431Scarlsonj get_line_remain());
10493431Scarlsonj }
10503431Scarlsonj }
1051