Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (C) 1998 and 1999 WIDE Project.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. Neither the name of the project nor the names of its contributors
     14  *    may be used to endorse or promote products derived from this software
     15  *    without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 /*
     30  * RFC3315: DHCPv6
     31  * supported DHCPv6 options:
     32  *  RFC3319,
     33  *  RFC3633,
     34  *  RFC3646,
     35  *  RFC3898,
     36  *  RFC4075,
     37  *  RFC4242,
     38  *  RFC4280,
     39  */
     40 
     41 #ifndef lint
     42 static const char rcsid[] _U_ =
     43     "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.35.2.1 2006/10/25 22:04:36 guy Exp $";
     44 #endif
     45 
     46 #ifdef HAVE_CONFIG_H
     47 #include "config.h"
     48 #endif
     49 
     50 #include <tcpdump-stdinc.h>
     51 
     52 #include <stdio.h>
     53 #include <string.h>
     54 
     55 #include "interface.h"
     56 #include "addrtoname.h"
     57 #include "extract.h"
     58 
     59 /* lease duration */
     60 #define DHCP6_DURATITION_INFINITE 0xffffffff
     61 
     62 /* Error Values */
     63 #define DH6ERR_FAILURE		16
     64 #define DH6ERR_AUTHFAIL		17
     65 #define DH6ERR_POORLYFORMED	18
     66 #define DH6ERR_UNAVAIL		19
     67 #define DH6ERR_OPTUNAVAIL	20
     68 
     69 /* Message type */
     70 #define DH6_SOLICIT	1
     71 #define DH6_ADVERTISE	2
     72 #define DH6_REQUEST	3
     73 #define DH6_CONFIRM	4
     74 #define DH6_RENEW	5
     75 #define DH6_REBIND	6
     76 #define DH6_REPLY	7
     77 #define DH6_RELEASE	8
     78 #define DH6_DECLINE	9
     79 #define DH6_RECONFIGURE	10
     80 #define DH6_INFORM_REQ	11
     81 #define DH6_RELAY_FORW	12
     82 #define DH6_RELAY_REPLY	13
     83 
     84 /* DHCP6 base packet format */
     85 struct dhcp6 {
     86 	union {
     87 		u_int8_t m;
     88 		u_int32_t x;
     89 	} dh6_msgtypexid;
     90 	/* options follow */
     91 };
     92 #define dh6_msgtype	dh6_msgtypexid.m
     93 #define dh6_xid		dh6_msgtypexid.x
     94 #define DH6_XIDMASK	0x00ffffff
     95 
     96 /* DHCPv6 relay messages */
     97 struct dhcp6_relay {
     98 	u_int8_t dh6relay_msgtype;
     99 	u_int8_t dh6relay_hcnt;
    100 	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
    101 	u_int8_t dh6relay_peeraddr[16];
    102 	/* options follow */
    103 };
    104 
    105 /* options */
    106 #define DH6OPT_CLIENTID	1
    107 #define DH6OPT_SERVERID	2
    108 #define DH6OPT_IA_NA 3
    109 #define DH6OPT_IA_TA 4
    110 #define DH6OPT_IA_ADDR 5
    111 #define DH6OPT_ORO 6
    112 #define DH6OPT_PREFERENCE 7
    113 #  define DH6OPT_PREF_MAX 255
    114 #define DH6OPT_ELAPSED_TIME 8
    115 #define DH6OPT_RELAY_MSG 9
    116 /*#define DH6OPT_SERVER_MSG 10 deprecated */
    117 #define DH6OPT_AUTH 11
    118 #  define DH6OPT_AUTHPROTO_DELAYED 2
    119 #  define DH6OPT_AUTHPROTO_RECONFIG 3
    120 #  define DH6OPT_AUTHALG_HMACMD5 1
    121 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
    122 #  define DH6OPT_AUTHRECONFIG_KEY 1
    123 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
    124 #define DH6OPT_UNICAST 12
    125 #define DH6OPT_STATUS_CODE 13
    126 #  define DH6OPT_STCODE_SUCCESS 0
    127 #  define DH6OPT_STCODE_UNSPECFAIL 1
    128 #  define DH6OPT_STCODE_NOADDRAVAIL 2
    129 #  define DH6OPT_STCODE_NOBINDING 3
    130 #  define DH6OPT_STCODE_NOTONLINK 4
    131 #  define DH6OPT_STCODE_USEMULTICAST 5
    132 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
    133 #define DH6OPT_RAPID_COMMIT 14
    134 #define DH6OPT_USER_CLASS 15
    135 #define DH6OPT_VENDOR_CLASS 16
    136 #define DH6OPT_VENDOR_OPTS 17
    137 #define DH6OPT_INTERFACE_ID 18
    138 #define DH6OPT_RECONF_MSG 19
    139 #define DH6OPT_RECONF_ACCEPT 20
    140 #define DH6OPT_SIP_SERVER_D 21
    141 #define DH6OPT_SIP_SERVER_A 22
    142 #define DH6OPT_DNS 23
    143 #define DH6OPT_DNSNAME 24
    144 #define DH6OPT_IA_PD 25
    145 #define DH6OPT_IA_PD_PREFIX 26
    146 #define DH6OPT_NIS_SERVERS 27
    147 #define DH6OPT_NISP_SERVERS 28
    148 #define DH6OPT_NIS_NAME 29
    149 #define DH6OPT_NISP_NAME 30
    150 #define DH6OPT_NTP_SERVERS 31
    151 #define DH6OPT_LIFETIME 32
    152 #define DH6OPT_BCMCS_SERVER_D 33
    153 #define DH6OPT_BCMCS_SERVER_A 34
    154 #define DH6OPT_GEOCONF_CIVIC 36
    155 #define DH6OPT_REMOTE_ID 37
    156 #define DH6OPT_SUBSCRIBER_ID 38
    157 #define DH6OPT_CLIENT_FQDN 39
    158 
    159 struct dhcp6opt {
    160 	u_int16_t dh6opt_type;
    161 	u_int16_t dh6opt_len;
    162 	/* type-dependent data follows */
    163 };
    164 
    165 struct dhcp6_ia {
    166 	u_int16_t dh6opt_ia_type;
    167 	u_int16_t dh6opt_ia_len;
    168 	u_int32_t dh6opt_ia_iaid;
    169 	u_int32_t dh6opt_ia_t1;
    170 	u_int32_t dh6opt_ia_t2;
    171 };
    172 
    173 struct dhcp6_ia_addr {
    174 	u_int16_t dh6opt_ia_addr_type;
    175 	u_int16_t dh6opt_ia_addr_len;
    176 	struct in6_addr dh6opt_ia_addr_addr;
    177 	u_int32_t dh6opt_ia_addr_pltime;
    178 	u_int32_t dh6opt_ia_addr_vltime;
    179 }  __attribute__ ((__packed__));
    180 
    181 struct dhcp6_ia_prefix {
    182 	u_int16_t dh6opt_ia_prefix_type;
    183 	u_int16_t dh6opt_ia_prefix_len;
    184 	u_int32_t dh6opt_ia_prefix_pltime;
    185 	u_int32_t dh6opt_ia_prefix_vltime;
    186 	u_int8_t dh6opt_ia_prefix_plen;
    187 	struct in6_addr dh6opt_ia_prefix_addr;
    188 }  __attribute__ ((__packed__));
    189 
    190 struct dhcp6_auth {
    191 	u_int16_t dh6opt_auth_type;
    192 	u_int16_t dh6opt_auth_len;
    193 	u_int8_t dh6opt_auth_proto;
    194 	u_int8_t dh6opt_auth_alg;
    195 	u_int8_t dh6opt_auth_rdm;
    196 	u_int8_t dh6opt_auth_rdinfo[8];
    197 	/* authentication information follows */
    198 } __attribute__ ((__packed__));
    199 
    200 static const char *
    201 dhcp6opt_name(int type)
    202 {
    203 	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
    204 
    205 	if (type > 65535)
    206 		return "INVALID option";
    207 
    208 	switch(type) {
    209 	case DH6OPT_CLIENTID:
    210 		return "client ID";
    211 	case DH6OPT_SERVERID:
    212 		return "server ID";
    213 	case DH6OPT_IA_NA:
    214 		return "IA_NA";
    215 	case DH6OPT_IA_TA:
    216 		return "IA_TA";
    217 	case DH6OPT_IA_ADDR:
    218 		return "IA_ADDR";
    219 	case DH6OPT_ORO:
    220 		return "option request";
    221 	case DH6OPT_PREFERENCE:
    222 		return "preference";
    223 	case DH6OPT_ELAPSED_TIME:
    224 		return "elapsed time";
    225 	case DH6OPT_RELAY_MSG:
    226 		return "relay message";
    227 	case DH6OPT_AUTH:
    228 		return "authentication";
    229 	case DH6OPT_UNICAST:
    230 		return "server unicast";
    231 	case DH6OPT_STATUS_CODE:
    232 		return "status code";
    233 	case DH6OPT_RAPID_COMMIT:
    234 		return "rapid commit";
    235 	case DH6OPT_USER_CLASS:
    236 		return "user class";
    237 	case DH6OPT_VENDOR_CLASS:
    238 		return "vendor class";
    239 	case DH6OPT_VENDOR_OPTS:
    240 		return "vendor-specific info";
    241 	case DH6OPT_INTERFACE_ID:
    242 		return "interface ID";
    243 	case DH6OPT_RECONF_MSG:
    244 		return "reconfigure message";
    245 	case DH6OPT_RECONF_ACCEPT:
    246 		return "reconfigure accept";
    247 	case DH6OPT_SIP_SERVER_D:
    248 		return "SIP servers domain";
    249 	case DH6OPT_SIP_SERVER_A:
    250 		return "SIP servers address";
    251 	case DH6OPT_DNS:
    252 		return "DNS";
    253 	case DH6OPT_DNSNAME:
    254 		return "DNS name";
    255 	case DH6OPT_IA_PD:
    256 		return "IA_PD";
    257 	case DH6OPT_IA_PD_PREFIX:
    258 		return "IA_PD prefix";
    259 	case DH6OPT_NTP_SERVERS:
    260 		return "NTP Server";
    261 	case DH6OPT_LIFETIME:
    262 		return "lifetime";
    263 	case DH6OPT_NIS_SERVERS:
    264 		return "NIS server";
    265 	case DH6OPT_NISP_SERVERS:
    266 		return "NIS+ server";
    267 	case DH6OPT_NIS_NAME:
    268 		return "NIS domain name";
    269 	case DH6OPT_NISP_NAME:
    270 		return "NIS+ domain name";
    271 	case DH6OPT_BCMCS_SERVER_D:
    272 		return "BCMCS domain name";
    273 	case DH6OPT_BCMCS_SERVER_A:
    274 		return "BCMCS server";
    275 	case DH6OPT_GEOCONF_CIVIC:
    276 		return "Geoconf Civic";
    277 	case DH6OPT_REMOTE_ID:
    278 		return "Remote ID";
    279 	case DH6OPT_SUBSCRIBER_ID:
    280 		return "Subscriber ID";
    281 	case DH6OPT_CLIENT_FQDN:
    282 		return "Client FQDN";
    283 	default:
    284 		snprintf(genstr, sizeof(genstr), "opt_%d", type);
    285 		return(genstr);
    286 	}
    287 }
    288 
    289 static const char *
    290 dhcp6stcode(int code)
    291 {
    292 	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
    293 
    294 	if (code > 255)
    295 		return "INVALID code";
    296 
    297 	switch(code) {
    298 	case DH6OPT_STCODE_SUCCESS:
    299 		return "success";
    300 	case DH6OPT_STCODE_UNSPECFAIL:
    301 		return "unspec failure";
    302 	case DH6OPT_STCODE_NOADDRAVAIL:
    303 		return "no addresses";
    304 	case DH6OPT_STCODE_NOBINDING:
    305 		return "no binding";
    306 	case DH6OPT_STCODE_NOTONLINK:
    307 		return "not on-link";
    308 	case DH6OPT_STCODE_USEMULTICAST:
    309 		return "use multicast";
    310 	case DH6OPT_STCODE_NOPREFIXAVAIL:
    311 		return "no prefixes";
    312 	default:
    313 		snprintf(genstr, sizeof(genstr), "code%d", code);
    314 		return(genstr);
    315 	}
    316 }
    317 
    318 static void
    319 dhcp6opt_print(const u_char *cp, const u_char *ep)
    320 {
    321 	struct dhcp6opt *dh6o;
    322 	u_char *tp;
    323 	size_t i;
    324 	u_int16_t opttype;
    325 	size_t optlen;
    326 	u_int16_t val16;
    327 	u_int32_t val32;
    328 	struct dhcp6_ia ia;
    329 	struct dhcp6_ia_prefix ia_prefix;
    330 	struct dhcp6_ia_addr ia_addr;
    331 	struct dhcp6_auth authopt;
    332 	u_int authinfolen, authrealmlen;
    333 
    334 	if (cp == ep)
    335 		return;
    336 	while (cp < ep) {
    337 		if (ep < cp + sizeof(*dh6o))
    338 			goto trunc;
    339 		dh6o = (struct dhcp6opt *)cp;
    340 		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
    341 		if (ep < cp + sizeof(*dh6o) + optlen)
    342 			goto trunc;
    343 		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
    344 		printf(" (%s", dhcp6opt_name(opttype));
    345 		switch (opttype) {
    346 		case DH6OPT_CLIENTID:
    347 		case DH6OPT_SERVERID:
    348 			if (optlen < 2) {
    349 				/*(*/
    350 				printf(" ?)");
    351 				break;
    352 			}
    353 			tp = (u_char *)(dh6o + 1);
    354 			switch (EXTRACT_16BITS(tp)) {
    355 			case 1:
    356 				if (optlen >= 2 + 6) {
    357 					printf(" hwaddr/time type %u time %u ",
    358 					    EXTRACT_16BITS(&tp[2]),
    359 					    EXTRACT_32BITS(&tp[4]));
    360 					for (i = 8; i < optlen; i++)
    361 						printf("%02x", tp[i]);
    362 					/*(*/
    363 					printf(")");
    364 				} else {
    365 					/*(*/
    366 					printf(" ?)");
    367 				}
    368 				break;
    369 			case 2:
    370 				if (optlen >= 2 + 8) {
    371 					printf(" vid ");
    372 					for (i = 2; i < 2 + 8; i++)
    373 						printf("%02x", tp[i]);
    374 					/*(*/
    375 					printf(")");
    376 				} else {
    377 					/*(*/
    378 					printf(" ?)");
    379 				}
    380 				break;
    381 			case 3:
    382 				if (optlen >= 2 + 2) {
    383 					printf(" hwaddr type %u ",
    384 					    EXTRACT_16BITS(&tp[2]));
    385 					for (i = 4; i < optlen; i++)
    386 						printf("%02x", tp[i]);
    387 					/*(*/
    388 					printf(")");
    389 				} else {
    390 					/*(*/
    391 					printf(" ?)");
    392 				}
    393 				break;
    394 			default:
    395 				printf(" type %d)", EXTRACT_16BITS(tp));
    396 				break;
    397 			}
    398 			break;
    399 		case DH6OPT_IA_ADDR:
    400 			if (optlen < sizeof(ia_addr) - 4) {
    401 				printf(" ?)");
    402 				break;
    403 			}
    404 			memcpy(&ia_addr, (u_char *)dh6o, sizeof(ia_addr));
    405 			printf(" %s",
    406 			    ip6addr_string(&ia_addr.dh6opt_ia_addr_addr));
    407 			ia_addr.dh6opt_ia_addr_pltime =
    408 			    ntohl(ia_addr.dh6opt_ia_addr_pltime);
    409 			ia_addr.dh6opt_ia_addr_vltime =
    410 			    ntohl(ia_addr.dh6opt_ia_addr_vltime);
    411 			printf(" pltime:%lu vltime:%lu",
    412 			    (unsigned long)ia_addr.dh6opt_ia_addr_pltime,
    413 			    (unsigned long)ia_addr.dh6opt_ia_addr_vltime);
    414 			if (optlen > sizeof(ia_addr) - 4) {
    415 				/* there are sub-options */
    416 				dhcp6opt_print((u_char *)dh6o +
    417 				    sizeof(ia_addr),
    418 				    (u_char *)(dh6o + 1) + optlen);
    419 			}
    420 			printf(")");
    421 			break;
    422 		case DH6OPT_ORO:
    423 			if (optlen % 2) {
    424 				printf(" ?)");
    425 				break;
    426 			}
    427 			tp = (u_char *)(dh6o + 1);
    428 			for (i = 0; i < optlen; i += 2) {
    429 				u_int16_t opt;
    430 
    431 				memcpy(&opt, &tp[i], sizeof(opt));
    432 				printf(" %s", dhcp6opt_name(ntohs(opt)));
    433 			}
    434 			printf(")");
    435 			break;
    436 		case DH6OPT_PREFERENCE:
    437 			if (optlen != 1) {
    438 				printf(" ?)");
    439 				break;
    440 			}
    441 			printf(" %d)", *((u_char *)(dh6o + 1) + 1));
    442 			break;
    443 		case DH6OPT_ELAPSED_TIME:
    444 			if (optlen != 2) {
    445 				printf(" ?)");
    446 				break;
    447 			}
    448 			memcpy(&val16, dh6o + 1, sizeof(val16));
    449 			val16 = ntohs(val16);
    450 			printf(" %d)", (int)val16);
    451 			break;
    452 		case DH6OPT_RELAY_MSG:
    453 			printf(" (");
    454 			dhcp6_print((const u_char *)(dh6o + 1), optlen);
    455 			printf(")");
    456 			break;
    457 		case DH6OPT_AUTH:
    458 			if (optlen < sizeof(authopt) - sizeof(*dh6o)) {
    459 				printf(" ?)");
    460 				break;
    461 			}
    462 			memcpy(&authopt, dh6o, sizeof(authopt));
    463 			switch (authopt.dh6opt_auth_proto) {
    464 			case DH6OPT_AUTHPROTO_DELAYED:
    465 				printf(" proto: delayed");
    466 				break;
    467 			case DH6OPT_AUTHPROTO_RECONFIG:
    468 				printf(" proto: reconfigure");
    469 				break;
    470 			default:
    471 				printf(" proto: %d",
    472 				    authopt.dh6opt_auth_proto);
    473 				break;
    474 			}
    475 			switch (authopt.dh6opt_auth_alg) {
    476 			case DH6OPT_AUTHALG_HMACMD5:
    477 				/* XXX: may depend on the protocol */
    478 				printf(", alg: HMAC-MD5");
    479 				break;
    480 			default:
    481 				printf(", alg: %d", authopt.dh6opt_auth_alg);
    482 				break;
    483 			}
    484 			switch (authopt.dh6opt_auth_rdm) {
    485 			case DH6OPT_AUTHRDM_MONOCOUNTER:
    486 				printf(", RDM: mono");
    487 				break;
    488 			default:
    489 				printf(", RDM: %d", authopt.dh6opt_auth_rdm);
    490 				break;
    491 			}
    492 			tp = (u_char *)&authopt.dh6opt_auth_rdinfo;
    493 			printf(", RD:");
    494 			for (i = 0; i < 4; i++, tp += sizeof(val16))
    495 				printf(" %04x", EXTRACT_16BITS(tp));
    496 
    497 			/* protocol dependent part */
    498 			tp = (u_char *)dh6o + sizeof(authopt);
    499 			authinfolen =
    500 			    optlen + sizeof(*dh6o) - sizeof(authopt);
    501 			switch (authopt.dh6opt_auth_proto) {
    502 			case DH6OPT_AUTHPROTO_DELAYED:
    503 				if (authinfolen == 0)
    504 					break;
    505 				if (authinfolen < 20) {
    506 					printf(" ??");
    507 					break;
    508 				}
    509 				authrealmlen = authinfolen - 20;
    510 				if (authrealmlen > 0) {
    511 					printf(", realm: ");
    512 				}
    513 				for (i = 0; i < authrealmlen; i++, tp++)
    514 					printf("%02x", *tp);
    515 				printf(", key ID: %08x", EXTRACT_32BITS(tp));
    516 				tp += 4;
    517 				printf(", HMAC-MD5:");
    518 				for (i = 0; i < 4; i++, tp+= 4)
    519 					printf(" %08x", EXTRACT_32BITS(tp));
    520 				break;
    521 			case DH6OPT_AUTHPROTO_RECONFIG:
    522 				if (authinfolen != 17) {
    523 					printf(" ??");
    524 					break;
    525 				}
    526 				switch (*tp++) {
    527 				case DH6OPT_AUTHRECONFIG_KEY:
    528 					printf(" reconfig-key");
    529 					break;
    530 				case DH6OPT_AUTHRECONFIG_HMACMD5:
    531 					printf(" type: HMAC-MD5");
    532 					break;
    533 				default:
    534 					printf(" type: ??");
    535 					break;
    536 				}
    537 				printf(" value:");
    538 				for (i = 0; i < 4; i++, tp+= 4)
    539 					printf(" %08x", EXTRACT_32BITS(tp));
    540 				break;
    541 			default:
    542 				printf(" ??");
    543 				break;
    544 			}
    545 
    546 			printf(")");
    547 			break;
    548 		case DH6OPT_RAPID_COMMIT: /* nothing todo */
    549 			printf(")");
    550 			break;
    551 		case DH6OPT_INTERFACE_ID:
    552 			/*
    553 			 * Since we cannot predict the encoding, print hex dump
    554 			 * at most 10 characters.
    555 			 */
    556 			for (i = 0; i < optlen && i < 10; i++)
    557 				printf("%02x", ((u_char *)(dh6o + 1))[i]);
    558 			break;
    559 		case DH6OPT_RECONF_MSG:
    560 			tp = (u_char *)(dh6o + 1);
    561 			switch (*tp) {
    562 			case DH6_RENEW:
    563 				printf(" for renew)");
    564 				break;
    565 			case DH6_INFORM_REQ:
    566 				printf(" for inf-req)");
    567 				break;
    568 			default:
    569 				printf(" for ?\?\?(%02x))", *tp);
    570 				break;
    571 			}
    572 			break;
    573 		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
    574 			printf(")");
    575 			break;
    576 		case DH6OPT_SIP_SERVER_A:
    577 		case DH6OPT_DNS:
    578 		case DH6OPT_NTP_SERVERS:
    579 		case DH6OPT_NIS_SERVERS:
    580 		case DH6OPT_NISP_SERVERS:
    581 		case DH6OPT_BCMCS_SERVER_A:
    582 			if (optlen % 16) {
    583 				printf(" ?)");
    584 				break;
    585 			}
    586 			tp = (u_char *)(dh6o + 1);
    587 			for (i = 0; i < optlen; i += 16)
    588 				printf(" %s", ip6addr_string(&tp[i]));
    589 			printf(")");
    590 			break;
    591 		case DH6OPT_STATUS_CODE:
    592 			if (optlen < 2) {
    593 				printf(" ?)");
    594 				break;
    595 			}
    596 			memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
    597 			val16 = ntohs(val16);
    598 			printf(" %s)", dhcp6stcode(val16));
    599 			break;
    600 		case DH6OPT_IA_NA:
    601 		case DH6OPT_IA_PD:
    602 			if (optlen < sizeof(ia) - 4) {
    603 				printf(" ?)");
    604 				break;
    605 			}
    606 			memcpy(&ia, (u_char *)dh6o, sizeof(ia));
    607 			ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
    608 			ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
    609 			ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
    610 			printf(" IAID:%lu T1:%lu T2:%lu",
    611 			    (unsigned long)ia.dh6opt_ia_iaid,
    612 			    (unsigned long)ia.dh6opt_ia_t1,
    613 			    (unsigned long)ia.dh6opt_ia_t2);
    614 			if (optlen > sizeof(ia) - 4) {
    615 				/* there are sub-options */
    616 				dhcp6opt_print((u_char *)dh6o + sizeof(ia),
    617 				    (u_char *)(dh6o + 1) + optlen);
    618 			}
    619 			printf(")");
    620 			break;
    621 		case DH6OPT_IA_PD_PREFIX:
    622 			if (optlen < sizeof(ia_prefix) - 4) {
    623 				printf(" ?)");
    624 				break;
    625 			}
    626 			memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
    627 			printf(" %s/%d",
    628 			    ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
    629 			    ia_prefix.dh6opt_ia_prefix_plen);
    630 			ia_prefix.dh6opt_ia_prefix_pltime =
    631 			    ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
    632 			ia_prefix.dh6opt_ia_prefix_vltime =
    633 			    ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
    634 			printf(" pltime:%lu vltime:%lu",
    635 			    (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
    636 			    (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
    637 			if (optlen > sizeof(ia_prefix) - 4) {
    638 				/* there are sub-options */
    639 				dhcp6opt_print((u_char *)dh6o +
    640 				    sizeof(ia_prefix),
    641 				    (u_char *)(dh6o + 1) + optlen);
    642 			}
    643 			printf(")");
    644 			break;
    645 		case DH6OPT_LIFETIME:
    646 			if (optlen != 4) {
    647 				printf(" ?)");
    648 				break;
    649 			}
    650 			memcpy(&val32, dh6o + 1, sizeof(val32));
    651 			val32 = ntohl(val32);
    652 			printf(" %d)", (int)val32);
    653 			break;
    654 		default:
    655 			printf(")");
    656 			break;
    657 		}
    658 
    659 		cp += sizeof(*dh6o) + optlen;
    660 	}
    661 	return;
    662 
    663 trunc:
    664 	printf("[|dhcp6ext]");
    665 }
    666 
    667 /*
    668  * Print dhcp6 packets
    669  */
    670 void
    671 dhcp6_print(const u_char *cp, u_int length)
    672 {
    673 	struct dhcp6 *dh6;
    674 	struct dhcp6_relay *dh6relay;
    675 	const u_char *ep;
    676 	u_char *extp;
    677 	const char *name;
    678 
    679 	printf("dhcp6");
    680 
    681 	ep = (u_char *)snapend;
    682 	if (cp + length < ep)
    683 		ep = cp + length;
    684 
    685 	dh6 = (struct dhcp6 *)cp;
    686 	dh6relay = (struct dhcp6_relay *)cp;
    687 	TCHECK(dh6->dh6_xid);
    688 	switch (dh6->dh6_msgtype) {
    689 	case DH6_SOLICIT:
    690 		name = "solicit";
    691 		break;
    692 	case DH6_ADVERTISE:
    693 		name = "advertise";
    694 		break;
    695 	case DH6_REQUEST:
    696 		name = "request";
    697 		break;
    698 	case DH6_CONFIRM:
    699 		name = "confirm";
    700 		break;
    701 	case DH6_RENEW:
    702 		name = "renew";
    703 		break;
    704 	case DH6_REBIND:
    705 		name = "rebind";
    706 		break;
    707 	case DH6_REPLY:
    708 		name = "reply";
    709 		break;
    710 	case DH6_RELEASE:
    711 		name = "release";
    712 		break;
    713 	case DH6_DECLINE:
    714 		name = "decline";
    715 		break;
    716 	case DH6_RECONFIGURE:
    717 		name = "reconfigure";
    718 		break;
    719 	case DH6_INFORM_REQ:
    720 		name= "inf-req";
    721 		break;
    722 	case DH6_RELAY_FORW:
    723 		name= "relay-fwd";
    724 		break;
    725 	case DH6_RELAY_REPLY:
    726 		name= "relay-reply";
    727 		break;
    728 	default:
    729 		name = NULL;
    730 		break;
    731 	}
    732 
    733 	if (!vflag) {
    734 		if (name)
    735 			printf(" %s", name);
    736 		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
    737 		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
    738 			printf(" msgtype-%u", dh6->dh6_msgtype);
    739 		}
    740 		return;
    741 	}
    742 
    743 	/* XXX relay agent messages have to be handled differently */
    744 
    745 	if (name)
    746 		printf(" %s (", name);	/*)*/
    747 	else
    748 		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
    749 	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
    750 	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
    751 		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
    752 		extp = (u_char *)(dh6 + 1);
    753 		dhcp6opt_print(extp, ep);
    754 	} else {		/* relay messages */
    755 		struct in6_addr addr6;
    756 
    757 		TCHECK(dh6relay->dh6relay_peeraddr);
    758 
    759 		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
    760 		printf("linkaddr=%s", ip6addr_string(&addr6));
    761 
    762 		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
    763 		printf(" peeraddr=%s", ip6addr_string(&addr6));
    764 
    765 		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
    766 	}
    767 	/*(*/
    768 	printf(")");
    769 	return;
    770 
    771 trunc:
    772 	printf("[|dhcp6]");
    773 }
    774