Change dissect_ppp() to accept offset.
[obnox/wireshark/wip.git] / packet-gre.c
index c5b8f0b499939c8197ff26769beb278ab337c3a1..dbe20248c69cae51b62b972d7eb059cc863ce747 100644 (file)
@@ -2,10 +2,10 @@
  * Routines for the Generic Routing Encapsulation (GRE) protocol
  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
  *
- * $Id: packet-gre.c,v 1.7 1999/11/16 11:42:31 guy Exp $
+ * $Id: packet-gre.c,v 1.17 2000/03/27 17:53:19 gram Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@unicom.net>
+ * By Gerald Combs <gerald@zing.org>
  * Copyright 1998 Gerald Combs
  *
  * 
 #endif
 #include <glib.h>
 #include "packet.h"
+#include "packet-ip.h"
+#include "packet-ppp.h"
 
 static int proto_gre = -1;
+static int hf_gre_proto = -1;
 
 static gint ett_gre = -1;
 static gint ett_gre_flags = -1;
@@ -56,55 +59,77 @@ static gint ett_gre_flags = -1;
 #define GH_B_VER       0x0007
 
 #define GRE_PPP                0x880B
+#define        GRE_IP          0x0800
+#define GRE_WCCP       0x883E
 
-static int calc_len(guint16, int);
 static void add_flags_and_ver(proto_tree *, guint16, int, int);
 
+static const value_string typevals[] = {
+       { GRE_PPP,  "PPP" },
+       { GRE_IP,   "IP" },
+       { GRE_WCCP, "WCCP"},
+       { 0,        NULL  }
+};
+
 void
 dissect_gre(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
   
   guint16      flags_and_ver = pntohs(pd + offset);
   guint16      type          = pntohs(pd + offset + sizeof(flags_and_ver));
-  static const value_string typevals[] = {
-    { GRE_PPP, "PPP" },
-    { 0,       NULL  }
-  };
+  guint16      sre_af;
+  guint8       sre_length;
 
   if (check_col(fd, COL_PROTOCOL))
     col_add_str(fd, COL_PROTOCOL, "GRE");
        
   if (check_col(fd, COL_INFO)) {
-    if (type == GRE_PPP)
-      col_add_str(fd, COL_INFO, "Encapsulated PPP");
-    else
-      col_add_str(fd, COL_INFO, "Encapsulated unknown");
+    col_add_fstr(fd, COL_INFO, "Encapsulated %s",
+        val_to_str(type, typevals, "0x%04X (unknown)"));
   }
                
   if (IS_DATA_IN_FRAME(offset) && tree) {
-    int                        is_ppp;
+    gboolean           is_ppp = FALSE;
+    gboolean           is_wccp2 = FALSE;
     proto_item *       ti;
     proto_tree *       gre_tree;
+    guint              len = 4;
 
-    if (type == GRE_PPP) {
-      is_ppp = 1;
-      ti = proto_tree_add_item_format(tree, proto_gre, offset, calc_len(flags_and_ver, 1),
-       NULL, "Generic Routing Encapsulation (PPP)");
-      gre_tree = proto_item_add_subtree(ti, ett_gre);
-      add_flags_and_ver(gre_tree, flags_and_ver, offset, 1);
-    }
-    else {
-      is_ppp = 0;
-      ti = proto_tree_add_item(tree, proto_gre, offset, calc_len(flags_and_ver, 1), NULL);
-      gre_tree = proto_item_add_subtree(ti, ett_gre);
-      add_flags_and_ver(gre_tree, flags_and_ver, offset, 0);
+    if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R)
+      len += 4;
+    if (flags_and_ver & GH_B_K)
+      len += 4;
+    if (flags_and_ver & GH_B_S)
+      len += 4;
+    switch (type) {
+
+    case GRE_PPP:
+      if (flags_and_ver & GH_P_A)
+        len += 4;
+      is_ppp = TRUE;
+      break;
+
+    case GRE_WCCP:
+      /* WCCP2 apparently puts an extra 4 octets into the header, but uses
+         the same encapsulation type; if it looks as if the first octet of
+        the packet isn't the beginning of an IPv4 header, assume it's
+        WCCP2. */
+      if ((pd[offset + sizeof(flags_and_ver) + sizeof(type)] & 0xF0) != 0x40) {
+       len += 4;
+       is_wccp2 = TRUE;
+      }
+      break;
     }
 
+    ti = proto_tree_add_protocol_format(tree, proto_gre, offset, len,
+      "Generic Routing Encapsulation (%s)",
+      val_to_str(type, typevals, "0x%04X - unknown"));
+    gre_tree = proto_item_add_subtree(ti, ett_gre);
+    add_flags_and_ver(gre_tree, flags_and_ver, offset, is_ppp);
+
     offset += sizeof(flags_and_ver);
 
-    proto_tree_add_text(gre_tree, offset, sizeof(type),
-                       "Protocol Type: %s (%#04x)",
-                       val_to_str(type, typevals, "Unknown"), type);
-    offset += sizeof(type);    
+    proto_tree_add_item(gre_tree, hf_gre_proto, offset, sizeof(type), type);
+    offset += sizeof(type);
 
     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
       guint16 checksum = pntohs(pd + offset);
@@ -158,38 +183,44 @@ dissect_gre(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
     }
 
     if (flags_and_ver & GH_B_R) {
-      proto_tree_add_text(gre_tree, offset, sizeof(guint16),
-                         "Address family: %u", pntohs(pd + offset));
-      offset += sizeof(guint16);
-      proto_tree_add_text(gre_tree, offset, 1,
+      for (;;) {
+       sre_af = pntohs(pd + offset);
+        proto_tree_add_text(gre_tree, offset, sizeof(guint16),
+                         "Address family: %u", sre_af);
+        offset += sizeof(guint16);
+        proto_tree_add_text(gre_tree, offset, 1,
                          "SRE offset: %u", pd[offset++]);
-      proto_tree_add_text(gre_tree, offset, 1,
-                         "SRE length: %u", pd[offset++]);
+       sre_length = pd[offset];
+        proto_tree_add_text(gre_tree, offset, sizeof(guint8),
+                         "SRE length: %u", sre_length);
+       offset += sizeof(guint8);
+       if (sre_af == 0 && sre_length == 0)
+         break;
+       offset += sre_length;
+      }
     }
 
     switch (type) {
-       case GRE_PPP:
-       dissect_payload_ppp(pd, offset, fd, tree);
+      case GRE_PPP:
+        dissect_ppp(pd, offset, fd, tree);
        break;
+      case GRE_IP:
+        dissect_ip(pd, offset, fd, tree);
+        break;
+      case GRE_WCCP:
+        if (is_wccp2) {
+          proto_tree_add_text(gre_tree, offset, sizeof(guint32), "WCCPv2 Data");
+          offset += 4;
+        }
+        dissect_ip(pd, offset, fd, tree);
+        break;
       default:
        dissect_data(pd, offset, fd, gre_tree);
+       break;
     }
   }
 }
 
-static int
-calc_len(guint16 flags_and_ver, int is_ppp) {
-  
-  int  len = 4;
-  
-  if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) len += 4;
-  if (flags_and_ver & GH_B_K) len += 4;
-  if (flags_and_ver & GH_B_S) len += 4;
-  if (is_ppp && flags_and_ver & GH_P_A) len += 4;
-  
-  return len;
-}
-
 static void
 add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_ppp) {
 
@@ -198,7 +229,7 @@ add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_pp
   int          nbits = sizeof(flags_and_ver) * 8;
   
   ti = proto_tree_add_text(tree, offset, 2, 
-                          "Flags and version: %#08x", flags_and_ver);
+                          "Flags and version: %#04x", flags_and_ver);
   fv_tree = proto_item_add_subtree(ti, ett_gre_flags);
   
   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
@@ -241,15 +272,18 @@ add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_pp
 void
 proto_register_gre(void)
 {
-/*        static hf_register_info hf[] = {
-                { &variable,
-                { "Name",           "gre.abbreviation", TYPE, VALS_POINTER }},
-        };*/
+       static hf_register_info hf[] = {
+               { &hf_gre_proto,
+                       { "Protocol Type", "gre.proto", FT_UINT16, BASE_HEX, VALS(typevals), 0x0,
+                               "The protocol that is GRE encapsulated"}
+               },
+       };
        static gint *ett[] = {
                &ett_gre,
+               &ett_gre_flags,
        };
 
         proto_gre = proto_register_protocol("Generic Routing Encapsulation", "gre");
- /*       proto_register_field_array(proto_gre, hf, array_length(hf));*/
+        proto_register_field_array(proto_gre, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
 }