Merge branch 'vendor/MDOCML'
[dragonfly.git] / contrib / tcpdump / print-dhcp6.c
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.36.2.1 2008-02-06 10:26:27 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 #define DH6_LEASEQUERY  14
84 #define DH6_LQ_REPLY    15
85
86 /* DHCP6 base packet format */
87 struct dhcp6 {
88         union {
89                 u_int8_t m;
90                 u_int32_t x;
91         } dh6_msgtypexid;
92         /* options follow */
93 };
94 #define dh6_msgtype     dh6_msgtypexid.m
95 #define dh6_xid         dh6_msgtypexid.x
96 #define DH6_XIDMASK     0x00ffffff
97
98 /* DHCPv6 relay messages */
99 struct dhcp6_relay {
100         u_int8_t dh6relay_msgtype;
101         u_int8_t dh6relay_hcnt;
102         u_int8_t dh6relay_linkaddr[16]; /* XXX: badly aligned */
103         u_int8_t dh6relay_peeraddr[16];
104         /* options follow */
105 };
106
107 /* options */
108 #define DH6OPT_CLIENTID 1
109 #define DH6OPT_SERVERID 2
110 #define DH6OPT_IA_NA 3
111 #define DH6OPT_IA_TA 4
112 #define DH6OPT_IA_ADDR 5
113 #define DH6OPT_ORO 6
114 #define DH6OPT_PREFERENCE 7
115 #  define DH6OPT_PREF_MAX 255
116 #define DH6OPT_ELAPSED_TIME 8
117 #define DH6OPT_RELAY_MSG 9
118 /*#define DH6OPT_SERVER_MSG 10 deprecated */
119 #define DH6OPT_AUTH 11
120 #  define DH6OPT_AUTHPROTO_DELAYED 2
121 #  define DH6OPT_AUTHPROTO_RECONFIG 3
122 #  define DH6OPT_AUTHALG_HMACMD5 1
123 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
124 #  define DH6OPT_AUTHRECONFIG_KEY 1
125 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
126 #define DH6OPT_UNICAST 12
127 #define DH6OPT_STATUS_CODE 13
128 #  define DH6OPT_STCODE_SUCCESS 0
129 #  define DH6OPT_STCODE_UNSPECFAIL 1
130 #  define DH6OPT_STCODE_NOADDRAVAIL 2
131 #  define DH6OPT_STCODE_NOBINDING 3
132 #  define DH6OPT_STCODE_NOTONLINK 4
133 #  define DH6OPT_STCODE_USEMULTICAST 5
134 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
135 #  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
136 #  define DH6OPT_STCODE_MALFORMEDQUERY 8
137 #  define DH6OPT_STCODE_NOTCONFIGURED 9
138 #  define DH6OPT_STCODE_NOTALLOWED 10
139 #define DH6OPT_RAPID_COMMIT 14
140 #define DH6OPT_USER_CLASS 15
141 #define DH6OPT_VENDOR_CLASS 16
142 #define DH6OPT_VENDOR_OPTS 17
143 #define DH6OPT_INTERFACE_ID 18
144 #define DH6OPT_RECONF_MSG 19
145 #define DH6OPT_RECONF_ACCEPT 20
146 #define DH6OPT_SIP_SERVER_D 21
147 #define DH6OPT_SIP_SERVER_A 22
148 #define DH6OPT_DNS 23
149 #define DH6OPT_DNSNAME 24
150 #define DH6OPT_IA_PD 25
151 #define DH6OPT_IA_PD_PREFIX 26
152 #define DH6OPT_NIS_SERVERS 27
153 #define DH6OPT_NISP_SERVERS 28
154 #define DH6OPT_NIS_NAME 29
155 #define DH6OPT_NISP_NAME 30
156 #define DH6OPT_NTP_SERVERS 31
157 #define DH6OPT_LIFETIME 32
158 #define DH6OPT_BCMCS_SERVER_D 33
159 #define DH6OPT_BCMCS_SERVER_A 34
160 #define DH6OPT_GEOCONF_CIVIC 36
161 #define DH6OPT_REMOTE_ID 37
162 #define DH6OPT_SUBSCRIBER_ID 38
163 #define DH6OPT_CLIENT_FQDN 39
164 #define DH6OPT_PANA_AGENT 40
165 #define DH6OPT_NEW_POSIX_TIMEZONE 41
166 #define DH6OPT_NEW_TZDB_TIMEZONE 42
167 #define DH6OPT_ERO 43
168 #define DH6OPT_LQ_QUERY 44
169 #define DH6OPT_CLIENT_DATA 45
170 #define DH6OPT_CLT_TIME 46
171 #define DH6OPT_LQ_RELAY_DATA 47
172 #define DH6OPT_LQ_CLIENT_LINK 48
173
174 struct dhcp6opt {
175         u_int16_t dh6opt_type;
176         u_int16_t dh6opt_len;
177         /* type-dependent data follows */
178 };
179
180 struct dhcp6_ia {
181         u_int16_t dh6opt_ia_type;
182         u_int16_t dh6opt_ia_len;
183         u_int32_t dh6opt_ia_iaid;
184         u_int32_t dh6opt_ia_t1;
185         u_int32_t dh6opt_ia_t2;
186 };
187
188 struct dhcp6_ia_addr {
189         u_int16_t dh6opt_ia_addr_type;
190         u_int16_t dh6opt_ia_addr_len;
191         struct in6_addr dh6opt_ia_addr_addr;
192         u_int32_t dh6opt_ia_addr_pltime;
193         u_int32_t dh6opt_ia_addr_vltime;
194 }  __attribute__ ((__packed__));
195
196 struct dhcp6_ia_prefix {
197         u_int16_t dh6opt_ia_prefix_type;
198         u_int16_t dh6opt_ia_prefix_len;
199         u_int32_t dh6opt_ia_prefix_pltime;
200         u_int32_t dh6opt_ia_prefix_vltime;
201         u_int8_t dh6opt_ia_prefix_plen;
202         struct in6_addr dh6opt_ia_prefix_addr;
203 }  __attribute__ ((__packed__));
204
205 struct dhcp6_auth {
206         u_int16_t dh6opt_auth_type;
207         u_int16_t dh6opt_auth_len;
208         u_int8_t dh6opt_auth_proto;
209         u_int8_t dh6opt_auth_alg;
210         u_int8_t dh6opt_auth_rdm;
211         u_int8_t dh6opt_auth_rdinfo[8];
212         /* authentication information follows */
213 } __attribute__ ((__packed__));
214
215 static const char *
216 dhcp6opt_name(int type)
217 {
218         static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
219
220         if (type > 65535)
221                 return "INVALID option";
222
223         switch(type) {
224         case DH6OPT_CLIENTID:
225                 return "client ID";
226         case DH6OPT_SERVERID:
227                 return "server ID";
228         case DH6OPT_IA_NA:
229                 return "IA_NA";
230         case DH6OPT_IA_TA:
231                 return "IA_TA";
232         case DH6OPT_IA_ADDR:
233                 return "IA_ADDR";
234         case DH6OPT_ORO:
235                 return "option request";
236         case DH6OPT_PREFERENCE:
237                 return "preference";
238         case DH6OPT_ELAPSED_TIME:
239                 return "elapsed time";
240         case DH6OPT_RELAY_MSG:
241                 return "relay message";
242         case DH6OPT_AUTH:
243                 return "authentication";
244         case DH6OPT_UNICAST:
245                 return "server unicast";
246         case DH6OPT_STATUS_CODE:
247                 return "status code";
248         case DH6OPT_RAPID_COMMIT:
249                 return "rapid commit";
250         case DH6OPT_USER_CLASS:
251                 return "user class";
252         case DH6OPT_VENDOR_CLASS:
253                 return "vendor class";
254         case DH6OPT_VENDOR_OPTS:
255                 return "vendor-specific info";
256         case DH6OPT_INTERFACE_ID:
257                 return "interface ID";
258         case DH6OPT_RECONF_MSG:
259                 return "reconfigure message";
260         case DH6OPT_RECONF_ACCEPT:
261                 return "reconfigure accept";
262         case DH6OPT_SIP_SERVER_D:
263                 return "SIP servers domain";
264         case DH6OPT_SIP_SERVER_A:
265                 return "SIP servers address";
266         case DH6OPT_DNS:
267                 return "DNS";
268         case DH6OPT_DNSNAME:
269                 return "DNS name";
270         case DH6OPT_IA_PD:
271                 return "IA_PD";
272         case DH6OPT_IA_PD_PREFIX:
273                 return "IA_PD prefix";
274         case DH6OPT_NTP_SERVERS:
275                 return "NTP Server";
276         case DH6OPT_LIFETIME:
277                 return "lifetime";
278         case DH6OPT_NIS_SERVERS:
279                 return "NIS server";
280         case DH6OPT_NISP_SERVERS:
281                 return "NIS+ server";
282         case DH6OPT_NIS_NAME:
283                 return "NIS domain name";
284         case DH6OPT_NISP_NAME:
285                 return "NIS+ domain name";
286         case DH6OPT_BCMCS_SERVER_D:
287                 return "BCMCS domain name";
288         case DH6OPT_BCMCS_SERVER_A:
289                 return "BCMCS server";
290         case DH6OPT_GEOCONF_CIVIC:
291                 return "Geoconf Civic";
292         case DH6OPT_REMOTE_ID:
293                 return "Remote ID";
294         case DH6OPT_SUBSCRIBER_ID:
295                 return "Subscriber ID";
296         case DH6OPT_CLIENT_FQDN:
297                 return "Client FQDN";
298         case DH6OPT_PANA_AGENT:
299                 return "PANA agent";
300         case DH6OPT_NEW_POSIX_TIMEZONE:
301                 return "POSIX timezone";
302         case DH6OPT_NEW_TZDB_TIMEZONE:
303                 return "POSIX tz database";
304         case DH6OPT_ERO:
305                 return "Echo request option";
306         case DH6OPT_LQ_QUERY:
307                 return "Lease query";
308         case DH6OPT_CLIENT_DATA:
309                 return "LQ client data";
310         case DH6OPT_CLT_TIME:
311                 return "Clt time";
312         case DH6OPT_LQ_RELAY_DATA:
313                 return "LQ relay data";
314         case DH6OPT_LQ_CLIENT_LINK:
315                 return "LQ client link";
316         default:
317                 snprintf(genstr, sizeof(genstr), "opt_%d", type);
318                 return(genstr);
319         }
320 }
321
322 static const char *
323 dhcp6stcode(int code)
324 {
325         static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
326
327         if (code > 255)
328                 return "INVALID code";
329
330         switch(code) {
331         case DH6OPT_STCODE_SUCCESS:
332                 return "success";
333         case DH6OPT_STCODE_UNSPECFAIL:
334                 return "unspec failure";
335         case DH6OPT_STCODE_NOADDRAVAIL:
336                 return "no addresses";
337         case DH6OPT_STCODE_NOBINDING:
338                 return "no binding";
339         case DH6OPT_STCODE_NOTONLINK:
340                 return "not on-link";
341         case DH6OPT_STCODE_USEMULTICAST:
342                 return "use multicast";
343         case DH6OPT_STCODE_NOPREFIXAVAIL:
344                 return "no prefixes";
345         case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
346                 return "unknown query type";
347         case DH6OPT_STCODE_MALFORMEDQUERY:
348                 return "malformed query";
349         case DH6OPT_STCODE_NOTCONFIGURED:
350                 return "not configured";
351         case DH6OPT_STCODE_NOTALLOWED:
352                 return "not allowed";
353         default:
354                 snprintf(genstr, sizeof(genstr), "code%d", code);
355                 return(genstr);
356         }
357 }
358
359 static void
360 dhcp6opt_print(const u_char *cp, const u_char *ep)
361 {
362         struct dhcp6opt *dh6o;
363         u_char *tp;
364         size_t i;
365         u_int16_t opttype;
366         size_t optlen;
367         u_int16_t val16;
368         u_int32_t val32;
369         struct dhcp6_ia ia;
370         struct dhcp6_ia_prefix ia_prefix;
371         struct dhcp6_ia_addr ia_addr;
372         struct dhcp6_auth authopt;
373         u_int authinfolen, authrealmlen;
374
375         if (cp == ep)
376                 return;
377         while (cp < ep) {
378                 if (ep < cp + sizeof(*dh6o))
379                         goto trunc;
380                 dh6o = (struct dhcp6opt *)cp;
381                 optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
382                 if (ep < cp + sizeof(*dh6o) + optlen)
383                         goto trunc;
384                 opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
385                 printf(" (%s", dhcp6opt_name(opttype));
386                 switch (opttype) {
387                 case DH6OPT_CLIENTID:
388                 case DH6OPT_SERVERID:
389                         if (optlen < 2) {
390                                 /*(*/
391                                 printf(" ?)");
392                                 break;
393                         }
394                         tp = (u_char *)(dh6o + 1);
395                         switch (EXTRACT_16BITS(tp)) {
396                         case 1:
397                                 if (optlen >= 2 + 6) {
398                                         printf(" hwaddr/time type %u time %u ",
399                                             EXTRACT_16BITS(&tp[2]),
400                                             EXTRACT_32BITS(&tp[4]));
401                                         for (i = 8; i < optlen; i++)
402                                                 printf("%02x", tp[i]);
403                                         /*(*/
404                                         printf(")");
405                                 } else {
406                                         /*(*/
407                                         printf(" ?)");
408                                 }
409                                 break;
410                         case 2:
411                                 if (optlen >= 2 + 8) {
412                                         printf(" vid ");
413                                         for (i = 2; i < 2 + 8; i++)
414                                                 printf("%02x", tp[i]);
415                                         /*(*/
416                                         printf(")");
417                                 } else {
418                                         /*(*/
419                                         printf(" ?)");
420                                 }
421                                 break;
422                         case 3:
423                                 if (optlen >= 2 + 2) {
424                                         printf(" hwaddr type %u ",
425                                             EXTRACT_16BITS(&tp[2]));
426                                         for (i = 4; i < optlen; i++)
427                                                 printf("%02x", tp[i]);
428                                         /*(*/
429                                         printf(")");
430                                 } else {
431                                         /*(*/
432                                         printf(" ?)");
433                                 }
434                                 break;
435                         default:
436                                 printf(" type %d)", EXTRACT_16BITS(tp));
437                                 break;
438                         }
439                         break;
440                 case DH6OPT_IA_ADDR:
441                         if (optlen < sizeof(ia_addr) - 4) {
442                                 printf(" ?)");
443                                 break;
444                         }
445                         memcpy(&ia_addr, (u_char *)dh6o, sizeof(ia_addr));
446                         printf(" %s",
447                             ip6addr_string(&ia_addr.dh6opt_ia_addr_addr));
448                         ia_addr.dh6opt_ia_addr_pltime =
449                             ntohl(ia_addr.dh6opt_ia_addr_pltime);
450                         ia_addr.dh6opt_ia_addr_vltime =
451                             ntohl(ia_addr.dh6opt_ia_addr_vltime);
452                         printf(" pltime:%lu vltime:%lu",
453                             (unsigned long)ia_addr.dh6opt_ia_addr_pltime,
454                             (unsigned long)ia_addr.dh6opt_ia_addr_vltime);
455                         if (optlen > sizeof(ia_addr) - 4) {
456                                 /* there are sub-options */
457                                 dhcp6opt_print((u_char *)dh6o +
458                                     sizeof(ia_addr),
459                                     (u_char *)(dh6o + 1) + optlen);
460                         }
461                         printf(")");
462                         break;
463                 case DH6OPT_ORO:
464                 case DH6OPT_ERO:
465                         if (optlen % 2) {
466                                 printf(" ?)");
467                                 break;
468                         }
469                         tp = (u_char *)(dh6o + 1);
470                         for (i = 0; i < optlen; i += 2) {
471                                 u_int16_t opt;
472
473                                 memcpy(&opt, &tp[i], sizeof(opt));
474                                 printf(" %s", dhcp6opt_name(ntohs(opt)));
475                         }
476                         printf(")");
477                         break;
478                 case DH6OPT_PREFERENCE:
479                         if (optlen != 1) {
480                                 printf(" ?)");
481                                 break;
482                         }
483                         printf(" %d)", *((u_char *)(dh6o + 1) + 1));
484                         break;
485                 case DH6OPT_ELAPSED_TIME:
486                         if (optlen != 2) {
487                                 printf(" ?)");
488                                 break;
489                         }
490                         memcpy(&val16, dh6o + 1, sizeof(val16));
491                         val16 = ntohs(val16);
492                         printf(" %d)", (int)val16);
493                         break;
494                 case DH6OPT_RELAY_MSG:
495                         printf(" (");
496                         dhcp6_print((const u_char *)(dh6o + 1), optlen);
497                         printf(")");
498                         break;
499                 case DH6OPT_AUTH:
500                         if (optlen < sizeof(authopt) - sizeof(*dh6o)) {
501                                 printf(" ?)");
502                                 break;
503                         }
504                         memcpy(&authopt, dh6o, sizeof(authopt));
505                         switch (authopt.dh6opt_auth_proto) {
506                         case DH6OPT_AUTHPROTO_DELAYED:
507                                 printf(" proto: delayed");
508                                 break;
509                         case DH6OPT_AUTHPROTO_RECONFIG:
510                                 printf(" proto: reconfigure");
511                                 break;
512                         default:
513                                 printf(" proto: %d",
514                                     authopt.dh6opt_auth_proto);
515                                 break;
516                         }
517                         switch (authopt.dh6opt_auth_alg) {
518                         case DH6OPT_AUTHALG_HMACMD5:
519                                 /* XXX: may depend on the protocol */
520                                 printf(", alg: HMAC-MD5");
521                                 break;
522                         default:
523                                 printf(", alg: %d", authopt.dh6opt_auth_alg);
524                                 break;
525                         }
526                         switch (authopt.dh6opt_auth_rdm) {
527                         case DH6OPT_AUTHRDM_MONOCOUNTER:
528                                 printf(", RDM: mono");
529                                 break;
530                         default:
531                                 printf(", RDM: %d", authopt.dh6opt_auth_rdm);
532                                 break;
533                         }
534                         tp = (u_char *)&authopt.dh6opt_auth_rdinfo;
535                         printf(", RD:");
536                         for (i = 0; i < 4; i++, tp += sizeof(val16))
537                                 printf(" %04x", EXTRACT_16BITS(tp));
538
539                         /* protocol dependent part */
540                         tp = (u_char *)dh6o + sizeof(authopt);
541                         authinfolen =
542                             optlen + sizeof(*dh6o) - sizeof(authopt); 
543                         switch (authopt.dh6opt_auth_proto) {
544                         case DH6OPT_AUTHPROTO_DELAYED:
545                                 if (authinfolen == 0)
546                                         break;
547                                 if (authinfolen < 20) {
548                                         printf(" ??");
549                                         break;
550                                 }
551                                 authrealmlen = authinfolen - 20;
552                                 if (authrealmlen > 0) {
553                                         printf(", realm: ");
554                                 }
555                                 for (i = 0; i < authrealmlen; i++, tp++)
556                                         printf("%02x", *tp);
557                                 printf(", key ID: %08x", EXTRACT_32BITS(tp));
558                                 tp += 4;
559                                 printf(", HMAC-MD5:");
560                                 for (i = 0; i < 4; i++, tp+= 4)
561                                         printf(" %08x", EXTRACT_32BITS(tp));
562                                 break;
563                         case DH6OPT_AUTHPROTO_RECONFIG:
564                                 if (authinfolen != 17) {
565                                         printf(" ??");
566                                         break;
567                                 }
568                                 switch (*tp++) {
569                                 case DH6OPT_AUTHRECONFIG_KEY:
570                                         printf(" reconfig-key");
571                                         break;
572                                 case DH6OPT_AUTHRECONFIG_HMACMD5:
573                                         printf(" type: HMAC-MD5");
574                                         break;
575                                 default:
576                                         printf(" type: ??");
577                                         break;
578                                 }
579                                 printf(" value:");
580                                 for (i = 0; i < 4; i++, tp+= 4)
581                                         printf(" %08x", EXTRACT_32BITS(tp));
582                                 break;
583                         default:
584                                 printf(" ??");
585                                 break;
586                         }
587
588                         printf(")");
589                         break;
590                 case DH6OPT_RAPID_COMMIT: /* nothing todo */
591                         printf(")");
592                         break;
593                 case DH6OPT_INTERFACE_ID:
594                 case DH6OPT_SUBSCRIBER_ID:
595                         /*
596                          * Since we cannot predict the encoding, print hex dump
597                          * at most 10 characters.
598                          */
599                         printf(" ");
600                         for (i = 0; i < optlen && i < 10; i++)
601                                 printf("%02x", ((u_char *)(dh6o + 1))[i]);
602                         printf("...)");
603                         break;
604                 case DH6OPT_RECONF_MSG:
605                         tp = (u_char *)(dh6o + 1);
606                         switch (*tp) {
607                         case DH6_RENEW:
608                                 printf(" for renew)");
609                                 break;
610                         case DH6_INFORM_REQ:
611                                 printf(" for inf-req)");
612                                 break;
613                         default:
614                                 printf(" for ?\?\?(%02x))", *tp);
615                                 break;
616                         }
617                         break;
618                 case DH6OPT_RECONF_ACCEPT: /* nothing todo */
619                         printf(")");
620                         break;
621                 case DH6OPT_SIP_SERVER_A:
622                 case DH6OPT_DNS:
623                 case DH6OPT_NTP_SERVERS:
624                 case DH6OPT_NIS_SERVERS:
625                 case DH6OPT_NISP_SERVERS:
626                 case DH6OPT_BCMCS_SERVER_A:
627                 case DH6OPT_PANA_AGENT:
628                 case DH6OPT_LQ_CLIENT_LINK:
629                         if (optlen % 16) {
630                                 printf(" ?)");
631                                 break;
632                         }
633                         tp = (u_char *)(dh6o + 1);
634                         for (i = 0; i < optlen; i += 16)
635                                 printf(" %s", ip6addr_string(&tp[i]));
636                         printf(")");
637                         break;
638                 case DH6OPT_STATUS_CODE:
639                         if (optlen < 2) {
640                                 printf(" ?)");
641                                 break;
642                         }
643                         memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
644                         val16 = ntohs(val16);
645                         printf(" %s)", dhcp6stcode(val16));
646                         break;
647                 case DH6OPT_IA_NA:
648                 case DH6OPT_IA_PD:
649                         if (optlen < sizeof(ia) - 4) {
650                                 printf(" ?)");
651                                 break;
652                         }
653                         memcpy(&ia, (u_char *)dh6o, sizeof(ia));
654                         ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
655                         ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
656                         ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
657                         printf(" IAID:%lu T1:%lu T2:%lu",
658                             (unsigned long)ia.dh6opt_ia_iaid,
659                             (unsigned long)ia.dh6opt_ia_t1,
660                             (unsigned long)ia.dh6opt_ia_t2);
661                         if (optlen > sizeof(ia) - 4) {
662                                 /* there are sub-options */
663                                 dhcp6opt_print((u_char *)dh6o + sizeof(ia),
664                                     (u_char *)(dh6o + 1) + optlen);
665                         }
666                         printf(")");
667                         break;
668                 case DH6OPT_IA_TA:
669                         if (optlen < 4) {
670                                 printf(" ?)");
671                                 break;
672                         }
673                         memcpy(&val32, dh6o + 1, sizeof(val32));
674                         val32 = ntohl(val32);
675                         printf(" IAID:%lu", (unsigned long)val32);
676                         if (optlen > 4) {
677                                 /* there are sub-options */
678                                 dhcp6opt_print((u_char *)(dh6o + 1) + 4,
679                                     (u_char *)(dh6o + 1) + optlen);
680                         }
681                         printf(")");
682                         break;
683                 case DH6OPT_IA_PD_PREFIX:
684                         if (optlen < sizeof(ia_prefix) - 4) {
685                                 printf(" ?)");
686                                 break;
687                         }
688                         memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
689                         printf(" %s/%d",
690                             ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
691                             ia_prefix.dh6opt_ia_prefix_plen);
692                         ia_prefix.dh6opt_ia_prefix_pltime =
693                             ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
694                         ia_prefix.dh6opt_ia_prefix_vltime =
695                             ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
696                         printf(" pltime:%lu vltime:%lu",
697                             (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
698                             (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
699                         if (optlen > sizeof(ia_prefix) - 4) {
700                                 /* there are sub-options */
701                                 dhcp6opt_print((u_char *)dh6o +
702                                     sizeof(ia_prefix),
703                                     (u_char *)(dh6o + 1) + optlen);
704                         }
705                         printf(")");
706                         break;
707                 case DH6OPT_LIFETIME:
708                 case DH6OPT_CLT_TIME:
709                         if (optlen != 4) {
710                                 printf(" ?)");
711                                 break;
712                         }
713                         memcpy(&val32, dh6o + 1, sizeof(val32));
714                         val32 = ntohl(val32);
715                         printf(" %d)", (int)val32);
716                         break;
717                 case DH6OPT_REMOTE_ID:
718                         if (optlen < 4) {
719                                 printf(" ?)");
720                                 break;
721                         }
722                         tp = (u_char *)(dh6o + 1);
723                         memcpy(&val32, &tp[0], sizeof(val32));
724                         val32 = ntohl(val32);
725                         printf(" %d ", (int)val32);
726                         /*
727                          * Print hex dump first 10 characters.
728                          */
729                         for (i = 4; i < optlen && i < 14; i++)
730                                 printf("%02x", tp[i]);
731                         printf("...)");
732                         break;
733                 case DH6OPT_LQ_QUERY:
734                         if (optlen < 17) {
735                                 printf(" ?)");
736                                 break;
737                         }
738                         tp = (u_char *)(dh6o + 1);
739                         switch (*tp) {
740                         case 1:
741                                 printf(" by-address");
742                                 break;
743                         case 2:
744                                 printf(" by-clientID");
745                                 break;
746                         default:
747                                 printf(" type_%d", (int)*tp);
748                                 break;
749                         }
750                         printf(" %s", ip6addr_string(&tp[1]));
751                         if (optlen > 17) {
752                                 /* there are query-options */
753                                 dhcp6opt_print(tp + 17, tp + optlen);
754                         }
755                         printf(")");
756                         break;
757                 case DH6OPT_CLIENT_DATA:
758                         if (optlen > 0) {
759                                 /* there are encapsulated options */
760                                 dhcp6opt_print((u_char *)(dh6o + 1),
761                                     (u_char *)(dh6o + 1) + optlen);
762                         }
763                         printf(")");
764                         break;
765                 case DH6OPT_LQ_RELAY_DATA:
766                         if (optlen < 16) {
767                                 printf(" ?)");
768                                 break;
769                         }
770                         tp = (u_char *)(dh6o + 1);
771                         printf(" %s ", ip6addr_string(&tp[0]));
772                         /*
773                          * Print hex dump first 10 characters.
774                          */
775                         for (i = 16; i < optlen && i < 26; i++)
776                                 printf("%02x", tp[i]);
777                         printf("...)");
778                         break;
779                 default:
780                         printf(")");
781                         break;
782                 }
783
784                 cp += sizeof(*dh6o) + optlen;
785         }
786         return;
787
788 trunc:
789         printf("[|dhcp6ext]");
790 }
791
792 /*
793  * Print dhcp6 packets
794  */
795 void
796 dhcp6_print(const u_char *cp, u_int length)
797 {
798         struct dhcp6 *dh6;
799         struct dhcp6_relay *dh6relay;
800         const u_char *ep;
801         u_char *extp;
802         const char *name;
803
804         printf("dhcp6");
805
806         ep = (u_char *)snapend;
807         if (cp + length < ep)
808                 ep = cp + length;
809
810         dh6 = (struct dhcp6 *)cp;
811         dh6relay = (struct dhcp6_relay *)cp;
812         TCHECK(dh6->dh6_xid);
813         switch (dh6->dh6_msgtype) {
814         case DH6_SOLICIT:
815                 name = "solicit";
816                 break;
817         case DH6_ADVERTISE:
818                 name = "advertise";
819                 break;
820         case DH6_REQUEST:
821                 name = "request";
822                 break;
823         case DH6_CONFIRM:
824                 name = "confirm";
825                 break;
826         case DH6_RENEW:
827                 name = "renew";
828                 break;
829         case DH6_REBIND:
830                 name = "rebind";
831                 break;
832         case DH6_REPLY:
833                 name = "reply";
834                 break;
835         case DH6_RELEASE:
836                 name = "release";
837                 break;
838         case DH6_DECLINE:
839                 name = "decline";
840                 break;
841         case DH6_RECONFIGURE:
842                 name = "reconfigure";
843                 break;
844         case DH6_INFORM_REQ:
845                 name= "inf-req";
846                 break;
847         case DH6_RELAY_FORW:
848                 name= "relay-fwd";
849                 break;
850         case DH6_RELAY_REPLY:
851                 name= "relay-reply";
852                 break;
853         case DH6_LEASEQUERY:
854                 name= "leasequery";
855                 break;
856         case DH6_LQ_REPLY:
857                 name= "leasequery-reply";
858                 break;
859         default:
860                 name = NULL;
861                 break;
862         }
863
864         if (!vflag) {
865                 if (name)
866                         printf(" %s", name);
867                 else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
868                     dh6->dh6_msgtype != DH6_RELAY_REPLY) {
869                         printf(" msgtype-%u", dh6->dh6_msgtype);
870                 }
871                 return;
872         }
873
874         /* XXX relay agent messages have to be handled differently */
875
876         if (name)
877                 printf(" %s (", name);  /*)*/
878         else
879                 printf(" msgtype-%u (", dh6->dh6_msgtype);      /*)*/
880         if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
881             dh6->dh6_msgtype != DH6_RELAY_REPLY) {
882                 printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
883                 extp = (u_char *)(dh6 + 1);
884                 dhcp6opt_print(extp, ep);
885         } else {                /* relay messages */
886                 struct in6_addr addr6;
887
888                 TCHECK(dh6relay->dh6relay_peeraddr);
889
890                 memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
891                 printf("linkaddr=%s", ip6addr_string(&addr6));
892
893                 memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
894                 printf(" peeraddr=%s", ip6addr_string(&addr6));
895
896                 dhcp6opt_print((u_char *)(dh6relay + 1), ep);
897         }
898         /*(*/
899         printf(")");
900         return;
901
902 trunc:
903         printf("[|dhcp6]");
904 }