9f4999d70f622dbe50f9551f744fbab0e85d1b42
[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  *  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 }