Fix up a bunch of arguments to "dissect_ber_identifier()" to match its
[obnox/wireshark/wip.git] / epan / dissectors / packet-ppp.c
index 8216c9f9ab42417931c4cdb8d70ef50a664e0bb4..e878bc2d63688ee5afffe7438e9b624f70d3f875 100644 (file)
@@ -43,8 +43,8 @@
 #include "packet-ipx.h"
 #include "packet-vines.h"
 #include "nlpid.h"
-#include "crc16.h"
-#include "crc32.h"
+#include <epan/crc16.h>
+#include <epan/crc32.h>
 
 #define ppp_min(a, b)  ((a<b) ? a : b)
 
@@ -55,6 +55,10 @@ static int hf_ppp_protocol = -1;
 
 static gint ett_ppp = -1;
 
+static int proto_ppp_hdlc = -1;
+
+static gint ett_ppp_hdlc_data = -1;
+
 static int proto_lcp = -1;
 
 static gint ett_lcp = -1;
@@ -72,7 +76,8 @@ static int proto_ipcp = -1;
 static gint ett_ipcp = -1;
 static gint ett_ipcp_options = -1;
 static gint ett_ipcp_ipaddrs_opt = -1;
-static gint ett_ipcp_compressprot_opt = -1;
+static gint ett_ipcp_compress_opt = -1;
+static gint ett_ipcp_iphc_disableprot_opt = -1;
 
 static int proto_osicp = -1;
 
@@ -165,7 +170,7 @@ static int proto_ipv6cp = -1;  /* IPv6CP vars */
 static gint ett_ipv6cp = -1;
 static gint ett_ipv6cp_options = -1;
 static gint ett_ipv6cp_if_id_opt = -1;
-static gint ett_ipv6cp_compressprot_opt = -1;  
+static gint ett_ipv6cp_compress_opt = -1;  
 
 static dissector_table_t ppp_subdissector_table;
 static dissector_handle_t chdlc_handle;
@@ -240,7 +245,7 @@ const value_string ppp_vals[] = {
        {PPP_NTCITS_IPI,"NTCITS IPI" },
        {PPP_ML_SLCOMP, "single link compression in multilink" },
        {PPP_COMP,      "compressed packet" },
-       {PPP_STP_HELLO, "802.1d Hello Packet" },
+       {PPP_STP_HELLO, "802.1D Hello Packet" },
        {PPP_IBM_SR,    "IBM Source Routing BPDU" },
        {PPP_DEC_LB,    "DEC LANBridge100 Spanning Tree"},
        {PPP_CDP,       "Cisco Discovery Protocol" },
@@ -915,6 +920,12 @@ static void dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                        int offset, guint length, packet_info *pinfo,
                        proto_tree *tree);
+static void dissect_ipcp_compress_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
+                       int offset, guint length, packet_info *pinfo,
+                       proto_tree *tree);
+static void dissect_ipcp_iphc_disableprot_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
+                       int offset, guint length, packet_info *pinfo,
+                       proto_tree *tree);
 
 static const ip_tcp_opt ipcp_opts[] = {
        {
@@ -927,11 +938,11 @@ static const ip_tcp_opt ipcp_opts[] = {
        },
        {
                CI_COMPRESSTYPE,
-               "IP compression protocol",
-               &ett_ipcp_compressprot_opt,
+               "IP compression",
+               &ett_ipcp_compress_opt,
                VARIABLE_LENGTH,
                4,
-               dissect_lcp_protocol_opt
+               dissect_ipcp_compress_opt
        },
        {
                CI_ADDR,
@@ -985,6 +996,62 @@ static const ip_tcp_opt ipcp_opts[] = {
 
 #define N_IPCP_OPTS    (sizeof ipcp_opts / sizeof ipcp_opts[0])
 
+
+/*
+ * IP Compression options
+ */
+#define IPCP_COMPRESS_VJ_1172  0x37    /* value defined in RFC1172 (typo) */
+#define IPCP_COMPRESS_VJ       0x2d    /* value defined in RFC1332 (correct) */
+#define IPCP_COMPRESS_IPHC     0x61
+
+const value_string ipcp_compress_proto_vals[] = {
+    { IPCP_COMPRESS_VJ_1172,   "VJ compression (RFC1172-typo)" },
+    { IPCP_COMPRESS_VJ,                "VJ compression" },
+    { IPCP_COMPRESS_IPHC,      "IPHC compression" },
+    { 0,                       NULL }
+};
+
+/* IPHC suboptions (RFC2508, 3544) */
+#define IPCP_IPHC_CRTP         1
+#define IPCP_IPHC_ECRTP                2
+#define IPCP_IPHC_DISABLE_PROTO        3       /* Disable compression for protocol */
+
+const value_string ipcp_iphc_disable_proto_vals[] = {
+    { 1,       "TCP" },
+    { 2,       "Non-TCP" },
+    { 0,       NULL }
+};
+
+static const ip_tcp_opt ipcp_iphc_subopts[] = {
+       {
+               IPCP_IPHC_CRTP,
+               "RTP compression (RFC2508)",
+               NULL,
+               FIXED_LENGTH,
+               2,
+               NULL
+       },
+       {
+               IPCP_IPHC_CRTP,
+               "Enhanced RTP compression (RFC3545)",
+               NULL,
+               FIXED_LENGTH,
+               2,
+               NULL
+       },
+       {
+               IPCP_IPHC_DISABLE_PROTO,
+               "Enhanced RTP compression (RFC3545)",
+               &ett_ipcp_iphc_disableprot_opt,
+               FIXED_LENGTH,
+               3,
+               dissect_ipcp_iphc_disableprot_opt
+       },
+};
+
+#define N_IPCP_IPHC_SUBOPTS (sizeof ipcp_iphc_subopts / sizeof ipcp_iphc_subopts[0])
+
+
 /*
  * Options.  (OSICP)
  */
@@ -1351,11 +1418,11 @@ static const ip_tcp_opt ipv6cp_opts[] = {
        },
        {
                CI_COMPRESSTYPE,
-               "IPv6 compression protocol",
-               &ett_ipcp_compressprot_opt,
+               "IPv6 compression",
+               &ett_ipcp_compress_opt,
                VARIABLE_LENGTH,
                4,
-               dissect_lcp_protocol_opt
+               dissect_ipcp_compress_opt
        },
 };
 
@@ -1454,11 +1521,11 @@ decode_fcs(tvbuff_t *tvb, proto_tree *fh_tree, int fcs_decode, int proto_offset)
       rx_fcs_got = tvb_get_letohs(tvb, rx_fcs_offset);
       if (rx_fcs_got != rx_fcs_exp) {
         proto_tree_add_text(fh_tree, tvb, rx_fcs_offset, 2,
-                            "FCS 16: 0x%04x (incorrect, should be 0x%04x)",
+                            "FCS 16: 0x%04x [incorrect, should be 0x%04x]",
                             rx_fcs_got, rx_fcs_exp);
       } else {
         proto_tree_add_text(fh_tree, tvb, rx_fcs_offset, 2,
-                            "FCS 16: 0x%04x (correct)",
+                            "FCS 16: 0x%04x [correct]",
                             rx_fcs_got);
       }
     }
@@ -1506,18 +1573,18 @@ decode_fcs(tvbuff_t *tvb, proto_tree *fh_tree, int fcs_decode, int proto_offset)
       rx_fcs_got = tvb_get_letohl(tvb, rx_fcs_offset);
       if (rx_fcs_got != rx_fcs_exp) {
         proto_tree_add_text(fh_tree, tvb, rx_fcs_offset, 4,
-                            "FCS 32: 0x%08x (incorrect, should be 0x%08x)",
+                            "FCS 32: 0x%08x [incorrect, should be 0x%08x]",
                             rx_fcs_got, rx_fcs_exp);
       } else {
         proto_tree_add_text(fh_tree, tvb, rx_fcs_offset, 4,
-                            "FCS 32: 0x%08x (correct)",
+                            "FCS 32: 0x%08x [correct]",
                             rx_fcs_got);
       }
     }
     break;
 
   default:
-   g_assert_not_reached();
+   DISSECTOR_ASSERT_NOT_REACHED();
    next_tvb = NULL;
   }
 
@@ -1968,6 +2035,150 @@ static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                        ip_to_str(tvb_get_ptr(tvb, offset + 2, 4)));
 }
 
+static void dissect_ipcp_compress_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
+                       int offset, guint length, packet_info *pinfo _U_,
+                       proto_tree *tree)
+{
+    guint8  ub;
+    guint16 us;
+    proto_item *tf;
+    proto_tree *field_tree = NULL;
+
+    tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
+                            optp->name, length, plurality(length, "", "s"));
+
+    field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
+    offset += 2;       /* Skip option type + length */
+    length -= 2;
+
+    us = tvb_get_ntohs(tvb, offset);
+    proto_tree_add_text( field_tree, tvb, offset, 2, "IP compression protocol: %s (0x%04x)",
+                        val_to_str( us, ipcp_compress_proto_vals, "Unknown protocol" ),
+                        us );
+    offset += 2;       /* skip protocol */
+    length -= 2;
+
+    if (length > 0) {
+       switch ( us ) {
+       case IPCP_COMPRESS_VJ_1172:
+       case IPCP_COMPRESS_VJ:
+           /* First byte is max slot id */
+           ub = tvb_get_guint8( tvb, offset );
+           proto_tree_add_text( field_tree, tvb, offset, 1,
+                                "Max slot id: %u (0x%02x)",
+                                ub, ub );
+           offset++;
+           length--;
+
+           if ( length > 0 ) {
+               /* second byte is "compress slot id" */
+               ub = tvb_get_guint8( tvb, offset );
+               proto_tree_add_text( field_tree, tvb, offset, 1,
+                                    "Compress slot id: %s (0x%02x)",
+                                    ub ? "yes" : "no",  ub );
+               offset++;
+               length--;
+           }
+           break;
+
+           
+       case IPCP_COMPRESS_IPHC:
+           if ( length < 2 ) {
+               break;
+           }
+           us = tvb_get_ntohs(tvb, offset);
+           proto_tree_add_text( field_tree, tvb, offset, 2,
+                                "TCP space: %u (0x%04x)",
+                                us, us );
+           offset += 2;
+           length -= 2;
+
+
+           if ( length < 2 ) {
+               break;
+           }
+           us = tvb_get_ntohs(tvb, offset);
+           proto_tree_add_text( field_tree, tvb, offset, 2,
+                                "Non-TCP space: %u (0x%04x)",
+                                us, us );
+           offset += 2;
+           length -= 2;
+
+
+           if ( length < 2 ) {
+               break;
+           }
+           us = tvb_get_ntohs(tvb, offset);
+           proto_tree_add_text( field_tree, tvb, offset, 2,
+                                "Max period: %u (0x%04x) compressed packets",
+                                us, us );
+           offset += 2;
+           length -= 2;
+
+
+           if ( length < 2 ) {
+               break;
+           }
+           us = tvb_get_ntohs(tvb, offset);
+           proto_tree_add_text( field_tree, tvb, offset, 2,
+                                "Max time: %u (0x%04x) seconds",
+                                us, us );
+           offset += 2;
+           length -= 2;
+
+
+           if ( length < 2 ) {
+               break;
+           }
+           us = tvb_get_ntohs(tvb, offset);
+           proto_tree_add_text( field_tree, tvb, offset, 2,
+                                "Max header: %u (0x%04x) bytes",
+                                us, us );
+           offset += 2;
+           length -= 2;
+
+           if ( length > 0 ) {
+               /* suboptions */
+               tf = proto_tree_add_text(field_tree, tvb, offset, length,
+                                        "Suboptions: (%u byte%s)",
+                                        length, plurality(length, "", "s"));
+               field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
+               dissect_ip_tcp_options(tvb, offset, length,
+                                      ipcp_iphc_subopts, N_IPCP_IPHC_SUBOPTS, -1,
+                                      pinfo, field_tree);
+           }
+           return;
+       }
+
+       if (length > 0) {
+           proto_tree_add_text(field_tree, tvb, offset, length,
+                               "Data (%d byte%s)", length,
+                               plurality(length, "", "s"));
+       }
+    }
+}
+
+static void dissect_ipcp_iphc_disableprot_opt(const ip_tcp_opt *optp,
+                                             tvbuff_t *tvb,
+                                             int offset, guint length,
+                                             packet_info *pinfo _U_,
+                                             proto_tree *tree)
+{
+    proto_item *tf;
+    proto_tree *field_tree;
+    guint8 param;
+
+    tf = proto_tree_add_text(tree, tvb, offset, length, "%s", optp->name);
+    field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
+
+    param = tvb_get_guint8(tvb, offset + 2);
+    proto_tree_add_text(field_tree, tvb, offset + 2, 1,
+                       "Protocol: %s (0x%02x)",
+                       val_to_str( param, ipcp_iphc_disable_proto_vals, "Unknown" ),
+                       param );
+}
+
+
 static void dissect_osicp_align_npdu_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                         int offset, guint length, packet_info *pinfo _U_,
                         proto_tree *tree)
@@ -2184,11 +2395,16 @@ dissect_cbcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
     offset++;
     length--;
     addr_len = tvb_strsize(tvb, offset);
+    if (addr_len > length) {
+      proto_tree_add_text(addr_tree, tvb, offset, length,
+                         "Address: (runs past end of option)");
+      break;
+    }
     proto_tree_add_text(addr_tree, tvb, offset, addr_len,
                        "Address: %s",
                        tvb_format_text(tvb, offset, addr_len - 1));
-    offset += (addr_len + 1);
-    length -= (addr_len + 1);
+    offset += addr_len;
+    length -= addr_len;
   }
 }
 
@@ -2249,7 +2465,7 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
     subopt_type = tvb_get_guint8(tvb, offset);
     subopt_len = tvb_get_guint8(tvb, offset + 1);
     ti = proto_tree_add_text(field_tree, tvb, offset, subopt_len,
-               "Sub-Option (%d byte%s)",
+               "Sub-Option (%u byte%s)",
                subopt_len, plurality(subopt_len, "", "s"));
     suboption_tree = proto_item_add_subtree(ti, ett_bap_phone_delta_subopt);
 
@@ -2258,13 +2474,30 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
        val_to_str(subopt_type, bap_phone_delta_subopt_vals, "Unknown"),
        subopt_type);
 
+    if (subopt_len < 2) {
+      proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
+         "Sub-Option Length: %u (invalid, must be >= 2)", subopt_len);
+      return;
+    }
+    if (subopt_len > length) {
+      proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
+         "Sub-Option Length: %u (invalid, must be <= length remaining in option %u)", subopt_len, length);
+      return;
+    }
+
     proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
        "Sub-Option Length: %u", subopt_len);
 
     switch (subopt_type) {
     case BAP_PHONE_DELTA_SUBOPT_UNIQ_DIGIT:
-      proto_tree_add_text(suboption_tree, tvb, offset + 2, 1, "Uniq Digit: %u",
-                         tvb_get_guint8(tvb, offset + 2));
+      if (subopt_len == 3) {
+        proto_tree_add_text(suboption_tree, tvb, offset + 2, 1, "Unique Digit: %u",
+                           tvb_get_guint8(tvb, offset + 2));
+      } else {
+        proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
+                         "Invalid suboption length: %u (must be == 3)",
+                         subopt_len);
+      }
       break;
     case BAP_PHONE_DELTA_SUBOPT_SUBSC_NUM:
       if (subopt_len > 2) {
@@ -2273,7 +2506,8 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                          tvb_format_text(tvb, offset + 2, subopt_len - 2));
       } else {
         proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
-                         "Invalid suboption length: %u", subopt_len);
+                         "Invalid suboption length: %u (must be > 2)",
+                         subopt_len);
       }
       break;
     case BAP_PHONE_DELTA_SUBOPT_PHONENUM_SUBADDR:
@@ -2281,11 +2515,21 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
         proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2,
                          "Phone Number Sub Address: %s",
                          tvb_format_text(tvb, offset + 2, subopt_len - 2));
+      } else {
+        proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
+                         "Invalid suboption length: %u (must be > 2)",
+                         subopt_len);
       }
       break;
     default:
-      proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2,
+      if (subopt_len > 2) {
+        proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2,
                          "Unknown");
+      } else {
+        proto_tree_add_text(suboption_tree, tvb, offset + 1, 1,
+                         "Invalid suboption length: %u (must be > 2)",
+                         subopt_len);
+      }
       break;
     }
     offset += subopt_len;
@@ -2397,7 +2641,6 @@ dissect_cp( tvbuff_t *tvb, int proto_id, int proto_subtree_index,
     case ECHOREQ:
     case ECHOREP:
     case DISCREQ:
-    case IDENT:
       if(tree) {
        proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
                        tvb_get_ntohl(tvb, offset));
@@ -2409,6 +2652,18 @@ dissect_cp( tvbuff_t *tvb, int proto_id, int proto_subtree_index,
       }
       break;
 
+    case IDENT:
+      if(tree) {
+       proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
+                       tvb_get_ntohl(tvb, offset));
+       offset += 4;
+       length -= 4;
+       if (length > 0)
+          proto_tree_add_text(fh_tree, tvb, offset, length, "Message: %s",
+                               tvb_format_text(tvb, offset, length));
+      }
+      break;
+
     case TIMEREMAIN:
       if(tree) {
        proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
@@ -2489,7 +2744,7 @@ dissect_cp( tvbuff_t *tvb, int proto_id, int proto_subtree_index,
 
 static void
 dissect_ppp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-               proto_tree *fh_tree, proto_item *ti )
+               proto_tree *fh_tree, proto_item *ti, int proto_offset )
 {
   guint16 ppp_prot;
   int     proto_len;
@@ -2506,11 +2761,12 @@ dissect_ppp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
   }
 
   /* If "ti" is not null, it refers to the top-level "proto_ppp" item
-     for PPP, and was given a length equal to the length of any
-     stuff in the header preceding the protocol type, e.g. an HDLC
-     header; add the length of the protocol type field to it. */
+     for PPP, and proto_offset is the length of any stuff in the header
+     preceding the protocol type, e.g. an HDLC header; add the length
+     of the protocol type field to it, and set the length of that item
+     to the result. */
   if (ti != NULL)
-    proto_item_set_len(ti, proto_item_get_len(ti) + proto_len);
+    proto_item_set_len(ti, proto_offset + proto_len);
 
   if (tree)
     proto_tree_add_uint(fh_tree, hf_ppp_protocol, tvb, 0, proto_len, ppp_prot);
@@ -2767,6 +3023,7 @@ dissect_pppmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       length_remaining -= hdr_length;
       length -= pid_field;
 
+      tvb_ensure_bytes_exist (tvb,offset,length);
       sub_ti = proto_tree_add_text(sub_tree,tvb,offset,length,"Information Field");
       info_tree = proto_item_add_subtree(sub_ti,ett_pppmux_subframe_info);
 
@@ -2883,15 +3140,11 @@ dissect_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
     fh_tree = proto_item_add_subtree(ti, ett_ppp);
   }
 
-  dissect_ppp_common(tvb, pinfo, tree, fh_tree, ti);
+  dissect_ppp_common(tvb, pinfo, tree, fh_tree, ti, 0);
 }
 
-/*
- * Handles link-layer encapsulations where the frame might be
- * a PPP in HDLC-like Framing frame (RFC 1662) or a Cisco HDLC frame.
- */
 static void
-dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
+dissect_ppp_hdlc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   proto_item *ti = NULL;
   proto_tree *fh_tree = NULL;
@@ -2900,16 +3153,6 @@ dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
   tvbuff_t  *next_tvb;
 
   byte0 = tvb_get_guint8(tvb, 0);
-  if (byte0 == CHDLC_ADDR_UNICAST || byte0 == CHDLC_ADDR_MULTICAST) {
-    /* Cisco HDLC encapsulation */
-    call_dissector(chdlc_handle, tvb, pinfo, tree);
-    return;
-  }
-
-  /*
-   * XXX - should we have a routine that always dissects PPP, for use
-   * when we know the packets are PPP, not CHDLC?
-   */
 
   /* PPP HDLC encapsulation */
   if (byte0 == 0xff)
@@ -2921,10 +3164,42 @@ dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
 
   /* load the top pane info. This should be overwritten by
      the next protocol in the stack */
+  if(tree) {
+    ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, -1, FALSE);
+    fh_tree = proto_item_add_subtree(ti, ett_ppp);
+    if (byte0 == 0xff) {
+      proto_tree_add_item(fh_tree, hf_ppp_address, tvb, 0, 1, FALSE);
+      proto_tree_add_item(fh_tree, hf_ppp_control, tvb, 1, 1, FALSE);
+    }
+  }
 
-  if(check_col(pinfo->cinfo, COL_PROTOCOL))
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPP" );
+  next_tvb = decode_fcs(tvb, fh_tree, ppp_fcs_decode, proto_offset);
+
+  dissect_ppp_common(next_tvb, pinfo, tree, fh_tree, ti, proto_offset);
+}
+
+/*
+ * Handles link-layer encapsulations where the frame might be
+ * a PPP in HDLC-like Framing frame (RFC 1662) or a Cisco HDLC frame.
+ */
+static void
+dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
+{
+  guint8     byte0;
 
+  byte0 = tvb_get_guint8(tvb, 0);
+  if (byte0 == CHDLC_ADDR_UNICAST || byte0 == CHDLC_ADDR_MULTICAST) {
+    /* Cisco HDLC encapsulation */
+    call_dissector(chdlc_handle, tvb, pinfo, tree);
+    return;
+  }
+
+  /*
+   * XXX - should we have an exported dissector that always dissects PPP,
+   * for use when we know the packets are PPP, not CHDLC?
+   */
+  if(check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPP");
   switch (pinfo->p2p_dir) {
 
   case P2P_DIR_SENT:
@@ -2949,18 +3224,206 @@ dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
     break;
   }
 
-  if(tree) {
-    ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, proto_offset, FALSE);
-    fh_tree = proto_item_add_subtree(ti, ett_ppp);
-    if (byte0 == 0xff) {
-      proto_tree_add_item(fh_tree, hf_ppp_address, tvb, 0, 1, FALSE);
-      proto_tree_add_item(fh_tree, hf_ppp_control, tvb, 1, 1, FALSE);
-    }
+  dissect_ppp_hdlc_common(tvb, pinfo, tree);
+}
+
+static tvbuff_t*
+remove_escape_chars(tvbuff_t *tvb, int offset, int length)
+{
+  guint8       *buff;
+  int          i;
+  int          scanned_len = 0;
+  guint8       octet;
+  tvbuff_t  *next_tvb;
+       
+  buff = g_malloc(length);
+  i = 0;
+  while ( scanned_len < length ){
+         octet = tvb_get_guint8(tvb,offset);
+         if (octet == 0x7d){
+                 offset++;
+                 scanned_len++;
+                 if (scanned_len >= length)
+                         break;
+                 octet = tvb_get_guint8(tvb,offset);
+                 buff[i] = octet ^ 0x20;
+         }else{
+                 buff[i]= octet;
+         }
+         offset++;
+         scanned_len++;
+         i++;
   }
+  if (i == 0)
+         return NULL;
+  next_tvb = tvb_new_real_data(buff,i,i);
 
-  next_tvb = decode_fcs(tvb, fh_tree, ppp_fcs_decode, proto_offset);
+  /* Arrange that the allocated packet data copy be freed when the
+   * tvbuff is freed. 
+   */
+  tvb_set_free_cb( next_tvb, g_free );
+
+  tvb_set_child_real_data_tvbuff(tvb,next_tvb);
+  return next_tvb;
 
-  dissect_ppp_common(next_tvb, pinfo, tree, fh_tree, ti);
+}
+
+/*
+ * Handles link-layer encapsulations where we have a raw RFC 1662
+ * HDLC-like asynchronous framing byte stream, and have to
+ * break the byte stream into frames and remove escapes.
+ */
+static void
+dissect_ppp_raw_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
+{
+  proto_item *ti;
+  proto_tree *bs_tree = NULL;
+  gint       offset, end_offset, data_offset;
+  int        length, data_length;
+  tvbuff_t   *ppp_tvb;
+  gboolean    first = TRUE;
+
+  if(check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPP" );
+
+  if (tree) {
+    ti = proto_tree_add_item(tree, proto_ppp_hdlc, tvb, 0, -1, FALSE);
+    bs_tree = proto_item_add_subtree(ti, ett_ppp_hdlc_data);
+  }
+
+  /*
+   * XXX - this needs to handle a PPP frame split over multiple higher-level
+   * packets.
+   */
+
+  /*
+   * Look for a frame delimiter.
+   */
+  offset = tvb_find_guint8(tvb, 0, -1, 0x7e);
+  if (offset == -1) {
+         /*
+          * None found - this is presumably continued from an earlier
+          * packet and continued in a later packet.
+          */
+         if (check_col(pinfo->cinfo, COL_INFO)){
+                 col_add_str(pinfo->cinfo, COL_INFO,"PPP Fragment");
+         }
+         if (tree)
+                 proto_tree_add_text(bs_tree, tvb, offset, -1, "PPP Fragment");
+         offset++;
+         length = tvb_length_remaining(tvb,offset);
+         ppp_tvb = remove_escape_chars(tvb, offset,length);
+         if (ppp_tvb != NULL) {
+                 add_new_data_source(pinfo, ppp_tvb, "PPP Fragment");
+                 call_dissector(data_handle, ppp_tvb, pinfo, tree);
+         }
+         return;
+  }
+  if (offset != 0) {
+         /*
+          * We have some data preceding the first PPP packet;
+          * mark it as a PPP fragment.
+          */
+         if(check_col(pinfo->cinfo, COL_INFO)){
+                 col_add_str(pinfo->cinfo, COL_INFO,"PPP Fragment");
+         }
+         length = offset;
+         if (tree)
+                 proto_tree_add_text(bs_tree, tvb, 0, length, "PPP Fragment");
+         if (length != 0) {
+                 ppp_tvb = remove_escape_chars(tvb, 0, length - 1);
+                 if (ppp_tvb != NULL) {
+                         add_new_data_source(pinfo, ppp_tvb, "PPP Fragment");
+                         call_dissector(data_handle, ppp_tvb, pinfo, tree);
+                 }
+         }
+  }
+  while ( tvb_reported_length_remaining(tvb, offset) > 0 ){
+         /*
+          * Look for the next frame delimiter.
+          */
+         end_offset = tvb_find_guint8(tvb, offset+1, -1, 0x7e);
+         if ( end_offset == -1 ){
+                 /*
+                  * We didn't find one.  This is probably continued in
+                  * a later packet.
+                  */
+                 if (first) {
+                         if(check_col(pinfo->cinfo, COL_INFO)){
+                                 col_add_str(pinfo->cinfo, COL_INFO,"PPP Fragment");
+                         }
+                 }
+                 if (tree)
+                         proto_tree_add_text(bs_tree, tvb, offset, -1, "PPP Fragment");
+                 offset++;
+                 length = tvb_length_remaining(tvb, offset);
+                 ppp_tvb = remove_escape_chars(tvb, offset,length);
+                 if (ppp_tvb != NULL) {
+                         add_new_data_source(pinfo, ppp_tvb, "PPP Fragment");
+                         call_dissector(data_handle, ppp_tvb, pinfo, tree);
+                 }
+                 return;
+         }
+
+         data_offset = offset+1;       /* skip starting frame delimiter */
+         data_length = end_offset - data_offset;
+
+         /*
+          * Is that frame delimiter immediately followed by another one?
+          * Some PPP implementations put a frame delimiter at the
+          * beginning and the end of each frame, although RFC 1662
+          * appears only to require that there be one frame delimiter
+          * between adjacent frames:
+          *
+          *  Each frame begins and ends with a Flag Sequence, which is the
+          *  binary sequence 01111110 (hexadecimal 0x7e).  All implementations
+          *  continuously check for this flag, which is used for frame
+          *  synchronization.
+          *
+          *  Only one Flag Sequence is required between two frames.  Two
+          *  consecutive Flag Sequences constitute an empty frame, which is
+          *  silently discarded, and not counted as a FCS error.
+          *
+          * If the delimiter at the end of this frame is followed by
+          * another delimiter, we consider the first delimiter part
+          * of this frame.
+          */
+         if (tvb_offset_exists(tvb, end_offset+1) &&
+             tvb_get_guint8(tvb, end_offset+1) == 0x7e)
+                 end_offset++;
+         length = end_offset - offset;
+         if (tree)
+                 proto_tree_add_text(bs_tree, tvb, offset, length, "PPP Data");
+         if (length > 1) {
+                 ppp_tvb = remove_escape_chars(tvb, data_offset, data_length);
+                 if (ppp_tvb != NULL) {
+                         add_new_data_source(pinfo, ppp_tvb, "PPP Message");
+                         dissect_ppp_hdlc_common(ppp_tvb, pinfo, tree);
+                         first = FALSE;
+                 }
+         }
+         offset = end_offset;
+  } /* end while */
+}
+
+void
+proto_register_ppp_raw_hdlc(void)
+{
+  static gint *ett[] = {
+    &ett_ppp_hdlc_data
+  };
+
+  proto_ppp_hdlc = proto_register_protocol("PPP In HDLC-Like Framing", "PPP-HDLC", "ppp_hdlc");
+  proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_ppp_raw_hdlc(void)
+{
+  dissector_handle_t ppp_raw_hdlc_handle;
+
+  ppp_raw_hdlc_handle = create_dissector_handle(dissect_ppp_raw_hdlc, proto_ppp);
+  dissector_add("gre.proto", ETHERTYPE_CDMA2000_A10_UBS, ppp_raw_hdlc_handle);
 }
 
 /*
@@ -3077,9 +3540,8 @@ dissect_chap( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
   proto_tree *value_tree;
 
   guint8 code, id, value_size;
-  guint16 length;
+  gint32 length;
   int offset;
-  int name_length;
 
   code = tvb_get_guint8(tvb, 0);
   id = tvb_get_guint8(tvb, 1);
@@ -3099,6 +3561,15 @@ dissect_chap( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
       val_to_str(code, chap_vals, "Unknown"), code);
     proto_tree_add_text(fh_tree, tvb, 1, 1, "Identifier: 0x%02x",
                        id);
+  }
+  if(length < 4) {
+    if(tree) {
+      proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u (invalid, must be >= 4)",
+                         length);
+      return;
+    }
+  }
+  if(tree) {
     proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u",
                        length);
   }
@@ -3115,23 +3586,30 @@ dissect_chap( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
                                   plurality(length, "", "s"));
           field_tree = proto_item_add_subtree(tf, ett_chap_data);
          value_size = tvb_get_guint8(tvb, offset);
-         name_length = length - value_size - 1;
+         length--;
+         if (value_size > length) {
+           proto_tree_add_text(field_tree, tvb, offset, 1,
+                               "Value Size: %d byte%s (invalid, must be <= %u)",
+                               value_size, plurality(value_size, "", "s"),
+                               length);
+           return;
+         }
          tv = proto_tree_add_text(field_tree, tvb, offset, 1,
-                                  "Value Size: %d byte%s",
-                                  value_size, plurality(value_size, "", "s"));
-         if (--length > 0) {
+                                 "Value Size: %u byte%s",
+                                 value_size, plurality(value_size, "", "s"));
+         offset++;
+         if (length > 0) {
            value_tree = proto_item_add_subtree(tv, ett_chap_value);
-           proto_tree_add_text(value_tree, tvb, ++offset,
-                               ppp_min(value_size, length),
-                               "Value (%d byte%s)",
+           proto_tree_add_text(value_tree, tvb, offset, value_size,
+                               "Value (%u byte%s)",
                                value_size, plurality(value_size, "", "s"));
            offset+=value_size;
            length-=value_size;
            if (length > 0) {
-             proto_tree_add_text(field_tree, tvb, offset,
-                                 ppp_min(name_length, length),
-                                 "Name (%d byte%s)", name_length,
-                                 plurality(name_length, "", "s"));
+                 tvb_ensure_bytes_exist(tvb, offset, length);
+             proto_tree_add_text(field_tree, tvb, offset, length,
+                                 "Name (%u byte%s)", length,
+                                 plurality(length, "", "s"));
            }
          }
         }
@@ -3143,18 +3621,18 @@ dissect_chap( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
       if(tree) {
         if (length > 0) {
           tf = proto_tree_add_text(fh_tree, tvb, offset, length,
-                                  "Data (%d byte%s)", length,
+                                  "Data (%u byte%s)", length,
                                   plurality(length, "", "s"));
           field_tree = proto_item_add_subtree(tf, ett_chap_data);
          tv = proto_tree_add_text(field_tree, tvb, offset, length,
-                                  "Message: %d byte%s",
+                                  "Message: %u byte%s",
                                   length, plurality(length, "", "s"));
        }
       }
       break;
     default:
       if (length > 0)
-        proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%d byte%s)",
+        proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%u byte%s)",
                                length, plurality(length, "", "s"));
       break;
   }
@@ -3204,7 +3682,7 @@ proto_register_ppp(void)
         VALS(ppp_vals), 0x0, "", HFILL }},
   };
   static gint *ett[] = {
-    &ett_ppp,
+    &ett_ppp
   };
 
   module_t *ppp_module;
@@ -3253,11 +3731,13 @@ proto_reg_handoff_ppp(void)
   chdlc_handle = find_dissector("chdlc");
   data_handle = find_dissector("data");
 
-  ppp_hdlc_handle = find_dissector("ppp_hdlc");
   ppp_handle = find_dissector("ppp");
+  dissector_add("fr.ietf", NLPID_PPP, ppp_handle);
+
+  ppp_hdlc_handle = find_dissector("ppp_hdlc");
   dissector_add("wtap_encap", WTAP_ENCAP_PPP, ppp_hdlc_handle);
   dissector_add("wtap_encap", WTAP_ENCAP_PPP_WITH_PHDR, ppp_hdlc_handle);
-  dissector_add("fr.ietf", NLPID_PPP, ppp_handle);
+  dissector_add("osinl.excl", NLPID_PPP, ppp_handle);
   dissector_add("gre.proto", ETHERTYPE_PPP, ppp_hdlc_handle);
 }
 
@@ -3341,6 +3821,12 @@ proto_reg_handoff_lcp(void)
    * table.
    */
   dissector_add("ethertype", PPP_LCP, lcp_handle);
+
+  /*
+   * for GSM-A / MobileL3 / GPRS SM / PCO
+   */
+  dissector_add("sm_pco.protocol", PPP_LCP, lcp_handle);
+
 }
 
 void
@@ -3350,7 +3836,7 @@ proto_register_ipcp(void)
     &ett_ipcp,
     &ett_ipcp_options,
     &ett_ipcp_ipaddrs_opt,
-    &ett_ipcp_compressprot_opt,
+    &ett_ipcp_compress_opt,
   };
 
   proto_ipcp = proto_register_protocol("PPP IP Control Protocol", "PPP IPCP",
@@ -3371,6 +3857,12 @@ proto_reg_handoff_ipcp(void)
    * registering with the "ethertype" dissector table.
    */
   dissector_add("ethertype", PPP_IPCP, ipcp_handle);
+
+  /*
+   * for GSM-A / MobileL3 / GPRS SM / PCO
+   */
+  dissector_add("sm_pco.protocol", PPP_IPCP, ipcp_handle);
+
 }
 
 void
@@ -3584,6 +4076,11 @@ proto_reg_handoff_pap(void)
    * registering with the "ethertype" dissector table.
    */
   dissector_add("ethertype", PPP_PAP, pap_handle);
+
+  /*
+   * for GSM-A / MobileL3 / GPRS SM / PCO
+   */
+  dissector_add("sm_pco.protocol", PPP_PAP, pap_handle);
 }
 
 void
@@ -3615,6 +4112,11 @@ proto_reg_handoff_chap(void)
    * registering with the "ethertype" dissector table.
    */
   dissector_add("ethertype", PPP_CHAP, chap_handle);
+  
+  /*
+   * for GSM-A / MobileL3 / GPRS SM / PCO
+   */
+  dissector_add("sm_pco.protocol", PPP_CHAP, chap_handle);
 }
 
 void
@@ -3743,7 +4245,7 @@ proto_register_ipv6cp(void)
     &ett_ipv6cp,
     &ett_ipv6cp_options,
     &ett_ipv6cp_if_id_opt,
-    &ett_ipv6cp_compressprot_opt,
+    &ett_ipv6cp_compress_opt,
   };
 
   proto_ipv6cp = proto_register_protocol("PPP IPv6 Control Protocol",