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