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