Add the RFC 3203 FORCERENEW message type, as suggested by Suresh K.
[obnox/wireshark/wip.git] / packet-ipv6.c
1 /* packet-ipv6.c
2  * Routines for IPv6 packet disassembly
3  *
4  * $Id: packet-ipv6.c,v 1.93 2003/02/04 20:16:57 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * MobileIPv6 support added by Tomislav Borosa <tomislav.borosa@siemens.hr>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <stdio.h>
33 #include <glib.h>
34 #include <epan/packet.h>
35 #include "packet-ip.h"
36 #include "packet-ipsec.h"
37 #include "packet-ipv6.h"
38 #include <epan/resolv.h>
39 #include "prefs.h"
40 #include "reassemble.h"
41 #include "ipproto.h"
42 #include "etypes.h"
43 #include "ppptypes.h"
44 #include "aftypes.h"
45 #include "nlpid.h"
46 #include "arcnet_pids.h"
47
48 /*
49  * NOTE: ipv6.nxt is not very useful as we will have chained header.
50  * now testing ipv6.final, but it raises SEGV.
51 #define TEST_FINALHDR
52  */
53
54 static int proto_ipv6 = -1;
55 static int hf_ipv6_version = -1;
56 static int hf_ipv6_class = -1;
57 static int hf_ipv6_flow = -1;
58 static int hf_ipv6_plen = -1;
59 static int hf_ipv6_nxt = -1;
60 static int hf_ipv6_hlim = -1;
61 static int hf_ipv6_src = -1;
62 static int hf_ipv6_dst = -1;
63 static int hf_ipv6_addr = -1;
64 #ifdef TEST_FINALHDR
65 static int hf_ipv6_final = -1;
66 #endif
67 static int hf_ipv6_fragments = -1;
68 static int hf_ipv6_fragment = -1;
69 static int hf_ipv6_fragment_overlap = -1;
70 static int hf_ipv6_fragment_overlap_conflict = -1;
71 static int hf_ipv6_fragment_multiple_tails = -1;
72 static int hf_ipv6_fragment_too_long_fragment = -1;
73 static int hf_ipv6_fragment_error = -1;
74
75 static int hf_ipv6_mipv6_type = -1;
76 static int hf_ipv6_mipv6_length = -1;
77 static int hf_ipv6_mipv6_home_address = -1;
78
79 static gint ett_ipv6 = -1;
80 static gint ett_ipv6_fragments = -1;
81 static gint ett_ipv6_fragment  = -1;
82
83 static const fragment_items ipv6_frag_items = {
84         &ett_ipv6_fragment,
85         &ett_ipv6_fragments,
86         &hf_ipv6_fragments,
87         &hf_ipv6_fragment,
88         &hf_ipv6_fragment_overlap,
89         &hf_ipv6_fragment_overlap_conflict,
90         &hf_ipv6_fragment_multiple_tails,
91         &hf_ipv6_fragment_too_long_fragment,
92         &hf_ipv6_fragment_error,
93         "fragments"
94 };
95
96 static dissector_handle_t data_handle;
97
98 /* Reassemble fragmented datagrams */
99 static gboolean ipv6_reassemble = FALSE;
100
101 #ifndef offsetof
102 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
103 #endif
104
105 /*
106  * defragmentation of IPv6
107  */
108 static GHashTable *ipv6_fragment_table = NULL;
109
110 void
111 capture_ipv6(const guchar *pd, int offset, int len, packet_counts *ld)
112 {
113   guint8 nxt;
114   int advance;
115
116   if (!BYTES_ARE_IN_FRAME(offset, len, 4+4+16+16)) {
117     ld->other++;
118     return;
119   }
120   nxt = pd[offset+6];           /* get the "next header" value */
121   offset += 4+4+16+16;          /* skip past the IPv6 header */
122   len -= 4+4+16+16;
123
124 again:
125    switch (nxt) {
126    case IP_PROTO_HOPOPTS:
127    case IP_PROTO_ROUTING:
128    case IP_PROTO_DSTOPTS:
129      if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
130        ld->other++;
131        return;
132      }
133      nxt = pd[offset];
134      advance = (pd[offset+1] + 1) << 3;
135      if (!BYTES_ARE_IN_FRAME(offset, len, advance)) {
136        ld->other++;
137        return;
138      }
139      offset += advance;
140      len -= advance;
141      goto again;
142    case IP_PROTO_FRAGMENT:
143      if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
144        ld->other++;
145        return;
146      }
147      nxt = pd[offset];
148      advance = 8;
149      if (!BYTES_ARE_IN_FRAME(offset, len, advance)) {
150        ld->other++;
151        return;
152      }
153      offset += advance;
154      len -= advance;
155      goto again;
156    case IP_PROTO_AH:
157      if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
158        ld->other++;
159        return;
160      }
161      nxt = pd[offset];
162      advance = 8 + ((pd[offset+1] - 1) << 2);
163      if (!BYTES_ARE_IN_FRAME(offset, len, advance)) {
164        ld->other++;
165        return;
166      }
167      offset += advance;
168      len -= advance;
169      goto again;
170    }
171
172   switch(nxt) {
173     case IP_PROTO_SCTP:
174       ld->sctp++;
175       break;
176     case IP_PROTO_TCP:
177       ld->tcp++;
178       break;
179     case IP_PROTO_UDP:
180       ld->udp++;
181       break;
182     case IP_PROTO_ICMP:
183     case IP_PROTO_ICMPV6:       /* XXX - separate counters? */
184       ld->icmp++;
185       break;
186     case IP_PROTO_OSPF:
187       ld->ospf++;
188       break;
189     case IP_PROTO_GRE:
190       ld->gre++;
191       break;
192     case IP_PROTO_VINES:
193       ld->vines++;
194       break;
195     default:
196       ld->other++;
197   }
198 }
199
200 static void
201 ipv6_reassemble_init(void)
202 {
203   fragment_table_init(&ipv6_fragment_table);
204 }
205
206 static int
207 dissect_routing6(tvbuff_t *tvb, int offset, proto_tree *tree) {
208     struct ip6_rthdr rt;
209     guint len;
210     proto_tree *rthdr_tree;
211         proto_item *ti;
212     char buf[sizeof(struct ip6_rthdr0) + sizeof(struct e_in6_addr) * 23];
213
214     tvb_memcpy(tvb, (guint8 *)&rt, offset, sizeof(rt));
215     len = (rt.ip6r_len + 1) << 3;
216
217     if (tree) {
218         /* !!! specify length */
219         ti = proto_tree_add_text(tree, tvb, offset, len,
220             "Routing Header, Type %u", rt.ip6r_type);
221         rthdr_tree = proto_item_add_subtree(ti, ett_ipv6);
222
223         proto_tree_add_text(rthdr_tree, tvb,
224             offset + offsetof(struct ip6_rthdr, ip6r_nxt), 1,
225             "Next header: %s (0x%02x)", ipprotostr(rt.ip6r_nxt), rt.ip6r_nxt);
226         proto_tree_add_text(rthdr_tree, tvb,
227             offset + offsetof(struct ip6_rthdr, ip6r_len), 1,
228             "Length: %u (%d bytes)", rt.ip6r_len, len);
229         proto_tree_add_text(rthdr_tree, tvb,
230             offset + offsetof(struct ip6_rthdr, ip6r_type), 1,
231             "Type: %u", rt.ip6r_type);
232         proto_tree_add_text(rthdr_tree, tvb,
233             offset + offsetof(struct ip6_rthdr, ip6r_segleft), 1,
234             "Segments left: %u", rt.ip6r_segleft);
235
236         if (rt.ip6r_type == 0 && len <= sizeof(buf)) {
237             struct e_in6_addr *a;
238             int n;
239             struct ip6_rthdr0 *rt0;
240
241             tvb_memcpy(tvb, buf, offset, len);
242             rt0 = (struct ip6_rthdr0 *)buf;
243             for (a = rt0->ip6r0_addr, n = 0;
244                  a < (struct e_in6_addr *)(buf + len);
245                  a++, n++) {
246                 proto_tree_add_text(rthdr_tree, tvb,
247                     offset + offsetof(struct ip6_rthdr0, ip6r0_addr) + n * sizeof(struct e_in6_addr),
248                     sizeof(struct e_in6_addr),
249 #ifdef INET6
250                     "address %d: %s (%s)",
251                     n, get_hostname6(a), ip6_to_str(a)
252 #else
253                     "address %d: %s", n, ip6_to_str(a)
254 #endif
255                     );
256             }
257         }
258         if (rt.ip6r_type == 2) {
259             proto_tree_add_ipv6(rthdr_tree, hf_ipv6_mipv6_home_address,
260                                        tvb, offset + 8, 16,
261                                        tvb_get_ptr(tvb, offset + 8, 16));
262         }
263     }
264
265     return len;
266 }
267
268 static int
269 dissect_frag6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,
270     guint16 *offlg, guint32 *ident) {
271     struct ip6_frag frag;
272     int len;
273     proto_item *ti;
274     proto_tree *rthdr_tree;
275
276     tvb_memcpy(tvb, (guint8 *)&frag, offset, sizeof(frag));
277     len = sizeof(frag);
278     frag.ip6f_offlg = g_ntohs(frag.ip6f_offlg);
279     *offlg = frag.ip6f_offlg;
280     *ident = frag.ip6f_ident;
281     if (check_col(pinfo->cinfo, COL_INFO)) {
282         col_add_fstr(pinfo->cinfo, COL_INFO,
283             "IPv6 fragment (nxt=%s (0x%02x) off=%u id=0x%x)",
284             ipprotostr(frag.ip6f_nxt), frag.ip6f_nxt,
285             frag.ip6f_offlg & IP6F_OFF_MASK, frag.ip6f_ident);
286     }
287     if (tree) {
288            ti = proto_tree_add_text(tree, tvb, offset, len,
289                            "Fragmentation Header");
290            rthdr_tree = proto_item_add_subtree(ti, ett_ipv6);
291
292            proto_tree_add_text(rthdr_tree, tvb,
293                          offset + offsetof(struct ip6_frag, ip6f_nxt), 1,
294                          "Next header: %s (0x%02x)",
295                          ipprotostr(frag.ip6f_nxt), frag.ip6f_nxt);
296
297 #if 0
298            proto_tree_add_text(rthdr_tree, tvb,
299                          offset + offsetof(struct ip6_frag, ip6f_reserved), 1,
300                          "Reserved: %u",
301                          frag.ip6f_reserved);
302 #endif
303
304            proto_tree_add_text(rthdr_tree, tvb,
305                          offset + offsetof(struct ip6_frag, ip6f_offlg), 2,
306                          "Offset: %u",
307                          frag.ip6f_offlg & IP6F_OFF_MASK);
308
309            proto_tree_add_text(rthdr_tree, tvb,
310                          offset + offsetof(struct ip6_frag, ip6f_offlg), 2,
311                          "More fragments: %s",
312                                 frag.ip6f_offlg & IP6F_MORE_FRAG ?
313                                 "Yes" : "No");
314
315            proto_tree_add_text(rthdr_tree, tvb,
316                          offset + offsetof(struct ip6_frag, ip6f_ident), 4,
317                          "Identification: 0x%08x",
318                          frag.ip6f_ident);
319     }
320     return len;
321 }
322
323 static int
324 dissect_mipv6_hoa(tvbuff_t *tvb, proto_tree *dstopt_tree, int offset)
325 {
326     int len = 0;
327
328     proto_tree_add_uint_format(dstopt_tree, hf_ipv6_mipv6_type, tvb,
329         offset + len, 1,
330         tvb_get_guint8(tvb, offset + len),
331         "Option Type: %u (0x%02x) - Home Address Option",
332         tvb_get_guint8(tvb, offset + len),
333         tvb_get_guint8(tvb, offset + len));
334     len += 1;
335
336     proto_tree_add_uint(dstopt_tree, hf_ipv6_mipv6_length, tvb, offset + len,
337         1, tvb_get_guint8(tvb, offset + len));
338     len += 1;
339
340     proto_tree_add_ipv6(dstopt_tree, hf_ipv6_mipv6_home_address, tvb,
341         offset + len, 16, tvb_get_ptr(tvb, offset + len, 16));
342     len += 16;
343     return len;
344 }
345
346 static const value_string rtalertvals[] = {
347     { IP6OPT_RTALERT_MLD, "MLD" },
348     { IP6OPT_RTALERT_RSVP, "RSVP" },
349     { 0, NULL },
350 };
351
352 static int
353 dissect_opts(tvbuff_t *tvb, int offset, proto_tree *tree, char *optname)
354 {
355     struct ip6_ext ext;
356     int len;
357     proto_tree *dstopt_tree;
358     proto_item *ti;
359     gint p;
360     guint8 tmp;
361     int mip_offset = 0, delta = 0;
362
363     tvb_memcpy(tvb, (guint8 *)&ext, offset, sizeof(ext));
364     len = (ext.ip6e_len + 1) << 3;
365
366     if (tree) {
367         /* !!! specify length */
368         ti = proto_tree_add_text(tree, tvb, offset, len, "%s Header ", optname);
369
370         dstopt_tree = proto_item_add_subtree(ti, ett_ipv6);
371
372         proto_tree_add_text(dstopt_tree, tvb,
373             offset + offsetof(struct ip6_ext, ip6e_nxt), 1,
374             "Next header: %s (0x%02x)", ipprotostr(ext.ip6e_nxt), ext.ip6e_nxt);
375         proto_tree_add_text(dstopt_tree, tvb,
376             offset + offsetof(struct ip6_ext, ip6e_len), 1,
377             "Length: %u (%d bytes)", ext.ip6e_len, len);
378
379         mip_offset = offset;
380         mip_offset += 2;
381
382         p = offset + 2;
383
384         while (p < offset + len) {
385             switch (tvb_get_guint8(tvb, p)) {
386             case IP6OPT_PAD1:
387                 proto_tree_add_text(dstopt_tree, tvb, p, 1, "Pad1");
388                 p++;
389                 mip_offset++;
390                 break;
391             case IP6OPT_PADN:
392                 tmp = tvb_get_guint8(tvb, p + 1);
393                 proto_tree_add_text(dstopt_tree, tvb, p, tmp + 2,
394                     "PadN: %u bytes", tmp + 2);
395                 p += tmp;
396                 p += 2;
397                 mip_offset += tvb_get_guint8(tvb, mip_offset + 1) + 2;
398                 break;
399             case IP6OPT_JUMBO:
400                 tmp = tvb_get_guint8(tvb, p + 1);
401                 if (tmp == 4) {
402                     proto_tree_add_text(dstopt_tree, tvb, p, tmp + 2,
403                         "Jumbo payload: %u (%u bytes)",
404                         tvb_get_ntohl(tvb, p + 2), tmp + 2);
405                 } else {
406                     proto_tree_add_text(dstopt_tree, tvb, p, tmp + 2,
407                         "Jumbo payload: Invalid length (%u bytes)",
408                         tmp + 2);
409                 }
410                 p += tmp;
411                 p += 2;
412                 mip_offset += tvb_get_guint8(tvb, mip_offset+1)+2;
413                 break;
414             case IP6OPT_RTALERT:
415               {
416                 char *rta;
417
418                 tmp = tvb_get_guint8(tvb, p + 1);
419                 if (tmp == 2) {
420                     rta = val_to_str(tvb_get_ntohs(tvb, p + 2), rtalertvals,
421                         "Unknown");
422                 } else
423                     rta = "Invalid length";
424                 ti = proto_tree_add_text(dstopt_tree, tvb, p , tmp + 2,
425                     "Router alert: %s (%u bytes)", rta, tmp + 2);
426                 p += tmp;
427                 p += 2;
428                 mip_offset += tvb_get_guint8(tvb, mip_offset + 1) + 2;
429                 break;
430               }
431             case IP6OPT_HOME_ADDRESS:
432                 delta = dissect_mipv6_hoa(tvb, dstopt_tree, mip_offset);
433                 p += delta;
434                 mip_offset += delta;
435                 break;
436             default:
437                 p = offset + len;
438                 break;
439             }
440         }
441
442         /* decode... */
443     }
444     return len;
445 }
446
447 static int
448 dissect_hopopts(tvbuff_t *tvb, int offset, proto_tree *tree)
449 {
450     return dissect_opts(tvb, offset, tree, "Hop-by-hop Option");
451 }
452
453 static int
454 dissect_dstopts(tvbuff_t *tvb, int offset, proto_tree *tree)
455 {
456     return dissect_opts(tvb, offset, tree, "Destination Option");
457 }
458
459 static void
460 dissect_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
461 {
462   proto_tree *ipv6_tree = NULL;
463   proto_item *ti;
464   guint8 nxt;
465   int advance;
466   int poffset;
467   guint16 plen;
468   gboolean hopopts, routing, frag, ah, dstopts;
469   guint16 offlg;
470   guint32 ident;
471   int offset;
472   fragment_data *ipfd_head;
473   tvbuff_t   *next_tvb;
474   gboolean update_col_info = TRUE;
475   gboolean save_fragmented;
476
477   struct ip6_hdr ipv6;
478
479   if (check_col(pinfo->cinfo, COL_PROTOCOL))
480     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPv6");
481   if (check_col(pinfo->cinfo, COL_INFO))
482     col_clear(pinfo->cinfo, COL_INFO);
483
484   offset = 0;
485   tvb_memcpy(tvb, (guint8 *)&ipv6, offset, sizeof(ipv6));
486
487   pinfo->ipproto = ipv6.ip6_nxt; /* XXX make work TCP follow (ipproto = 6) */
488
489   /* Get the payload length */
490   plen = g_ntohs(ipv6.ip6_plen);
491
492   /* Adjust the length of this tvbuff to include only the IPv6 datagram. */
493   set_actual_length(tvb, plen + sizeof (struct ip6_hdr));
494
495   SET_ADDRESS(&pinfo->net_src, AT_IPv6, 16, tvb_get_ptr(tvb, offset + IP6H_SRC, 16));
496   SET_ADDRESS(&pinfo->src, AT_IPv6, 16, tvb_get_ptr(tvb, offset + IP6H_SRC, 16));
497   SET_ADDRESS(&pinfo->net_dst, AT_IPv6, 16, tvb_get_ptr(tvb, offset + IP6H_DST, 16));
498   SET_ADDRESS(&pinfo->dst, AT_IPv6, 16, tvb_get_ptr(tvb, offset + IP6H_DST, 16));
499
500   if (tree) {
501     /* !!! specify length */
502     ti = proto_tree_add_item(tree, proto_ipv6, tvb, offset, 40, FALSE);
503     ipv6_tree = proto_item_add_subtree(ti, ett_ipv6);
504
505     /* !!! warning: version also contains 4 Bit priority */
506     proto_tree_add_uint(ipv6_tree, hf_ipv6_version, tvb,
507                 offset + offsetof(struct ip6_hdr, ip6_vfc), 1,
508                 (ipv6.ip6_vfc >> 4) & 0x0f);
509
510     proto_tree_add_uint(ipv6_tree, hf_ipv6_class, tvb,
511                 offset + offsetof(struct ip6_hdr, ip6_flow), 4,
512                 (guint8)((g_ntohl(ipv6.ip6_flow) >> 20) & 0xff));
513
514     /*
515      * there should be no alignment problems for ip6_flow, since it's the first
516      * guint32 in the ipv6 struct
517      */
518     proto_tree_add_uint_format(ipv6_tree, hf_ipv6_flow, tvb,
519                 offset + offsetof(struct ip6_hdr, ip6_flow), 4,
520                 (unsigned long)(g_ntohl(ipv6.ip6_flow) & IPV6_FLOWLABEL_MASK),
521                 "Flowlabel: 0x%05lx",
522                 (unsigned long)(g_ntohl(ipv6.ip6_flow) & IPV6_FLOWLABEL_MASK));
523
524     proto_tree_add_uint(ipv6_tree, hf_ipv6_plen, tvb,
525                 offset + offsetof(struct ip6_hdr, ip6_plen), 2,
526                 plen);
527
528     proto_tree_add_uint_format(ipv6_tree, hf_ipv6_nxt, tvb,
529                 offset + offsetof(struct ip6_hdr, ip6_nxt), 1,
530                 ipv6.ip6_nxt,
531                 "Next header: %s (0x%02x)",
532                 ipprotostr(ipv6.ip6_nxt), ipv6.ip6_nxt);
533
534     proto_tree_add_uint(ipv6_tree, hf_ipv6_hlim, tvb,
535                 offset + offsetof(struct ip6_hdr, ip6_hlim), 1,
536                 ipv6.ip6_hlim);
537
538     proto_tree_add_ipv6_hidden(ipv6_tree, hf_ipv6_addr, tvb,
539                                offset + offsetof(struct ip6_hdr, ip6_src), 16,
540                                ipv6.ip6_src.s6_addr8);
541     proto_tree_add_ipv6_hidden(ipv6_tree, hf_ipv6_addr, tvb,
542                                offset + offsetof(struct ip6_hdr, ip6_dst), 16,
543                                ipv6.ip6_dst.s6_addr8);
544
545     proto_tree_add_ipv6_format(ipv6_tree, hf_ipv6_src, tvb,
546                 offset + offsetof(struct ip6_hdr, ip6_src), 16,
547                 (guint8 *)&ipv6.ip6_src,
548 #ifdef INET6
549                 "Source address: %s (%s)",
550                 get_hostname6(&ipv6.ip6_src),
551 #else
552                 "Source address: %s",
553 #endif
554                 ip6_to_str(&ipv6.ip6_src));
555
556     proto_tree_add_ipv6_format(ipv6_tree, hf_ipv6_dst, tvb,
557                 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
558                 (guint8 *)&ipv6.ip6_dst,
559 #ifdef INET6
560                 "Destination address: %s (%s)",
561                 get_hostname6(&ipv6.ip6_dst),
562 #else
563                 "Destination address: %s",
564 #endif
565                 ip6_to_str(&ipv6.ip6_dst));
566   }
567
568   /* start of the new header (could be a extension header) */
569   poffset = offset + offsetof(struct ip6_hdr, ip6_nxt);
570   nxt = tvb_get_guint8(tvb, poffset);
571   offset += sizeof(struct ip6_hdr);
572   offlg = 0;
573   ident = 0;
574
575 /* start out assuming this isn't fragmented, and has none of the other
576    non-final headers */
577   hopopts = FALSE;
578   routing = FALSE;
579   frag = FALSE;
580   ah = FALSE;
581   dstopts = FALSE;
582
583 again:
584    switch (nxt) {
585    case IP_PROTO_HOPOPTS:
586                         hopopts = TRUE;
587                         advance = dissect_hopopts(tvb, offset, tree);
588                         nxt = tvb_get_guint8(tvb, offset);
589                         poffset = offset;
590                         offset += advance;
591                         plen -= advance;
592                         goto again;
593     case IP_PROTO_ROUTING:
594                         routing = TRUE;
595                         advance = dissect_routing6(tvb, offset, tree);
596                         nxt = tvb_get_guint8(tvb, offset);
597                         poffset = offset;
598                         offset += advance;
599                         plen -= advance;
600                         goto again;
601     case IP_PROTO_FRAGMENT:
602                         frag = TRUE;
603                         advance = dissect_frag6(tvb, offset, pinfo, tree,
604                             &offlg, &ident);
605                         nxt = tvb_get_guint8(tvb, offset);
606                         poffset = offset;
607                         offset += advance;
608                         plen -= advance;
609                         goto again;
610     case IP_PROTO_AH:
611                         ah = TRUE;
612                         advance = dissect_ah_header(
613                                   tvb_new_subset(tvb, offset, -1, -1),
614                                   pinfo, tree, NULL, NULL);
615                         nxt = tvb_get_guint8(tvb, offset);
616                         poffset = offset;
617                         offset += advance;
618                         plen -= advance;
619                         goto again;
620     case IP_PROTO_DSTOPTS:
621                         dstopts = TRUE;
622                         advance = dissect_dstopts(tvb, offset, tree);
623                         nxt = tvb_get_guint8(tvb, offset);
624                         poffset = offset;
625                         offset += advance;
626                         plen -= advance;
627                         goto again;
628     }
629
630 #ifdef TEST_FINALHDR
631   proto_tree_add_uint_hidden(ipv6_tree, hf_ipv6_final, tvb, poffset, 1, nxt);
632 #endif
633
634   /* If ipv6_reassemble is on, this is a fragment, and we have all the data
635    * in the fragment, then just add the fragment to the hashtable.
636    */
637   save_fragmented = pinfo->fragmented;
638   if (ipv6_reassemble && frag && tvb_reported_length(tvb) <= tvb_length(tvb)) {
639     ipfd_head = fragment_add(tvb, offset, pinfo, ident,
640                              ipv6_fragment_table,
641                              offlg & IP6F_OFF_MASK,
642                              plen,
643                              offlg & IP6F_MORE_FRAG);
644
645     if (ipfd_head != NULL) {
646       /* OK, we have the complete reassembled payload.
647          Allocate a new tvbuff, referring to the reassembled payload. */
648       next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen,
649         ipfd_head->datalen);
650
651       /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
652          were handed refers, so it'll get cleaned up when that tvbuff
653          is cleaned up. */
654       tvb_set_child_real_data_tvbuff(tvb, next_tvb);
655
656       /* Add the defragmented data to the data source list. */
657       add_new_data_source(pinfo, next_tvb, "Reassembled IPv6");
658
659       /* show all fragments */
660       update_col_info = !show_fragment_tree(ipfd_head, &ipv6_frag_items,
661         ipv6_tree, pinfo, next_tvb);
662     } else {
663       /* We don't have the complete reassembled payload. */
664       next_tvb = NULL;
665     }
666   } else {
667     /* If this is the first fragment, dissect its contents, otherwise
668        just show it as a fragment.
669
670        XXX - if we eventually don't save the reassembled contents of all
671        fragmented datagrams, we may want to always reassemble. */
672     if (offlg & IP6F_OFF_MASK) {
673       /* Not the first fragment - don't dissect it. */
674       next_tvb = NULL;
675     } else {
676       /* First fragment, or not fragmented.  Dissect what we have here. */
677
678       /* Get a tvbuff for the payload. */
679       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
680
681       /*
682        * If this is the first fragment, but not the only fragment,
683        * tell the next protocol that.
684        */
685       if (offlg & IP6F_MORE_FRAG)
686         pinfo->fragmented = TRUE;
687       else
688         pinfo->fragmented = FALSE;
689     }
690   }
691
692   if (next_tvb == NULL) {
693     /* Just show this as a fragment. */
694     /* COL_INFO was filled in by "dissect_frag6()" */
695     call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
696
697     /* As we haven't reassembled anything, we haven't changed "pi", so
698        we don't have to restore it. */
699     pinfo->fragmented = save_fragmented;
700     return;
701   }
702
703   /* do lookup with the subdissector table */
704   if (!dissector_try_port(ip_dissector_table, nxt, next_tvb, pinfo, tree)) {
705     /* Unknown protocol.
706        Handle "no next header" specially. */
707     if (nxt == IP_PROTO_NONE) {
708       if (check_col(pinfo->cinfo, COL_INFO)) {
709         /* If we had an Authentication Header, the AH dissector already
710            put something in the Info column; leave it there. */
711         if (!ah) {
712           if (hopopts || routing || dstopts) {
713             char *sep = "IPv6 ";
714             if (hopopts) {
715               col_append_fstr(pinfo->cinfo, COL_INFO, "%shop-by-hop options",
716                              sep);
717               sep = ", ";
718             }
719             if (routing) {
720               col_append_fstr(pinfo->cinfo, COL_INFO, "%srouting", sep);
721               sep = ", ";
722             }
723             if (dstopts) {
724               col_append_fstr(pinfo->cinfo, COL_INFO, "%sdestination options",
725                               sep);
726             }
727           } else
728             col_set_str(pinfo->cinfo, COL_INFO, "IPv6 no next header");
729         }
730       }
731     } else {
732       if (check_col(pinfo->cinfo, COL_INFO))
733         col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%02x)", ipprotostr(nxt),nxt);
734     }
735     call_dissector(data_handle, next_tvb, pinfo, tree);
736   }
737   pinfo->fragmented = save_fragmented;
738 }
739
740 void
741 proto_register_ipv6(void)
742 {
743   static hf_register_info hf[] = {
744     { &hf_ipv6_version,
745       { "Version",              "ipv6.version",
746                                 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
747     { &hf_ipv6_class,
748       { "Traffic class",        "ipv6.class",
749                                 FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
750     { &hf_ipv6_flow,
751       { "Flowlabel",            "ipv6.flow",
752                                 FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
753     { &hf_ipv6_plen,
754       { "Payload length",       "ipv6.plen",
755                                 FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
756     { &hf_ipv6_nxt,
757       { "Next header",          "ipv6.nxt",
758                                 FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
759     { &hf_ipv6_hlim,
760       { "Hop limit",            "ipv6.hlim",
761                                 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
762     { &hf_ipv6_src,
763       { "Source",               "ipv6.src",
764                                 FT_IPv6, BASE_NONE, NULL, 0x0,
765                                 "Source IPv6 Address", HFILL }},
766     { &hf_ipv6_dst,
767       { "Destination",          "ipv6.dst",
768                                 FT_IPv6, BASE_NONE, NULL, 0x0,
769                                 "Destination IPv6 Address", HFILL }},
770     { &hf_ipv6_addr,
771       { "Address",              "ipv6.addr",
772                                 FT_IPv6, BASE_NONE, NULL, 0x0,
773                                 "Source or Destination IPv6 Address", HFILL }},
774
775     { &hf_ipv6_fragment_overlap,
776       { "Fragment overlap",     "ipv6.fragment.overlap",
777                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
778                                 "Fragment overlaps with other fragments", HFILL }},
779
780     { &hf_ipv6_fragment_overlap_conflict,
781       { "Conflicting data in fragment overlap", "ipv6.fragment.overlap.conflict",
782                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
783                                 "Overlapping fragments contained conflicting data", HFILL }},
784
785     { &hf_ipv6_fragment_multiple_tails,
786       { "Multiple tail fragments found", "ipv6.fragment.multipletails",
787                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
788                                 "Several tails were found when defragmenting the packet", HFILL }},
789
790     { &hf_ipv6_fragment_too_long_fragment,
791       { "Fragment too long",    "ipv6.fragment.toolongfragment",
792                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
793                                 "Fragment contained data past end of packet", HFILL }},
794
795     { &hf_ipv6_fragment_error,
796       { "Defragmentation error", "ipv6.fragment.error",
797                                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
798                                 "Defragmentation error due to illegal fragments", HFILL }},
799
800     { &hf_ipv6_fragment,
801       { "IPv6 Fragment",        "ipv6.fragment",
802                                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
803                                 "IPv6 Fragment", HFILL }},
804
805     { &hf_ipv6_fragments,
806       { "IPv6 Fragments",       "ipv6.fragments",
807                                 FT_NONE, BASE_NONE, NULL, 0x0,
808                                 "IPv6 Fragments", HFILL }},
809
810     /* Mobile IPv6 */
811     { &hf_ipv6_mipv6_type,
812       { "Option Type ",         "ipv6.mipv6_type",
813                                 FT_UINT8, BASE_DEC, NULL, 0x0,
814                                 "", HFILL }},
815     { &hf_ipv6_mipv6_length,
816       { "Option Length ",       "ipv6.mipv6_length",
817                                 FT_UINT8, BASE_DEC, NULL, 0x0,
818                                 "", HFILL }},
819     { &hf_ipv6_mipv6_home_address,
820       { "Home Address ",        "ipv6.mipv6_home_address",
821                                 FT_IPv6, BASE_HEX, NULL, 0x0,
822                                 "", HFILL }},
823
824 #ifdef TEST_FINALHDR
825     { &hf_ipv6_final,
826       { "Final next header",    "ipv6.final",
827                                 FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
828 #endif
829   };
830   static gint *ett[] = {
831     &ett_ipv6,
832     &ett_ipv6_fragments,
833     &ett_ipv6_fragment,
834   };
835   module_t *ipv6_module;
836
837   proto_ipv6 = proto_register_protocol("Internet Protocol Version 6", "IPv6", "ipv6");
838   proto_register_field_array(proto_ipv6, hf, array_length(hf));
839   proto_register_subtree_array(ett, array_length(ett));
840
841   /* Register configuration options */
842   ipv6_module = prefs_register_protocol(proto_ipv6, NULL);
843   prefs_register_bool_preference(ipv6_module, "defragment",
844         "Reassemble fragmented IPv6 datagrams",
845         "Whether fragmented IPv6 datagrams should be reassembled",
846         &ipv6_reassemble);
847
848   register_dissector("ipv6", dissect_ipv6, proto_ipv6);
849   register_init_routine(ipv6_reassemble_init);
850 }
851
852 void
853 proto_reg_handoff_ipv6(void)
854 {
855   dissector_handle_t ipv6_handle;
856
857   data_handle = find_dissector("data");
858   ipv6_handle = find_dissector("ipv6");
859   dissector_add("ethertype", ETHERTYPE_IPv6, ipv6_handle);
860   dissector_add("ppp.protocol", PPP_IPV6, ipv6_handle);
861   dissector_add("ppp.protocol", ETHERTYPE_IPv6, ipv6_handle);
862   dissector_add("gre.proto", ETHERTYPE_IPv6, ipv6_handle);
863   dissector_add("ip.proto", IP_PROTO_IPV6, ipv6_handle);
864   dissector_add("null.type", BSD_AF_INET6_BSD, ipv6_handle);
865   dissector_add("null.type", BSD_AF_INET6_FREEBSD, ipv6_handle);
866   dissector_add("null.type", BSD_AF_INET6_DARWIN, ipv6_handle);
867   dissector_add("chdlctype", ETHERTYPE_IPv6, ipv6_handle);
868   dissector_add("fr.ietf", NLPID_IP6, ipv6_handle);
869   dissector_add("x.25.spi", NLPID_IP6, ipv6_handle);
870   dissector_add("arcnet.protocol_id", ARCNET_PROTO_IPv6, ipv6_handle);
871 }