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