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