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