Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-eap.c
index 3c22d00531c434a25627b6265cb0dbca611975ea..21944279f0f73189cb6d49ddd733a532c7643740 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for EAP Extensible Authentication Protocol dissection
  * RFC 2284
  *
- * $Id: packet-eap.c,v 1.13 2002/02/25 23:55:21 guy Exp $
+ * $Id: packet-eap.c,v 1.27 2002/08/02 23:35:49 jmayer Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
 #include <glib.h>
 #include <epan/packet.h>
-#include "packet-ieee8023.h"
-#include "packet-ipx.h"
-#include "packet-llc.h"
-#include "etypes.h"
+#include <epan/conversation.h>
 #include "ppptypes.h"
+#include "reassemble.h"
 
 static int proto_eap = -1;
 static int hf_eap_code = -1;
 static int hf_eap_identifier = -1;
 static int hf_eap_len = -1;
 static int hf_eap_type = -1;
+static int hf_eap_type_nak = -1;
 
 static gint ett_eap = -1;
 
@@ -66,58 +57,304 @@ static const value_string eap_code_vals[] = {
     { 0,            NULL }
 };
 
+/*
+References:
+  1) http://www.iana.org/assignments/ppp-numbers       
+                       PPP EAP REQUEST/RESPONSE TYPES
+  2) http://www.ietf.org/internet-drafts/draft-ietf-pppext-rfc2284bis-02.txt
+  3) RFC2284
+*/
+
+#define EAP_TYPE_ID     1
+#define EAP_TYPE_NOTIFY 2
+#define EAP_TYPE_NAK    3
 #define EAP_TYPE_TLS   13
+#define EAP_TYPE_LEAP  17
 
 static const value_string eap_type_vals[] = { 
-    { 1,            "Identity" },
-    { 2,            "Notification" },
-    { 3,            "Nak (Response only)" },
-    { 4,            "MD5-Challenge" },
-    { 5,            "One-Time Password (OTP) (RFC 1938)" },
-    { 6,            "Generic Token Card" },
-    { EAP_TYPE_TLS, "EAP/TLS (RFC2716)" },
-    { 0,            NULL }
+  {EAP_TYPE_ID,  "Identity [RFC2284]" },
+  {EAP_TYPE_NOTIFY,"Notification [RFC2284]" },
+  {EAP_TYPE_NAK, "Nak (Response only) [RFC2284]" },
+  {  4,          "MD5-Challenge [RFC2284]" },
+  {  5,          "One Time Password (OTP) [RFC2289]" },
+  {  6,          "Generic Token Card [RFC2284]" },
+  {  7,          "?? RESERVED ?? " }, /* ??? */
+  {  8,          "?? RESERVED ?? " }, /* ??? */
+  {  9,          "RSA Public Key Authentication [Whelan]" },
+  { 10,          "DSS Unilateral [Nace]" },
+  { 11,          "KEA [Nace]" },
+  { 12,          "KEA-VALIDATE [Nace]" },
+  {EAP_TYPE_TLS, "EAP-TLS [RFC2716] [Aboba]" },
+  { 14,          "Defender Token (AXENT) [Rosselli]" },
+  { 15,          "Windows 2000 EAP [Asnes]" },
+  { 16,          "Arcot Systems EAP [Jerdonek]" },
+  {EAP_TYPE_LEAP,"EAP-Cisco Wireless (LEAP) [Norman]" }, 
+  { 18,          "Nokia IP smart card authentication [Haverinen]" },  
+  { 19,          "SRP-SHA1 Part 1 [Carlson]" },
+  { 20,          "SRP-SHA1 Part 2 [Carlson]" },
+  { 21,          "EAP-TTLS [Funk]" },
+  { 22,          "Remote Access Service [Fields]" },
+  { 23,          "UMTS Authentication and Key Agreement [Haverinen]" }, 
+  { 24,          "EAP-3Com Wireless [Young]" }, 
+  { 25,          "PEAP [Palekar]" },
+  { 26,          "MS-EAP-Authentication [Palekar]" },
+  { 27,          "Mutual Authentication w/Key Exchange (MAKE)[Berrendonner]" },
+  { 28,          "CRYPTOCard [Webb]" },
+  { 29,          "EAP-MSCHAP-V2 [Potter]" },
+  { 30,          "DynamID [Merlin]" },
+  { 31,          "Rob EAP [Ullah]" },
+  { 32,          "SecurID EAP [Josefsson]" },
+  { 255,         "Vendor-specific [draft-ietf-pppext-rfc2284bis-02.txt]" },
+  { 0,          NULL }
+
+};
+
+/*
+ * State information for EAP-TLS (RFC2716) and Lightweight EAP:
+ *
+ *     http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
+ *
+ * Attach to all conversations:
+ *
+ *     a sequence number to be handed to "fragment_add_seq()" as
+ *     the fragment sequence number - if it's -1, no reassembly
+ *     is in progress, but if it's not, it's the sequence number
+ *     to use for the current fragment;
+ *
+ *     a value to be handed to "fragment_add_seq()" as the
+ *     reassembly ID - when a reassembly is started, it's set to
+ *     the frame number of the current frame, i.e. the frame
+ *     that starts the reassembly;
+ *
+ *     an indication of the current state of LEAP negotiation,
+ *     with -1 meaning no LEAP negotiation is in progress.
+ *
+ * Attach to frames containing fragments of EAP-TLS messages the
+ * reassembly ID for those fragments, so we can find the reassembled
+ * data after the first pass through the packets.
+ *
+ * Attach to LEAP frames the state of the LEAP negotiation when the
+ * frame was processed, so we can properly dissect
+ * the LEAP message after the first pass through the packets.
+ *
+ * Attach to all conversations both pieces of information, to keep
+ * track of EAP-TLS reassembly and the LEAP state machine.
+ */
+static GMemChunk *conv_state_chunk = NULL;
+
+typedef struct {
+       int     eap_tls_seq;
+       guint32 eap_reass_cookie;
+       int     leap_state;
+} conv_state_t;
+
+static GMemChunk *frame_state_chunk = NULL;
+
+typedef struct {
+       int     info;   /* interpretation depends on EAP message type */
+} frame_state_t;
+
+/*********************************************************************
+                           EAP-TLS 
+RFC2716
+**********************************************************************/
+
+/*
+from RFC2716, pg 17
+
+   Flags
+
+      0 1 2 3 4 5 6 7 8
+      +-+-+-+-+-+-+-+-+
+      |L M S R R R R R|
+      +-+-+-+-+-+-+-+-+
+
+      L = Length included
+      M = More fragments
+      S = EAP-TLS start
+      R = Reserved
+*/
+
+#define EAP_TLS_FLAG_L 0x80 /* Length included */
+#define EAP_TLS_FLAG_M 0x40 /* More fragments  */
+#define EAP_TLS_FLAG_S 0x20 /* EAP-TLS start   */
+
+/*
+ * reassembly of EAP-TLS
+ */
+static GHashTable *eaptls_fragment_table = NULL;
+
+static int   hf_eaptls_fragment  = -1;
+static int   hf_eaptls_fragments = -1;
+static int   hf_eaptls_fragment_overlap = -1;
+static int   hf_eaptls_fragment_overlap_conflict = -1;
+static int   hf_eaptls_fragment_multiple_tails = -1;
+static int   hf_eaptls_fragment_too_long_fragment = -1;
+static int   hf_eaptls_fragment_error = -1;
+static gint ett_eaptls_fragment  = -1;
+static gint ett_eaptls_fragments = -1;
+
+fragment_items eaptls_frag_items = {
+       &ett_eaptls_fragment,
+       &ett_eaptls_fragments,
+       &hf_eaptls_fragments,
+       &hf_eaptls_fragment,
+       &hf_eaptls_fragment_overlap,
+       &hf_eaptls_fragment_overlap_conflict,
+       &hf_eaptls_fragment_multiple_tails,
+       &hf_eaptls_fragment_too_long_fragment,
+       &hf_eaptls_fragment_error,
+       "fragments"
 };
 
+/*********************************************************************
+**********************************************************************/
+
+static gboolean
+test_flag(unsigned char flag, unsigned char mask) 
+{
+  return ( ( flag & mask ) != 0 );
+}
+
+static void
+eaptls_defragment_init(void)
+{
+  fragment_table_init(&eaptls_fragment_table);
+}
+
 static void
-dissect_eap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-               gboolean top_level)
+eap_init_protocol(void)
+{
+  if (conv_state_chunk != NULL)
+    g_mem_chunk_destroy(conv_state_chunk);
+  if (frame_state_chunk != NULL)
+    g_mem_chunk_destroy(frame_state_chunk);
+
+  conv_state_chunk = g_mem_chunk_new("conv_state_chunk",
+                                    sizeof (conv_state_t),
+                                    10 * sizeof (conv_state_t),
+                                    G_ALLOC_ONLY);
+
+  frame_state_chunk = g_mem_chunk_new("frame_state_chunk",
+                                     sizeof (frame_state_t),
+                                    100 * sizeof (frame_state_t),
+                                    G_ALLOC_ONLY);
+}
+
+static int
+dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+                gboolean fragmented)
 {
   guint8      eap_code;
   guint8      eap_id;
   guint16     eap_len;
   guint8      eap_type;
-  guint       len;
+  gint        len;
+  conversation_t *conversation;
+  conv_state_t *conversation_state;
+  frame_state_t *packet_state;
+  int leap_state;
   proto_tree *ti;
   proto_tree *eap_tree = NULL;
 
-  if (top_level) {
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-      col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP");
-    if (check_col(pinfo->cinfo, COL_INFO))
-      col_clear(pinfo->cinfo, COL_INFO);
-  }
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   eap_code = tvb_get_guint8(tvb, 0);
-  if (top_level) {
-    if (check_col(pinfo->cinfo, COL_INFO))
-      col_add_str(pinfo->cinfo, COL_INFO,
-                 val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)"));
+
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_str(pinfo->cinfo, COL_INFO,
+               val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)"));
+
+  /*
+   * Find a conversation to which we belong; create one if we don't find
+   * it.
+   *
+   * We use the source and destination addresses, and the *matched* port
+   * number, because if this is running over RADIUS, there's no guarantee
+   * that the source port number for request and the destination port
+   * number for replies will be the same in all messages - the client
+   * may use different port numbers for each request.
+   *
+   * We have to pair up the matched port number with the corresponding
+   * address; we determine which that is by comparing it with the
+   * destination port - if it matches, we matched on the destination
+   * port (this is a request), otherwise we matched on the source port
+   * (this is a reply).
+   *
+   * XXX - what if we're running over a TCP or UDP protocol with a
+   * heuristic dissector, meaning the matched port number won't be set?
+   *
+   * XXX - what if we have a capture file with captures on multiple
+   * PPP interfaces, with LEAP traffic on all of them?  How can we
+   * keep them separate?  (Or is that not going to happen?)
+   */
+  if (pinfo->destport == pinfo->match_port) {
+    conversation = find_conversation(&pinfo->dst, &pinfo->src,
+                                    pinfo->ptype, pinfo->destport,
+                                    0, NO_PORT_B);
+  } else {
+    conversation = find_conversation(&pinfo->src, &pinfo->dst,
+                                    pinfo->ptype, pinfo->srcport,
+                                    0, NO_PORT_B);
+  }
+  if (conversation == NULL) {
+    if (pinfo->destport == pinfo->match_port) {
+      conversation = conversation_new(&pinfo->dst, &pinfo->src,
+                                     pinfo->ptype, pinfo->destport,
+                                     0, NO_PORT2);
+    } else {
+      conversation = conversation_new(&pinfo->src, &pinfo->dst,
+                                     pinfo->ptype, pinfo->srcport,
+                                     0, NO_PORT2);
+    }
   }
 
+  /*
+   * Get the state information for the conversation; attach some if
+   * we don't find it.
+   */
+  conversation_state = conversation_get_proto_data(conversation, proto_eap);
+  if (conversation_state == NULL) {
+    /*
+     * Attach state information to the conversation.
+     */
+    conversation_state = g_mem_chunk_alloc(conv_state_chunk);
+    conversation_state->eap_tls_seq = -1;
+    conversation_state->eap_reass_cookie = 0;
+    conversation_state->leap_state = -1;
+    conversation_add_proto_data(conversation, proto_eap, conversation_state);
+  }
+
+  /*
+   * Set this now, so that it gets remembered even if we throw an exception
+   * later.
+   */
+  if (eap_code == EAP_FAILURE)
+    conversation_state->leap_state = -1;
+
+  eap_id = tvb_get_guint8(tvb, 1);
+
   eap_len = tvb_get_ntohs(tvb, 2);
   len = eap_len;
 
-  /* at least for now, until we get defragmentation support */
-  if (len>tvb_length(tvb))
-    len=tvb_length(tvb);
+  if (fragmented) {
+    /*
+     * This is an EAP fragment inside, for example, RADIUS.  If we don't
+     * have all of the packet data, return the negative of the amount of
+     * additional data we need.
+     */
+    int reported_len = tvb_reported_length_remaining(tvb, 0);
+
+    if (reported_len < len)
+      return -(len - reported_len);
+  }
 
   if (tree) {
-    if (top_level) {
-      ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE);
-      eap_tree = proto_item_add_subtree(ti, ett_eap);
-    } else
-      eap_tree = tree;
+    ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE);
+    eap_tree = proto_item_add_subtree(ti, ett_eap);
 
     proto_tree_add_uint(eap_tree, hf_eap_code, tvb, 0, 1, eap_code);
   }
@@ -130,74 +367,426 @@ dissect_eap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
   switch (eap_code) {
 
+  case EAP_SUCCESS:
+  case EAP_FAILURE:
+    break;
+
   case EAP_REQUEST:
   case EAP_RESPONSE:
     eap_type = tvb_get_guint8(tvb, 4);
-    if (top_level) {
-      if (check_col(pinfo->cinfo, COL_INFO))
-        col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
-                       val_to_str(eap_type, eap_type_vals,
-                                  "Unknown type (0x%02X)"));
-    }
-    if (tree) {
+
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+                     val_to_str(eap_type, eap_type_vals,
+                                "Unknown type (0x%02X)"));
+    if (tree)
       proto_tree_add_uint(eap_tree, hf_eap_type, tvb, 4, 1, eap_type);
 
-      if (len > 5) {
-       guint   offset = 5;
-       guint   size   = len - offset;
+    if (len > 5) {
+      int     offset = 5;
+      gint    size   = len - offset;
+
+      switch (eap_type) {
+      /*********************************************************************
+      **********************************************************************/
+      case EAP_TYPE_ID:
+       if (tree) {
+         proto_tree_add_text(eap_tree, tvb, offset, size, 
+                             "Identity (%d byte%s): %s",
+                             size, plurality(size, "", "s"),
+                             tvb_format_text(tvb, offset, size));
+         }
+       if(!pinfo->fd->flags.visited)
+         conversation_state->leap_state = 0;
+       break;
+
+      /*********************************************************************
+      **********************************************************************/
+      case EAP_TYPE_NOTIFY:
+       if (tree) {
+         proto_tree_add_text(eap_tree, tvb, offset, size, 
+                             "Notification (%d byte%s): %s",
+                             size, plurality(size, "", "s"),
+                             tvb_format_text(tvb, offset, size));
+       }
+       break;
+      /*********************************************************************
+      **********************************************************************/
+      case EAP_TYPE_NAK:
+       if (tree) {
+         proto_tree_add_uint(eap_tree, hf_eap_type_nak, tvb,
+                             offset, size, eap_type);
+       }
+       break;
+      /*********************************************************************
+                                  EAP-TLS
+      **********************************************************************/
+      case EAP_TYPE_TLS:
+       {
+       guint8 flags   = tvb_get_guint8(tvb, offset);
+       gboolean more_fragments;
+       gboolean has_length;
+       guint32 length;
+       int eap_tls_seq = -1;
+       guint32 eap_reass_cookie = 0;
+       gboolean needs_reassembly = FALSE;
+
+       more_fragments = test_flag(flags,EAP_TLS_FLAG_M);
+       has_length = test_flag(flags,EAP_TLS_FLAG_L);
+
+       /* Flags field, 1 byte */
+       if (tree)
+         proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(0x%X): %s%s%s",
+                             flags,
+                             has_length                      ? "Length ":"",
+                             more_fragments                  ? "More "  :"",
+                             test_flag(flags,EAP_TLS_FLAG_S) ? "Start " :"");
+       size--;
+       offset++;
+
+       /* Length field, 4 bytes, OPTIONAL. */
+       if ( has_length ) {
+         length = tvb_get_ntohl(tvb, offset);
+         if (tree)
+           proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",length);
+         size   -= 4;
+         offset += 4;
+       }
 
-       switch (eap_type) {
+       if (size>0) {
+
+         tvbuff_t *next_tvb;
+         gint tvb_len; 
+         gboolean save_fragmented;
+
+         tvb_len = tvb_length_remaining(tvb, offset);
+         if (size < tvb_len)
+           tvb_len = size;
+         
+           /* 
+              EAP/TLS is weird protocol (it comes from 
+              Microsoft after all). 
+
+              If we have series of fragmented packets,
+              then there's no way of knowing that from
+              the packet itself, if it is the last packet
+              in series, that is that the packet part of 
+              bigger fragmented set of data.
+
+              The only way to know is, by knowing
+              that we are already in defragmentation
+              "mode" and we are expecing packet
+              carrying fragment of data. (either 
+              because we have not received expected
+              amount of data, or because the packet before
+              had "F"ragment flag set.)
+
+              The situation is alleviated by fact that it 
+              is simple ack/nack protcol so there's no 
+              place for out-of-order packets like it is 
+              possible with IP. 
+
+              Anyway, point of this lengthy essay is that
+              we have to keep state information in the
+              conversation, so that we can put ourselves in 
+              defragmenting mode and wait for the last packet,
+              and have to attach state to frames as well, so
+              that we can handle defragmentation after the
+              first pass through the capture.
+           */
+         /* See if we have a remembered defragmentation EAP ID. */
+         packet_state = p_get_proto_data(pinfo->fd, proto_eap);
+         if (packet_state == NULL) {
+           /*
+            * We haven't - does this message require reassembly?
+            */
+           if (!pinfo->fd->flags.visited) {
+             /*
+              * This is the first time we've looked at this frame,
+              * so it wouldn't have any remembered information.
+              *
+              * Therefore, we check whether this conversation has
+              * a reassembly operation in progress, or whether
+              * this frame has the Fragment flag set.
+              */
+             if (conversation_state->eap_tls_seq != -1) {
+               /*
+                * There's a reassembly in progress; the sequence number
+                * of the previous fragment is
+                * "conversation_state->eap_tls_seq", and the reassembly
+                * ID is "conversation_state->eap_reass_cookie".
+                *
+                * We must include this frame in the reassembly.
+                * We advance the sequence number, giving us the
+                * sequence number for this fragment.
+                */
+               needs_reassembly = TRUE;
+               conversation_state->eap_tls_seq++;
+
+               eap_reass_cookie = conversation_state->eap_reass_cookie;
+               eap_tls_seq = conversation_state->eap_tls_seq;
+             } else if (more_fragments && has_length) {
+               /*
+                * This message has the Fragment flag set, so it requires
+                * reassembly.  It's the message containing the first
+                * fragment (if it's a later fragment, the sequence
+                * number in the conversation state would not be -1).
+                *
+                * If it doesn't include a length, however, we can't
+                * do reassembly (either the message is in error, as
+                * the first fragment *must* contain a length, or we
+                * didn't capture the first fragment, and this just
+                * happens to be the first fragment we saw), so we
+                * also check that we have a length;
+                */
+               needs_reassembly = TRUE;
+               conversation_state->eap_reass_cookie = pinfo->fd->num;
+
+               /*
+                * Start the reassembly sequence number at 0.
+                */
+               conversation_state->eap_tls_seq = 0;
+
+               eap_tls_seq = conversation_state->eap_tls_seq;
+               eap_reass_cookie = conversation_state->eap_reass_cookie;
+             }
+
+             if (needs_reassembly) {
+               /*
+                * This frame requires reassembly; remember the reassembly
+                * ID for subsequent accesses to it.
+                */
+               packet_state = g_mem_chunk_alloc(frame_state_chunk);
+               packet_state->info = eap_reass_cookie;
+               p_add_proto_data(pinfo->fd, proto_eap, packet_state);
+             }
+           }
+         } else {
+           /*
+            * This frame has a reassembly cookie associated with it, so
+            * it requires reassembly.  We've already done the
+            * reassembly in the first pass, so "fragment_add_seq()"
+            * won't look at the sequence number; set it to 0.
+            *
+            * XXX - a frame isn't supposed to have more than one
+            * EAP message in it, but if it includes both an EAP-TLS
+            * message and a LEAP message, we might be mistakenly
+            * concluding it requires reassembly because the "info"
+            * field isn't -1.  We could, I guess, pack both EAP-TLS
+            * ID and LEAP state into the structure, but that doesn't
+            * work if you have multiple EAP-TLS or LEAP messages in
+            * the frame.
+            *
+            * But it's not clear how much work we should do to handle
+            * a bogus message such as that; as long as we don't crash
+            * or do something else equally horrible, we may not
+            * have to worry about this at all.
+            */
+           needs_reassembly = TRUE;
+           eap_reass_cookie = packet_state->info;
+           eap_tls_seq = 0;
+         }
 
-       case EAP_TYPE_TLS:
-         {
-         guint8 flags = tvb_get_guint8(tvb, offset);
+         /* 
+            We test here to see whether EAP-TLS packet 
+            carry fragmented of TLS data. 
+
+            If this is the case, we do reasembly below,
+            otherwise we just call dissector.
+         */
+         if (needs_reassembly) {
+           fragment_data   *fd_head = NULL;
+
+           /*
+            * Yes, this frame contains a fragment that requires
+            * reassembly.
+            */
+           save_fragmented = pinfo->fragmented;
+           pinfo->fragmented = TRUE;
+           fd_head = fragment_add_seq(tvb, offset, pinfo, 
+                                  eap_reass_cookie,
+                                  eaptls_fragment_table,
+                                  eap_tls_seq, 
+                                  size,
+                                  more_fragments);
+
+           if (fd_head != NULL)            /* Reassembled  */
+             {
+
+               next_tvb = tvb_new_real_data(fd_head->data,
+                                            fd_head->len,
+                                            fd_head->len);
+               tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+               add_new_data_source(pinfo, next_tvb, "Reassembled EAP-TLS");
+
+               show_fragment_seq_tree(fd_head, &eaptls_frag_items,
+                   eap_tree, pinfo, next_tvb);
+
+               call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+
+               /*
+                * We're finished reassembing this frame.
+                * Reinitialize the reassembly state.
+                */
+               if (!pinfo->fd->flags.visited)
+                 conversation_state->eap_tls_seq = -1;
+             }
+
+           pinfo->fragmented = save_fragmented;
+                       
+         } else { /* this data is NOT fragmented */
+           next_tvb = tvb_new_subset(tvb, offset, tvb_len, size);
+           call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+         }
+       }
+       }
+       break; /*  EAP_TYPE_TLS */
+      /*********************************************************************
+                                  Cisco's Lightweight EAP (LEAP)
+      http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
+      **********************************************************************/
+      case EAP_TYPE_LEAP:
+       {
+         guint8  field,count,namesize;
+
+         /* Version (byte) */
+         if (tree) {
+           field = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(eap_tree, tvb, offset, 1, 
+                               "Version: %i",field);
+         }
+         size--;
+         offset++;
 
-         proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(%i): %s%s%s",
-                             flags,
-                             flags & 128 ? "Length " : "",
-                             flags &  64 ? "More " : "",
-                             flags &  32 ? "Start " : "");
+         /* Unused  (byte) */
+         if (tree) {
+           field = tvb_get_guint8(tvb, offset);
+           proto_tree_add_text(eap_tree, tvb, offset, 1, 
+                               "Reserved: %i",field);
+         }
          size--;
          offset++;
 
-         if (flags >> 7) {
-           guint32 length = tvb_get_ntohl(tvb, offset);
-           proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",
-                               length);
-           size   -= 4;
-           offset += 4;
+         /* Count   (byte) */
+         count = tvb_get_guint8(tvb, offset);
+         if (tree) {
+           proto_tree_add_text(eap_tree, tvb, offset, 1, 
+                               "Count: %i",count);
          }
+         size--;
+         offset++;
 
-         if (size>0) {
-           tvbuff_t   *next_tvb;
-           next_tvb = tvb_new_subset(tvb, offset, size, size);
-           call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+         /* Data    (byte*Count) */
+         /* This part is state-dependent. */
+
+         /* See if we've already remembered the state. */
+         packet_state = p_get_proto_data(pinfo->fd, proto_eap);
+         if (packet_state == NULL) {
+           /*
+            * We haven't - compute the state based on the current
+            * state in the conversation.
+            */
+           leap_state = conversation_state->leap_state;
+           
+           /* Advance the state machine. */
+           if (leap_state==0) leap_state =  1; else
+           if (leap_state==1) leap_state =  2; else
+           if (leap_state==2) leap_state =  3; else
+           if (leap_state==3) leap_state =  4; else
+           if (leap_state==4) leap_state = -1;
+
+           /*
+            * Remember the state for subsequent accesses to this
+            * frame.
+            */
+           packet_state = g_mem_chunk_alloc(frame_state_chunk);
+           packet_state->info = leap_state;
+           p_add_proto_data(pinfo->fd, proto_eap, packet_state);
+
+           /*
+            * Update the conversation's state.
+            */
+           conversation_state->leap_state = leap_state;
          }
+
+         /* Get the remembered state. */
+         leap_state = packet_state->info;
+
+         if (tree) { 
+
+           if        (leap_state==1) {
+             proto_tree_add_text(eap_tree, tvb, offset, count, 
+                                 "Peer Challenge [8] Random Value:\"%s\"",
+                                 tvb_bytes_to_str(tvb, offset, count));
+           } else if (leap_state==2) {
+             proto_tree_add_text(eap_tree, tvb, offset, count, 
+                                 "Peer Response [24] NtChallengeResponse(%s)",
+                                 tvb_bytes_to_str(tvb, offset, count));
+           } else if (leap_state==3) {
+             proto_tree_add_text(eap_tree, tvb, offset, count, 
+                                 "AP Challenge [8] Random Value:\"%s\"",
+                                 tvb_bytes_to_str(tvb, offset, count));
+           } else if (leap_state==4) {
+             proto_tree_add_text(eap_tree, tvb, offset, count, 
+                                 "AP Response [24] ChallengeResponse(%s)",
+                                 tvb_bytes_to_str(tvb, offset, count));
+           } else {
+             proto_tree_add_text(eap_tree, tvb, offset, count, 
+                               "Data (%d byte%s): \"%s\"",
+                               count, plurality(count, "", "s"),
+                               tvb_bytes_to_str(tvb, offset, count));
+           }
+
+         } /* END: if (tree) */
+
+
+         size   -= count;
+         offset += count;
+
+         /* Name    (Length-(8+Count)) */
+         namesize = eap_len - (8+count);
+         if (tree) {
+           proto_tree_add_text(eap_tree, tvb, offset, namesize, 
+                               "Name (%d byte%s): %s",
+                               namesize, plurality(count, "", "s"),
+                               tvb_format_text(tvb, offset, namesize));
          }
-         break;
+         size   -= namesize;
+         offset += namesize;
+       }
 
-       default:
+       break; /* EAP_TYPE_LEAP */
+      /*********************************************************************
+      **********************************************************************/
+      default:
+        if (tree) {
          proto_tree_add_text(eap_tree, tvb, offset, size, 
                              "Type-Data (%d byte%s) Value: %s",
                              size, plurality(size, "", "s"),
-                             tvb_format_text(tvb, offset, size));
-         break;
+                             tvb_bytes_to_str(tvb, offset, size));
        }
-      }
+       break;
+      /*********************************************************************
+      **********************************************************************/
+      } /* switch (eap_type) */
+
     }
-  }
+
+  } /* switch (eap_code) */
+
+  return tvb_length(tvb);
 }
 
-static void
+static int
 dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-  dissect_eap_pdu(tvb, pinfo, tree, TRUE);
+  return dissect_eap_data(tvb, pinfo, tree, FALSE);
 }
 
-static void
-dissect_encapsulated_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_eap_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-  dissect_eap_pdu(tvb, pinfo, tree, FALSE);
+  return dissect_eap_data(tvb, pinfo, tree, TRUE);
 }
 
 void
@@ -216,18 +805,53 @@ proto_register_eap(void)
        { &hf_eap_type, { 
                "Type", "eap.type", FT_UINT8, BASE_DEC, 
                VALS(eap_type_vals), 0x0, "", HFILL }},
+       { &hf_eap_type_nak, { 
+               "Desired Auth Type", "eap.type", FT_UINT8, BASE_DEC, 
+               VALS(eap_type_vals), 0x0, "", HFILL }},
+       { &hf_eaptls_fragment,
+         { "EAP-TLS Fragment", "eaptls.fragment", 
+               FT_NONE, BASE_NONE, NULL, 0x0,
+               "EAP-TLS Fragment", HFILL }},
+       { &hf_eaptls_fragments,
+         { "EAP-TLS Fragments", "eaptls.fragments", 
+               FT_NONE, BASE_NONE, NULL, 0x0,
+               "EAP-TLS Fragments", HFILL }},
+       { &hf_eaptls_fragment_overlap,
+         { "Fragment overlap", "eaptls.fragment.overlap",
+               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "Fragment overlaps with other fragments", HFILL }},
+       { &hf_eaptls_fragment_overlap_conflict,
+         { "Conflicting data in fragment overlap",     "eaptls.fragment.overlap.conflict",
+               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "Overlapping fragments contained conflicting data", HFILL }},
+       { &hf_eaptls_fragment_multiple_tails,
+         { "Multiple tail fragments found",    "eaptls.fragment.multipletails",
+               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "Several tails were found when defragmenting the packet", HFILL }},
+       { &hf_eaptls_fragment_too_long_fragment,
+         { "Fragment too long",        "eaptls.fragment.toolongfragment",
+               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+               "Fragment contained data past end of packet", HFILL }},
+       { &hf_eaptls_fragment_error,
+         { "Defragmentation error", "eaptls.fragment.error",
+               FT_NONE, BASE_NONE, NULL, 0x0,
+               "Defragmentation error due to illegal fragments", HFILL }},
   };
   static gint *ett[] = {
        &ett_eap,
+       &ett_eaptls_fragment,
+       &ett_eaptls_fragments,
   };
 
   proto_eap = proto_register_protocol("Extensible Authentication Protocol", 
                                      "EAP", "eap");
   proto_register_field_array(proto_eap, hf, array_length(hf));
   proto_register_subtree_array(ett, array_length(ett));
+  register_init_routine(&eap_init_protocol);
 
-  register_dissector("eap", dissect_eap, proto_eap);
-  register_dissector("eap_encap", dissect_encapsulated_eap, proto_eap);
+  new_register_dissector("eap", dissect_eap, proto_eap);
+  new_register_dissector("eap_fragment", dissect_eap_fragment, proto_eap);
+  register_init_routine(eaptls_defragment_init);
 }
 
 void