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