From Ronald Henderson: make "format_text()", on Windows, escape all
[obnox/wireshark/wip.git] / packet-ppp.c
index a3688b10ea8a6d0113777aea772d1a2848282584..d78ebd9bc35db38e04fe3269d779bb32379d309b 100644 (file)
@@ -1,24 +1,24 @@
 /* packet-ppp.c
  * Routines for ppp packet disassembly
  *
- * $Id: packet-ppp.c,v 1.93 2002/05/22 09:52:14 guy Exp $
+ * $Id: packet-ppp.c,v 1.103 2002/12/11 19:59:08 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  *
  * This file created and by Mike Hall <mlh@io.com>
  * Copyright 1998
- * 
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <string.h>
 #include <glib.h>
 #include "prefs.h"
@@ -132,6 +128,14 @@ static int hf_mp_sequence_num = -1;
 static int ett_mp = -1;
 static int ett_mp_flags = -1;
 
+static int proto_mplscp = -1;
+static gint ett_mplscp = -1;
+static gint ett_mplscp_options = -1;
+
+static int proto_cdpcp = -1;
+static gint ett_cdpcp = -1;
+static gint ett_cdpcp_options = -1;
+
 static int proto_pap                   = -1;           /* PAP vars */
 static gint ett_pap                    = -1;
 static gint ett_pap_data               = -1;
@@ -146,7 +150,17 @@ static gint ett_chap_value         = -1;
 static gint ett_chap_name              = -1;
 static gint ett_chap_message           = -1;
 
-static dissector_table_t subdissector_table;
+static int proto_ipv6cp = -1;  /* IPv6CP vars */
+
+static gint ett_ipv6cp = -1;
+static gint ett_ipv6cp_options = -1;
+static gint ett_ipv6cp_if_token_opt = -1;
+static gint ett_ipv6cp_compressprot_opt = -1;  
+
+/*
+ * Used by the GTP dissector as well.
+ */
+dissector_table_t ppp_subdissector_table;
 static dissector_handle_t chdlc_handle;
 static dissector_handle_t data_handle;
 
@@ -156,7 +170,7 @@ static gint ppp_fcs_decode = 0; /* 0 = No FCS, 1 = 16 bit FCS, 2 = 32 bit FCS */
 #define FCS_16 1
 #define FCS_32 2
 gboolean ppp_vj_decomp = TRUE; /* Default to VJ header decompression */
-                               
+
 /*
  * For Default Protocol ID negotiated with PPPMuxCP. We need to
  * this ID so that if the first subframe doesn't have protocol
@@ -167,42 +181,138 @@ static guint pppmux_def_prot_id = 0;
 
 /* PPP definitions */
 
-static const value_string ppp_vals[] = {
+/*
+ * Used by the GTP dissector as well.
+ */
+const value_string ppp_vals[] = {
+       {PPP_PADDING,   "Padding Protocol" },
+       {PPP_ROHC_SCID, "ROHC small-CID" },
+       {PPP_ROHC_LCID, "ROHC large-CID" },
        {PPP_IP,        "IP"             },
        {PPP_OSI,       "OSI"            },
+       {PPP_DEC4,      "DECnet Phase IV" },
        {PPP_AT,        "Appletalk"      },
        {PPP_IPX,       "Netware IPX/SPX"},
        {PPP_VJC_COMP,  "VJ compressed TCP"},
        {PPP_VJC_UNCOMP,"VJ uncompressed TCP"},
        {PPP_BPDU,      "Bridging PDU"},
+       {PPP_ST,        "Stream Protocol (ST-II)" },
        {PPP_VINES,     "Vines"          },
-        {PPP_MP,       "Multilink"},
+       {PPP_AT_EDDP,   "AppleTalk EDDP" },
+       {PPP_AT_SB,     "AppleTalk SmartBuffered" },
+       {PPP_MP,        "Multilink"},
+       {PPP_NB,        "NETBIOS Framing" },
+       {PPP_CISCO,     "Cisco Systems" },
+       {PPP_ASCOM,     "Ascom Timeplex" },
+       {PPP_LBLB,      "Fujitsu Link Backup and Load Balancing" },
+       {PPP_RL,        "DCA Remote Lan" },
+       {PPP_SDTP,      "Serial Data Transport Protocol" },
+       {PPP_LLC,       "SNA over LLC" },
+       {PPP_SNA,       "SNA" },
+       {PPP_IPV6HC,    "IPv6 Header Compression " },
+       {PPP_KNX,       "KNX Bridging Data" },
+       {PPP_ENCRYPT,   "Encryption" },
+       {PPP_ILE,       "Individual Link Encryption" },
        {PPP_IPV6,      "IPv6"           },
         {PPP_MUX,       "PPP Multiplexing"},
+       {PPP_RTP_FH,    "RTP IPHC Full Header" },
+       {PPP_RTP_CTCP,  "RTP IPHC Compressed TCP" },
+       {PPP_RTP_CNTCP, "RTP IPHC Compressed Non TCP" },
+       {PPP_RTP_CUDP8, "RTP IPHC Compressed UDP 8" },
+       {PPP_RTP_CRTP8, "RTP IPHC Compressed RTP 8" },
+       {PPP_STAMPEDE,  "Stampede Bridging" },
+       {PPP_MPPLUS,    "MP+ Protocol" },
+       {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_IBM_SR,    "IBM Source Routing BPDU" },
        {PPP_DEC_LB,    "DEC LANBridge100 Spanning Tree"},
+       {PPP_CDP,       "Cisco Discovery Protocol" },
+       {PPP_NETCS,     "Netcs Twin Routing" },
+       {PPP_STP,       "Scheduled Transfer Protocol" },
+       {PPP_EDP,       "Extreme Discovery Protocol" },
+       {PPP_OSCP,      "Optical Supervisory Channel Protocol" },
+       {PPP_OSCP2,     "Optical Supervisory Channel Protocol" },
+       {PPP_LUXCOM,    "Luxcom" },
+       {PPP_SIGMA,     "Sigma Network Systems" },
+       {PPP_ACSP,      "Apple Client Server Protocol" },
        {PPP_MPLS_UNI,  "MPLS Unicast"},
        {PPP_MPLS_MULTI, "MPLS Multicast"},
+       {PPP_P12844,    "IEEE p1284.4 standard - data packets" },
+       {PPP_ETSI,      "ETSI TETRA Networks Procotol Type 1" },
+       {PPP_MFTP,      "Multichannel Flow Treatment Protocol" },
+       {PPP_RTP_CTCPND,"RTP IPHC Compressed TCP No Delta" },
+       {PPP_RTP_CS,    "RTP IPHC Context State" },
+       {PPP_RTP_CUDP16,"RTP IPHC Compressed UDP 16" },
+       {PPP_RTP_CRDP16,"RTP IPHC Compressed RTP 16" },
+       {PPP_CCCP,      "Cray Communications Control Protocol" },
+       {PPP_CDPD_MNRP, "CDPD Mobile Network Registration Protocol" },
+       {PPP_EXPANDAP,  "Expand accelarator protocol" },
+       {PPP_ODSICP,    "ODSICP NCP" },
+       {PPP_DOCSIS,    "DOCSIS DLL" },
+       {PPP_LZS,       "Stacker LZS" },
+       {PPP_REFTEK,    "RefTek Protocol" },
+       {PPP_FC,        "Fibre Channel" },
+       {PPP_EMIT,      "EMIT Protocols" },
        {PPP_IPCP,      "IP Control Protocol" },
        {PPP_OSICP,     "OSI Control Protocol" },
+       {PPP_XNSIDPCP,  "Xerox NS IDP Control Protocol" },
+       {PPP_DECNETCP,  "DECnet Phase IV Control Protocol" },
        {PPP_ATCP,      "AppleTalk Control Protocol" },
        {PPP_IPXCP,     "IPX Control Protocol" },
+       {PPP_BRIDGENCP, "Bridging NCP" },
+       {PPP_SPCP,      "Stream Protocol Control Protocol" },
+       {PPP_BVCP,      "Banyan Vines Control Protocol" },
+       {PPP_MLCP,      "Multi-Link Control Protocol" },
+       {PPP_NBCP,      "NETBIOS Framing Control Protocol" },
+       {PPP_CISCOCP,   "Cisco Systems Control Protocol" },
+       {PPP_ASCOMCP,   "Ascom Timeplex" },
+       {PPP_LBLBCP,    "Fujitsu LBLB Control Protocol" },
+       {PPP_RLNCP,     "DCA Remote Lan Network Control Protocol" },
+       {PPP_SDCP,      "Serial Data Control Protocol" },
+       {PPP_LLCCP,     "SNA over LLC Control Protocol" },
+       {PPP_SNACP,     "SNA Control Protocol" },
+       {PPP_KNXCP,     "KNX Bridging Control Protocol" },
+       {PPP_ECP,       "Encryption Control Protocol" },
+       {PPP_ILECP,     "Individual Encryption Control Protocol" },
+       {PPP_IPV6CP,    "IPv6 Control Protocol" },
        {PPP_MUXCP,     "PPPMux Control Protocol"},
+       {PPP_STAMPEDECP,"Stampede Bridging Control Protocol" },
+       {PPP_MPPCP,     "MP+ Contorol Protocol" },
+       {PPP_IPICP,     "NTCITS IPI Control Protocol" },
+       {PPP_SLCC,      "single link compression in multilink control" },
        {PPP_CCP,       "Compression Control Protocol" },
+       {PPP_CDPCP,     "CDP Control Protocol" },
+       {PPP_NETCSCP,   "Netcs Twin Routing" },
+       {PPP_STPCP,     "STP - Control Protocol" },
+       {PPP_EDPCP,     "EDP Control Protocol" },
+       {PPP_ACSPC,     "Apple Client Server Protocol Control" },
+       {PPP_MPLSCP,    "MPLS Control Protocol" },
+       {PPP_P12844CP,  "IEEE p1284.4 standard - Protocol Control" },
+       {PPP_ETSICP,    "ETSI TETRA TNP1 Control Protocol" },
+       {PPP_MFTPCP,    "Multichannel Flow Treatment Protocol" },
        {PPP_LCP,       "Link Control Protocol" },
        {PPP_PAP,       "Password Authentication Protocol"  },
        {PPP_LQR,       "Link Quality Report protocol" },
        {PPP_SPAP,      "Shiva Password Authentication Protocol" },
-       {PPP_CHAP,      "Cryptographic Handshake Auth. Protocol" },
-       {PPP_EAP,       "Extensible Authentication Protocol" },
        {PPP_CBCP,      "Callback Control Protocol" },
        {PPP_BACP,      "Bandwidth Allocation Control Protocol" },
        {PPP_BAP,       "Bandwitdh Allocation Protocol" },
+       {PPP_CONTCP,    "Container Control Protocol" },
+       {PPP_CHAP,      "Challenge Handshake Authentication Protocol" },
+       {PPP_RSAAP,     "RSA Authentication Protocol" },
+       {PPP_EAP,       "Extensible Authentication Protocol" },
+       {PPP_SIEP,      "Mitsubishi Security Information Exchange Protocol"},
+       {PPP_SBAP,      "Stampede Bridging Authorization Protocol" },
+       {PPP_PRPAP,     "Proprietary Authentication Protocol" },
+       {PPP_PRPAP2,    "Proprietary Authentication Protocol" },
+       {PPP_PRPNIAP,   "Proprietary Node ID Authentication Protocol" },
        {0,             NULL            }
 };
 
 /* CP (LCP, IPCP, etc.) codes.
- * from pppd fsm.h 
+ * from pppd fsm.h
  */
 #define CONFREQ    1  /* Configuration Request */
 #define CONFACK    2  /* Configuration Ack */
@@ -232,7 +342,7 @@ static const value_string cp_vals[] = {
 #define IDENT      12 /* Identification */
 #define TIMEREMAIN 13 /* Time remaining */
 
-/* 
+/*
  * CCP-specific packet types.
  */
 #define RESETREQ   14  /* Reset Request */
@@ -286,14 +396,14 @@ static const value_string ccp_vals[] = {
        {CODEREJ,    "Code Reject" },
        {RESETREQ,   "Reset Request" },
        {RESETACK,   "Reset Ack" },
-       {0,          NULL } 
+       {0,          NULL }
 };
 
 static const value_string cbcp_vals[] = {
        {CBREQ,      "Callback Request" },
        {CBRES,      "Callback Response" },
        {CBACK,      "Callback Ack" },
-       {0,          NULL } 
+       {0,          NULL }
 };
 
 static const value_string bap_vals[] = {
@@ -353,7 +463,7 @@ static const value_string bap_phone_delta_subopt_vals[] = {
 /*
  * Cause codes for Cause.
  *
- * The following code table is taken from packet-q931.c but is slightly 
+ * The following code table is taken from packet-q931.c but is slightly
  * adapted to BAP protocol.
  */
 static const value_string q931_cause_code_vals[] = {
@@ -757,7 +867,7 @@ static const ip_tcp_opt lcp_opts[] = {
 
 #define N_LCP_OPTS     (sizeof lcp_opts / sizeof lcp_opts[0])
 
-/* 
+/*
  * CHAP Algorithms
  */
 #define CHAP_ALG_MD5   0x05    /* CHAP with MD5 */
@@ -879,7 +989,7 @@ static const ip_tcp_opt ipcp_opts[] = {
 #define CI_CCP_RESERVED        255     /* Reserved (RFC1962) */
 
 /*
- * Microsoft Point-To-Point Compression (MPPC) and Encryption (MPPE) 
+ * Microsoft Point-To-Point Compression (MPPC) and Encryption (MPPE)
  * supported bits.
  */
 #define MPPC_SUPPORTED_BITS_C  0x00000001      /* MPPC negotiation */
@@ -974,7 +1084,7 @@ static const ip_tcp_opt ccp_opts[] = {
  */
 #define CI_CBCP_NO_CALLBACK    1  /* No callback */
 #define CI_CBCP_CB_USER                2  /* Callback to a user-specified number */
-#define CI_CBCP_CB_PRE         3  /* Callback to a pre-specified or 
+#define CI_CBCP_CB_PRE         3  /* Callback to a pre-specified or
                                             administrator specified number */
 #define CI_CBCP_CB_ANY         4  /* Callback to any of a list of numbers */
 
@@ -1129,7 +1239,7 @@ static const ip_tcp_opt bap_opts[] = {
 
 #define N_BAP_OPTS     (sizeof bap_opts / sizeof bap_opts[0])
 
-static void dissect_ppp(tvbuff_t *tvb, packet_info *pinfo, 
+static void dissect_ppp(tvbuff_t *tvb, packet_info *pinfo,
     proto_tree *tree);
 
 static const value_string pap_vals[] = {
@@ -1183,6 +1293,38 @@ static const ip_tcp_opt pppmuxcp_opts[] = {
 
 #define N_PPPMUXCP_OPTS (sizeof pppmuxcp_opts / sizeof pppmuxcp_opts[0])
 
+/*
+ * Options.  (IPv6CP)
+ */
+#define CI_IPV6CP_IF_TOKEN     1       /* Interface Token (RFC 2472) */
+#define CI_IPV6CP_COMPRESSTYPE 2       /* Compression Type (RFC 2472) */
+
+static void dissect_ipv6cp_if_token_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
+                       int offset, guint length, packet_info *pinfo,
+                       proto_tree *tree);
+
+static const ip_tcp_opt ipv6cp_opts[] = {
+       {
+               CI_IPV6CP_IF_TOKEN,
+               "Interface Token",
+               &ett_ipv6cp_if_token_opt,
+               FIXED_LENGTH,
+               10,
+               dissect_ipv6cp_if_token_opt
+       },
+       {
+               CI_COMPRESSTYPE,
+               "IPv6 compression protocol",
+               &ett_ipcp_compressprot_opt,
+               VARIABLE_LENGTH,
+               4,
+               dissect_lcp_protocol_opt
+       },
+};
+
+#define N_IPV6CP_OPTS  (sizeof ipv6cp_opts / sizeof ipv6cp_opts[0])
+
+
 static const unsigned int fcstab_32[256] =
       {
       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
@@ -1285,7 +1427,7 @@ static const unsigned short fcstab_16[256] = {
         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
     };
-  
+
 /*
 *******************************************************************************
 * DETAILS : Calculate a new FCS-16 given the current FCS-16 and the new data.
@@ -1295,7 +1437,7 @@ static guint16
 fcs16(register guint16 fcs, tvbuff_t * tvbuff)
 {
     int offset = 0;
-    guint len = tvb_length(tvbuff);
+    guint len = tvb_length(tvbuff)-2;
     guint8 val;
 
     /* Check for Invalid Length */
@@ -1309,7 +1451,7 @@ fcs16(register guint16 fcs, tvbuff_t * tvbuff)
 
     return (fcs ^ 0xffff);
 }
-  
+
 /*
 *******************************************************************************
 * DETAILS : Calculate a new FCS-32 given the current FCS-32 and the new data.
@@ -1319,7 +1461,7 @@ static guint32
 fcs32(guint32 fcs, tvbuff_t * tvbuff)
 {
     int offset = 0;
-    guint len = tvb_length(tvbuff);
+    guint len = tvb_length(tvbuff)-4;
     guint8 val;
 
     /* Check for invalid Length */
@@ -1334,7 +1476,7 @@ fcs32(guint32 fcs, tvbuff_t * tvbuff)
 }
 
 void
-capture_ppp_hdlc( const u_char *pd, int offset, int len, packet_counts *ld ) {
+capture_ppp_hdlc( const guchar *pd, int offset, int len, packet_counts *ld ) {
   if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
     ld->other++;
     return;
@@ -1428,7 +1570,7 @@ dissect_lcp_protocol_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
   guint16 protocol;
   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);
@@ -1453,7 +1595,7 @@ dissect_lcp_authprot_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
   guint8 algorithm;
   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);
@@ -1467,9 +1609,9 @@ dissect_lcp_authprot_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
   if (length > 0) {
     if (protocol == PPP_CHAP) {
       algorithm = tvb_get_guint8(tvb, offset);
-      proto_tree_add_text(field_tree, tvb, offset, length, 
-                         "Algorithm: %s (0x%02x)", 
-                         val_to_str(algorithm, chap_alg_vals, "Unknown"), 
+      proto_tree_add_text(field_tree, tvb, offset, length,
+                         "Algorithm: %s (0x%02x)",
+                         val_to_str(algorithm, chap_alg_vals, "Unknown"),
                          algorithm);
       offset++;
     } else {
@@ -1496,7 +1638,7 @@ dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   proto_item *tf;
   proto_tree *field_tree = NULL;
   guint8 alternatives;
-  
+
   alternatives = tvb_get_guint8(tvb, offset + 2);
   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: 0x%02x",
          optp->name, alternatives);
@@ -1529,7 +1671,7 @@ dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 {
   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);
@@ -1563,7 +1705,7 @@ dissect_lcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
   proto_item *tf;
   proto_tree *field_tree = NULL;
   guint8 operation;
-  
+
   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);
@@ -1727,7 +1869,7 @@ dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   proto_item *tf;
   proto_tree *field_tree = NULL;
   guint32 charset;
-  
+
   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);
@@ -1753,7 +1895,7 @@ dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 {
   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);
@@ -1780,7 +1922,7 @@ static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 static void dissect_pppmuxcp_def_pid_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                        int offset, guint length, packet_info *pinfo _U_,
                        proto_tree *tree)
-{ 
+{
   pppmux_def_prot_id = tvb_get_ntohs(tvb, offset + 2);
   proto_tree_add_text(tree, tvb, offset + 2, length - 2, "%s: %s (0x%02x)",optp->name,
                      val_to_str(pppmux_def_prot_id, ppp_vals, "Unknown"), pppmux_def_prot_id);
@@ -1797,7 +1939,7 @@ dissect_ccp_stac_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   guint8 check_mode;
 
   if (length == 6) {
-    proto_tree_add_text(tree, tvb, offset, length, 
+    proto_tree_add_text(tree, tvb, offset, length,
                        "%s (Ascend Proprietary version)", optp->name);
     /* We don't know how to decode the following 4 octets, since
        there's no public document that describe their usage. */
@@ -1809,9 +1951,9 @@ dissect_ccp_stac_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                        "History Count: %u", tvb_get_ntohs(tvb, offset + 2));
     check_mode = tvb_get_guint8(tvb, offset + 4);
     proto_tree_add_text(field_tree, tvb, offset + 4, 1,
-                       "Check Mode: %s (0x%02X)", 
+                       "Check Mode: %s (0x%02X)",
                        val_to_str(check_mode, stac_checkmode_vals, "Unknown"),
-                       check_mode); 
+                       check_mode);
   }
 }
 
@@ -1825,26 +1967,26 @@ dissect_ccp_mppc_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   guint32 supported_bits;
 
   supported_bits = tvb_get_ntohl(tvb, offset + 2);
-  tf = proto_tree_add_text(tree, tvb, offset, length, 
+  tf = proto_tree_add_text(tree, tvb, offset, length,
              "%s: Supported Bits: 0x%08X", optp->name, supported_bits);
   flags_tree = proto_item_add_subtree(tf, *optp->subtree_index);
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPC_SUPPORTED_BITS_C, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPC_SUPPORTED_BITS_C, 8*4,
       "Desire to negotiate MPPC", "NO Desire to negotiate MPPC"));
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_D, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_D, 8*4,
       "Obsolete (should NOT be 1)", "Obsolete (should ALWAYS be 0)"));
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_L, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_L, 8*4,
       "40-bit encryption ON", "40-bit encryption OFF"));
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_S, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_S, 8*4,
       "128-bit encryption ON", "128-bit encryption OFF"));
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_M, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_M, 8*4,
       "56-bit encryption ON", "56-bit encryption OFF"));
   proto_tree_add_text(flags_tree, tvb, offset + 2, 4, "%s",
-      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_H, 8*4, 
+      decode_boolean_bitfield(supported_bits, MPPE_SUPPORTED_BITS_H, 8*4,
       "Stateless mode ON", "Stateless mode OFF"));
 }
 
@@ -1862,7 +2004,7 @@ dissect_ccp_bsdcomp_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
                      "Version: %u", tvb_get_guint8(tvb, offset + 2) >> 5);
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
-                     "Dict: %u bits", 
+                     "Dict: %u bits",
                      tvb_get_guint8(tvb, offset + 2) & 0x1f);
 }
 
@@ -1883,14 +2025,14 @@ dissect_ccp_lzsdcp_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                      "History Count: %u", tvb_get_ntohs(tvb, offset + 2));
   check_mode = tvb_get_guint8(tvb, offset + 4);
   proto_tree_add_text(field_tree, tvb, offset + 4, 1,
-                     "Check Mode: %s (0x%02X)", 
+                     "Check Mode: %s (0x%02X)",
                      val_to_str(check_mode, lzsdcp_checkmode_vals, "Unknown"),
-                     check_mode); 
+                     check_mode);
   process_mode = tvb_get_guint8(tvb, offset + 5);
   proto_tree_add_text(field_tree, tvb, offset + 5, 1,
-                     "Process Mode: %s (0x%02X)", 
+                     "Process Mode: %s (0x%02X)",
                      val_to_str(process_mode, lzsdcp_processmode_vals, "Unkown"),
-                     process_mode); 
+                     process_mode);
 }
 
 static void
@@ -1907,7 +2049,7 @@ dissect_ccp_mvrca_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
                      "Features: %u", tvb_get_guint8(tvb, offset + 2) >> 5);
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
-                     "Packet by Packet flag: %s", 
+                     "Packet by Packet flag: %s",
                      tvb_get_guint8(tvb, offset + 2) & 0x20 ? "true" : "false");
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
                      "History: %u", tvb_get_guint8(tvb, offset + 2) & 0x20);
@@ -1931,10 +2073,10 @@ dissect_ccp_deflate_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                      "Window: %u", hi_nibble(tvb_get_guint8(tvb, offset + 2)));
   method = lo_nibble(tvb_get_guint8(tvb, offset + 2));
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
-                     "Method: %s (0x%02x)", 
+                     "Method: %s (0x%02x)",
                      method == 0x08 ?  "zlib compression" : "other", method);
   proto_tree_add_text(field_tree, tvb, offset + 3, 1,
-                     "Sequence number check method: %u", 
+                     "Sequence number check method: %u",
                      tvb_get_guint8(tvb, offset + 2) & 0x03);
 }
 
@@ -1959,7 +2101,7 @@ dissect_cbcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   gint addr_len;
   guint8 buf[256];     /* Since length field in Callback Conf Option is
                           8 bits, 256-octet buf is large enough. */
-  
+
   tf = proto_tree_add_text(tree, tvb, offset, length, "%s", optp->name);
   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
 
@@ -1967,14 +2109,14 @@ dissect_cbcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                      "Callback delay: %u", tvb_get_guint8(tvb, offset + 2));
   offset += 3;
   length -= 3;
-  
+
   while (length > 0) {
-    ta = proto_tree_add_text(field_tree, tvb, offset, length, 
+    ta = proto_tree_add_text(field_tree, tvb, offset, length,
                             "Callback Address");
-    addr_type = tvb_get_guint8(tvb, offset); 
+    addr_type = tvb_get_guint8(tvb, offset);
     addr_tree = proto_item_add_subtree(tf, ett_cbcp_callback_opt_addr);
-    proto_tree_add_text(addr_tree, tvb, offset, 1, 
-                       "Address Type: %s (%u)", 
+    proto_tree_add_text(addr_tree, tvb, offset, 1,
+                       "Address Type: %s (%u)",
                        ((addr_type == 1) ? "PSTN/ISDN" : "Other"), addr_type);
     offset++;
     length--;
@@ -2044,13 +2186,13 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
   while (length > 0) {
     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, 
+    ti = proto_tree_add_text(field_tree, tvb, offset, subopt_len,
                "Sub-Option (%d byte%s)",
                subopt_len, plurality(subopt_len, "", "s"));
     suboption_tree = proto_item_add_subtree(ti, ett_bap_phone_delta_subopt);
 
     proto_tree_add_text(suboption_tree, tvb, offset, 1,
-       "Sub-Option Type: %s (%u)", 
+       "Sub-Option Type: %s (%u)",
        val_to_str(subopt_type, bap_phone_delta_subopt_vals, "Unknown"),
        subopt_type);
 
@@ -2059,17 +2201,17 @@ dissect_bap_phone_delta_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 
     switch (subopt_type) {
     case BAP_PHONE_DELTA_SUBOPT_UNIQ_DIGIT:
-      proto_tree_add_text(suboption_tree, tvb, offset + 2, 1, "Uniq Digit: %u", 
+      proto_tree_add_text(suboption_tree, tvb, offset + 2, 1, "Uniq Digit: %u",
                          tvb_get_guint8(tvb, offset + 2));
       break;
     case BAP_PHONE_DELTA_SUBOPT_SUBSC_NUM:
       tvb_get_nstringz0(tvb, offset + 2, subopt_len - 2, buf);
-      proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2, 
+      proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2,
                          "Subscriber Number: %s", buf);
       break;
     case BAP_PHONE_DELTA_SUBOPT_PHONENUM_SUBADDR:
       tvb_get_nstringz0(tvb, offset + 2, subopt_len - 2, buf);
-      proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2, 
+      proto_tree_add_text(suboption_tree, tvb, offset + 2, subopt_len - 2,
                          "Phone Number Sub Address: %s", buf);
       break;
     default:
@@ -2091,7 +2233,7 @@ dissect_bap_reason_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                           8 bits, 256-octets buf is large enough */
 
   tvb_get_nstringz0(tvb, offset + 2, length - 2, buf);
-  proto_tree_add_text(tree, tvb, offset, length, "%s: %s", 
+  proto_tree_add_text(tree, tvb, offset, length, "%s: %s",
                           optp->name, buf);
 }
 
@@ -2100,7 +2242,7 @@ dissect_bap_link_disc_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
                        int offset, guint length, packet_info *pinfo _U_,
                        proto_tree *tree)
 {
-  proto_tree_add_text(tree, tvb, offset, length, "%s: 0x%04x", 
+  proto_tree_add_text(tree, tvb, offset, length, "%s: 0x%04x",
                      optp->name, tvb_get_ntohs(tvb, offset + 2));
 }
 
@@ -2118,12 +2260,12 @@ dissect_bap_call_status_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
 
   status = tvb_get_guint8(tvb, offset + 2);
   proto_tree_add_text(field_tree, tvb, offset + 2, 1,
-      "Status: %s (0x%02x)", 
+      "Status: %s (0x%02x)",
       val_to_str(status, q931_cause_code_vals, "Unknown"), status);
 
   action = tvb_get_guint8(tvb, offset + 3);
   proto_tree_add_text(field_tree, tvb, offset + 3, 1,
-      "Action: %s (0x%02x)", 
+      "Action: %s (0x%02x)",
       val_to_str(action, bap_call_status_opt_action_vals, "Unknown"), action);
 }
 
@@ -2134,7 +2276,7 @@ dissect_cp( tvbuff_t *tvb, int proto_id, int proto_subtree_index,
        proto_tree *tree )
 {
   proto_item *ti;
-  proto_tree *fh_tree = NULL;
+  proto_tree *volatile fh_tree = NULL;
   proto_item *tf;
   proto_tree *field_tree;
 
@@ -2218,15 +2360,82 @@ dissect_cp( tvbuff_t *tvb, int proto_id, int proto_subtree_index,
 
     case PROTREJ:
       if(tree) {
-       protocol = tvb_get_ntohs(tvb, offset);
-       proto_tree_add_text(fh_tree, tvb, offset, 2, "Rejected protocol: %s (0x%04x)",
-               val_to_str(protocol, ppp_vals, "Unknown"), protocol);
+       volatile address save_dl_src;
+       volatile address save_dl_dst;
+       volatile address save_net_src;
+       volatile address save_net_dst;
+       volatile address save_src;
+       volatile address save_dst;
+       gboolean save_in_error_pkt;
+       tvbuff_t *next_tvb;
+
+       protocol = tvb_get_ntohs(tvb, offset);
+       proto_tree_add_text(fh_tree, tvb, offset, 2,
+                           "Rejected protocol: %s (0x%04x)",
+                           val_to_str(protocol, ppp_vals, "Unknown"),
+                           protocol);
        offset += 2;
        length -= 2;
-       if (length > 0)
-          proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
-                               length, plurality(length, "", "s"));
-               /* XXX - should be dissected as a PPP packet */
+       if (length > 0) {
+          proto_tree_add_text(fh_tree, tvb, offset, length,
+                             "Rejected packet (%d byte%s)",
+                             length, plurality(length, "", "s"));
+
+         /* Decode the rejected packet.
+
+            Set the columns non-writable, so that the packet list
+            shows this as an LCP packet, not as the type of packet
+            for which the LCP packet was generated. */
+         col_set_writable(pinfo->cinfo, FALSE);
+
+         /* Also, save the current values of the addresses, and restore
+            them when we're finished dissecting the contained packet, so
+            that the address columns in the summary don't reflect the
+            contained packet, but reflect this packet instead. */
+         save_dl_src = pinfo->dl_src;
+         save_dl_dst = pinfo->dl_dst;
+         save_net_src = pinfo->net_src;
+         save_net_dst = pinfo->net_dst;
+         save_src = pinfo->src;
+         save_dst = pinfo->dst;
+
+         /* Save the current value of the "we're inside an error packet"
+            flag, and set that flag; subdissectors may treat packets
+            that are the payload of error packets differently from
+            "real" packets. */
+         save_in_error_pkt = pinfo->in_error_pkt;
+         pinfo->in_error_pkt = TRUE;
+
+         /* Dissect the contained packet.
+            Catch ReportedBoundsError, and do nothing if we see it,
+            because it's not an error if the contained packet is short;
+            there's no guarantee that all of it was included.
+
+            XXX - should catch BoundsError, and re-throw it after cleaning
+            up. */
+         next_tvb = tvb_new_subset(tvb, offset, length, length);
+         TRY {
+           if (!dissector_try_port(ppp_subdissector_table, protocol,
+                                   next_tvb, pinfo, fh_tree)) {
+             call_dissector(data_handle, next_tvb, pinfo, fh_tree);
+           }
+         }
+         CATCH(ReportedBoundsError) {
+           ; /* do nothing */
+         }
+         ENDTRY;
+
+         /* Restore the "we're inside an error packet" flag. */
+         pinfo->in_error_pkt = save_in_error_pkt;
+
+         /* Restore the addresses. */
+         pinfo->dl_src = save_dl_src;
+         pinfo->dl_dst = save_dl_dst;
+         pinfo->net_src = save_net_src;
+         pinfo->net_dst = save_net_dst;
+         pinfo->src = save_src;
+         pinfo->dst = save_dst;
+        }
       }
       break;
 
@@ -2286,7 +2495,7 @@ dissect_ppp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
   next_tvb = tvb_new_subset(tvb, proto_len, -1, -1);
 
   /* do lookup with the subdissector table */
-  if (!dissector_try_port(subdissector_table, ppp_prot, next_tvb, pinfo, tree)) {
+  if (!dissector_try_port(ppp_subdissector_table, ppp_prot, next_tvb, pinfo, tree)) {
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
       col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x", ppp_prot);
     if (check_col(pinfo->cinfo, COL_INFO))
@@ -2296,6 +2505,13 @@ dissect_ppp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
   }
 }
 
+static void
+dissect_lcp_options(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  dissect_ip_tcp_options(tvb, 0, tvb_reported_length(tvb), lcp_opts, N_LCP_OPTS, 
+            -1, pinfo, tree);
+}
+
 static void
 dissect_lcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -2334,7 +2550,7 @@ dissect_bacp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 static void
 dissect_bap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-  
+
   proto_item *ti;
   proto_tree *fh_tree = NULL;
   proto_item *tf;
@@ -2371,7 +2587,7 @@ dissect_bap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   offset = 4;
   length -= 4;
 
-  if (type == BAP_CRES || type == BAP_CBRES || 
+  if (type == BAP_CRES || type == BAP_CBRES ||
       type == BAP_LDQRES || type == BAP_CSRES) {
     resp_code = tvb_get_guint8(tvb, offset);
     proto_tree_add_text(fh_tree, tvb, offset, 1, "Response Code: %s (0x%02x)",
@@ -2398,7 +2614,7 @@ dissect_comp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   proto_tree *comp_data_tree;
 
   if (check_col(pinfo->cinfo, COL_PROTOCOL))
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, 
+    col_set_str(pinfo->cinfo, COL_PROTOCOL,
                proto_get_protocol_short_name(proto_comp_data));
 
   if(check_col(pinfo->cinfo, COL_INFO))
@@ -2423,7 +2639,7 @@ dissect_pppmuxcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 #define PPPMUX_PFF_BIT_SET         0x80
 #define PPPMUX_LXT_BIT_SET         0x40
 
-static void 
+static void
 dissect_pppmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   proto_tree *mux_tree, *hdr_tree, *sub_tree, *flag_tree;
@@ -2432,26 +2648,26 @@ dissect_pppmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   guint8 flags, byte;
   guint16 length;
   static guint16 pid;
-  tvbuff_t *next_tvb;    
+  tvbuff_t *next_tvb;
   int offset = 0, length_remaining;
   int length_field = 0, pid_field = 0,hdr_length = 0;
-  
+
   if (check_col(pinfo->cinfo, COL_PROTOCOL))
     col_set_str(pinfo->cinfo,COL_PROTOCOL, "PPP PPPMux");
-       
+
   if (check_col(pinfo->cinfo, COL_INFO))
     col_set_str(pinfo->cinfo, COL_INFO, "PPP Multiplexing");
-       
+
   length_remaining = tvb_reported_length(tvb);
-  
+
   if (tree) {
     ti = proto_tree_add_item(tree, proto_pppmux, tvb, 0, -1, FALSE);
     mux_tree = proto_item_add_subtree(ti,ett_pppmux);
-    
+
     while (length_remaining > 0) {
-       
+
       flags = tvb_get_guint8(tvb,offset) & PPPMUX_FLAGS_MASK;
-      
+
       if (flags && PPPMUX_LXT_BIT_SET ) {
        length = tvb_get_ntohs(tvb,offset) & 0x3fff;
        length_field = 2;
@@ -2459,7 +2675,7 @@ dissect_pppmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        length = tvb_get_guint8(tvb,offset) & 0x3f;
        length_field = 1;
       }
-      
+
       if (flags && PPPMUX_PFF_BIT_SET) {
        byte = tvb_get_guint8(tvb,offset + length_field);
        if (byte && PFC_BIT) {            /* Compressed PID field*/
@@ -2471,54 +2687,67 @@ dissect_pppmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
       } else {
        if (!pid){       /*No Last PID, hence use the default */
-         if (pppmux_def_prot_id) 
+         if (pppmux_def_prot_id)
            pid = pppmux_def_prot_id;
        }
       }
-      
+
       hdr_length = length_field + pid_field;
-      
+
       ti = proto_tree_add_text(mux_tree, tvb, offset, length + length_field,
                               "PPPMux Sub-frame");
       sub_tree = proto_item_add_subtree(ti,ett_pppmux_subframe);
       sub_ti = proto_tree_add_text(sub_tree, tvb, offset,
                                   hdr_length,"Header field");
-      
+
       hdr_tree = proto_item_add_subtree(sub_ti,ett_pppmux_subframe_hdr);
       ti = proto_tree_add_text(hdr_tree, tvb, offset, length_field, "PFF/LXT: 0x%02X",
                               flags);
-      
+
       flag_tree = proto_item_add_subtree(ti,ett_pppmux_subframe_flags);
       proto_tree_add_text(flag_tree,tvb,offset,length_field,"%s",
                          decode_boolean_bitfield(flags,0x80,8,"PID Present","PID not present"));
       proto_tree_add_text(flag_tree,tvb,offset,length_field,"%s",
                          decode_boolean_bitfield(flags,0x40,8,"2 bytes ength field ","1 byte length field"));
-      
+
       ti = proto_tree_add_text(hdr_tree,tvb,offset,length_field,"Sub-frame Length = %u",length);
-      
+
       if (flags && PPPMUX_PFF_BIT_SET)
        proto_tree_add_text(hdr_tree,tvb,offset + length_field,pid_field,"%s: %s(0x%02x)",
                            "Protocol ID",val_to_str(pid,ppp_vals,"Unknown"), pid);
-      
+
       offset += hdr_length;
       length_remaining -= hdr_length;
       length -= pid_field;
-      
+
       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);
-      
-      next_tvb = tvb_new_subset(tvb,offset,length,-1); 
-      
-      if (!dissector_try_port(subdissector_table, pid, next_tvb, pinfo, info_tree)) {
+
+      next_tvb = tvb_new_subset(tvb,offset,length,-1);
+
+      if (!dissector_try_port(ppp_subdissector_table, pid, next_tvb, pinfo, info_tree)) {
        call_dissector(data_handle, next_tvb, pinfo, info_tree);
       }
       offset += length;
       length_remaining -= length;
     }  /* While length_remaining */
-    pid = 0; 
-  } /* if tree */  
+    pid = 0;
+  } /* if tree */
 }
 
+static void
+dissect_mplscp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  dissect_cp(tvb, proto_mplscp, ett_mplscp, cp_vals, ett_mplscp_options,
+            NULL, 0, pinfo, tree);
+}
+
+static void
+dissect_cdpcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  dissect_cp(tvb, proto_cdpcp, ett_cdpcp, cp_vals, ett_cdpcp_options,
+            NULL, 0, pinfo, tree);
+}
 
 #define MP_FRAG_MASK     0xC0
 #define MP_FRAG(bits)    ((bits) & MP_FRAG_MASK)
@@ -2706,7 +2935,7 @@ dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
        * Compute the FCS and put it into the tree.
        */
       rx_fcs_offset = proto_offset + len;
-      rx_fcs_exp = fcs16(0xFFFF, next_tvb);
+      rx_fcs_exp = fcs16(0xFFFF, tvb);
       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,
@@ -2758,7 +2987,7 @@ dissect_ppp_hdlc( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
        * Compute the FCS and put it into the tree.
        */
       rx_fcs_offset = proto_offset + len;
-      rx_fcs_exp = fcs32(0xFFFFFFFF, next_tvb);
+      rx_fcs_exp = fcs32(0xFFFFFFFF, tvb);
       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,
@@ -2932,26 +3161,26 @@ 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 (%d byte%s)", length,
                                   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; 
+         name_length = length - value_size - 1;
          tv = proto_tree_add_text(field_tree, tvb, offset, 1,
-                                  "Value Size: %d byte%s", 
+                                  "Value Size: %d byte%s",
                                   value_size, plurality(value_size, "", "s"));
          if (--length > 0) {
            value_tree = proto_item_add_subtree(tv, ett_chap_value);
-           proto_tree_add_text(value_tree, tvb, ++offset, 
+           proto_tree_add_text(value_tree, tvb, ++offset,
                                ppp_min(value_size, length),
-                               "Value (%d byte%s)", 
+                               "Value (%d 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, 
+             proto_tree_add_text(field_tree, tvb, offset,
                                  ppp_min(name_length, length),
-                                 "Name (%d byte%s)", name_length, 
+                                 "Name (%d byte%s)", name_length,
                                  plurality(name_length, "", "s"));
            }
          }
@@ -2964,11 +3193,11 @@ 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 (%d 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: %d byte%s",
                                   length, plurality(length, "", "s"));
        }
       }
@@ -2981,6 +3210,29 @@ dissect_chap( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
   }
 }
 
+static void
+dissect_ipv6cp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  dissect_cp(tvb, proto_ipv6cp, ett_ipv6cp, cp_vals, ett_ipv6cp_options,
+            ipv6cp_opts, N_IPV6CP_OPTS, pinfo, tree);
+}
+
+static void dissect_ipv6cp_if_token_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
+                       int offset, guint length, packet_info *pinfo _U_,
+                       proto_tree *tree)
+{
+  proto_tree_add_text(tree, tvb, offset, length, "%s: %x:%x:%x:%x:%x:%x:%x:%x",
+                     optp->name,
+                     tvb_get_guint8(tvb, offset + 2),
+                     tvb_get_guint8(tvb, offset + 3),
+                     tvb_get_guint8(tvb, offset + 4),
+                     tvb_get_guint8(tvb, offset + 5),
+                     tvb_get_guint8(tvb, offset + 6),
+                     tvb_get_guint8(tvb, offset + 7),
+                     tvb_get_guint8(tvb, offset + 8),
+                     tvb_get_guint8(tvb, offset + 9)
+                     );
+}
 
 void
 proto_register_ppp(void)
@@ -3016,10 +3268,11 @@ proto_register_ppp(void)
   proto_register_subtree_array(ett, array_length(ett));
 
 /* subdissector code */
-  subdissector_table = register_dissector_table("ppp.protocol",
+  ppp_subdissector_table = register_dissector_table("ppp.protocol",
        "PPP protocol", FT_UINT16, BASE_HEX);
 
   register_dissector("ppp_hdlc", dissect_ppp_hdlc, proto_ppp);
+  register_dissector("ppp_lcp_options", dissect_lcp_options, proto_ppp);
   register_dissector("ppp", dissect_ppp, proto_ppp);
 
   /* Register the preferences for the ppp protocol */
@@ -3188,7 +3441,7 @@ proto_register_ccp(void)
     &ett_ccp_deflate_opt,
   };
 
-  proto_ccp = proto_register_protocol("PPP Compression Control Protocol", 
+  proto_ccp = proto_register_protocol("PPP Compression Control Protocol",
                                      "PPP CCP", "ccp");
   proto_register_subtree_array(ett, array_length(ett));
 }
@@ -3218,7 +3471,7 @@ proto_register_cbcp(void)
     &ett_cbcp_callback_opt_addr
   };
 
-  proto_cbcp = proto_register_protocol("PPP Callback Control Protocol", 
+  proto_cbcp = proto_register_protocol("PPP Callback Control Protocol",
                                      "PPP CBCP", "cbcp");
   proto_register_subtree_array(ett, array_length(ett));
 }
@@ -3247,7 +3500,7 @@ proto_register_bacp(void)
     &ett_bacp_favored_peer_opt
   };
 
-  proto_bacp = proto_register_protocol("PPP Bandwidth Allocation Control Protocol", 
+  proto_bacp = proto_register_protocol("PPP Bandwidth Allocation Control Protocol",
                                      "PPP BACP", "bacp");
   proto_register_subtree_array(ett, array_length(ett));
 }
@@ -3279,7 +3532,7 @@ proto_register_bap(void)
     &ett_bap_call_status_opt
   };
 
-  proto_bap = proto_register_protocol("PPP Bandwidth Allocation Protocol", 
+  proto_bap = proto_register_protocol("PPP Bandwidth Allocation Protocol",
                                      "PPP BAP", "bap");
   proto_register_subtree_array(ett, array_length(ett));
 }
@@ -3332,10 +3585,10 @@ proto_register_pap(void)
 {
   static gint *ett[] = {
     &ett_pap,
-       &ett_pap_data,
-       &ett_pap_peer_id,
-       &ett_pap_password,
-       &ett_pap_message,
+    &ett_pap_data,
+    &ett_pap_peer_id,
+    &ett_pap_password,
+    &ett_pap_message,
   };
 
   proto_pap = proto_register_protocol("PPP Password Authentication Protocol", "PPP PAP",
@@ -3397,7 +3650,7 @@ proto_register_pppmuxcp(void)
     &ett_pppmuxcp_options,
   };
 
-  proto_pppmuxcp = proto_register_protocol("PPPMux Control Protocol", 
+  proto_pppmuxcp = proto_register_protocol("PPPMux Control Protocol",
                                       "PPP PPPMuxCP",
                                      "pppmuxcp");
   proto_register_subtree_array(ett, array_length(ett));
@@ -3406,9 +3659,9 @@ proto_register_pppmuxcp(void)
 
 void
 proto_reg_handoff_pppmuxcp(void)
-{ 
-  dissector_handle_t muxcp_handle; 
+{
+  dissector_handle_t muxcp_handle;
+
   muxcp_handle = create_dissector_handle(dissect_pppmuxcp, proto_pppmuxcp);
   dissector_add("ppp.protocol", PPP_MUXCP, muxcp_handle);
 
@@ -3420,34 +3673,120 @@ proto_reg_handoff_pppmuxcp(void)
 }
 
 
-void 
-proto_register_pppmux(void) 
-{ 
-  static gint *ett[] = { 
-    &ett_pppmux, 
-    &ett_pppmux_subframe, 
-    &ett_pppmux_subframe_hdr, 
-    &ett_pppmux_subframe_flags, 
-    &ett_pppmux_subframe_info, 
-  }; 
-  proto_pppmux = proto_register_protocol("PPP Multiplexing",  
-                                      "PPP PPPMux", 
-                                     "pppmux"); 
-  proto_register_subtree_array(ett, array_length(ett)); 
-} 
-void 
-proto_reg_handoff_pppmux(void) 
-{ 
-  dissector_handle_t pppmux_handle; 
-  pppmux_handle = create_dissector_handle(dissect_pppmux, proto_pppmux); 
-  dissector_add("ppp.protocol", PPP_MUX, pppmux_handle); 
-  /* 
-   * See above comment about NDISWAN for an explanation of why we're 
-   * registering with the "ethertype" dissector table. 
-   */ 
-  dissector_add("ethertype", PPP_MUX, pppmux_handle); 
-} 
+void
+proto_register_pppmux(void)
+{
+  static gint *ett[] = {
+    &ett_pppmux,
+    &ett_pppmux_subframe,
+    &ett_pppmux_subframe_hdr,
+    &ett_pppmux_subframe_flags,
+    &ett_pppmux_subframe_info,
+  };
+
+  proto_pppmux = proto_register_protocol("PPP Multiplexing",
+                                      "PPP PPPMux",
+                                     "pppmux");
+  proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_pppmux(void)
+{
+  dissector_handle_t pppmux_handle;
+
+  pppmux_handle = create_dissector_handle(dissect_pppmux, proto_pppmux);
+  dissector_add("ppp.protocol", PPP_MUX, pppmux_handle);
+
+  /*
+   * See above comment about NDISWAN for an explanation of why we're
+   * registering with the "ethertype" dissector table.
+   */
+  dissector_add("ethertype", PPP_MUX, pppmux_handle);
+}
+
+void
+proto_register_mplscp(void)
+{
+  static gint *ett[] = {
+    &ett_mplscp,
+    &ett_mplscp_options,
+  };
+
+  proto_mplscp = proto_register_protocol("PPP MPLS Control Protocol",
+                                        "PPP MPLSCP", "mplscp");
+  proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_mplscp(void)
+{
+  dissector_handle_t mplscp_handle;
+
+  mplscp_handle = create_dissector_handle(dissect_mplscp, proto_mplscp);
+  dissector_add("ppp.protocol", PPP_MPLSCP, mplscp_handle);
+
+  /*
+   * See above comment about NDISWAN for an explanation of why we're
+   * registering with the "ethertype" dissector table.
+   */
+  dissector_add("ethertype", PPP_MPLSCP, mplscp_handle);
+}
+
+void
+proto_register_cdpcp(void)
+{
+  static gint *ett[] = {
+    &ett_cdpcp,
+    &ett_cdpcp_options,
+  };
+
+  proto_cdpcp = proto_register_protocol("PPP CDP Control Protocol",
+                                        "PPP CDPCP", "cdpcp");
+  proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_cdpcp(void)
+{
+  dissector_handle_t cdpcp_handle;
+
+  cdpcp_handle = create_dissector_handle(dissect_cdpcp, proto_cdpcp);
+  dissector_add("ppp.protocol", PPP_CDPCP, cdpcp_handle);
+
+  /*
+   * See above comment about NDISWAN for an explanation of why we're
+   * registering with the "ethertype" dissector table.
+   */
+  dissector_add("ethertype", PPP_CDPCP, cdpcp_handle);
+}
+
+void
+proto_register_ipv6cp(void)
+{
+  static gint *ett[] = {
+    &ett_ipv6cp,
+    &ett_ipv6cp_options,
+    &ett_ipv6cp_if_token_opt,
+    &ett_ipv6cp_compressprot_opt,
+  };
+
+  proto_ipv6cp = proto_register_protocol("PPP IPv6 Control Protocol",
+                                        "PPP IPV6CP", "ipv6cp");
+  proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_ipv6cp(void)
+{
+  dissector_handle_t ipv6cp_handle;
+
+  ipv6cp_handle = create_dissector_handle(dissect_ipv6cp, proto_ipv6cp);
+  dissector_add("ppp.protocol", PPP_IPV6CP, ipv6cp_handle);
+
+  /*
+   * See above comment about NDISWAN for an explanation of why we're
+   * registering with the "ethertype" dissector table.
+   */
+  dissector_add("ethertype", PPP_IPV6CP, ipv6cp_handle);
+}