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