The function pointer in a "per_choice_t" or a "per_sequence_t" is to a
[obnox/wireshark/wip.git] / packet-eap.c
1 /* packet-eap.c
2  * Routines for EAP Extensible Authentication Protocol dissection
3  * RFC 2284
4  *
5  * $Id: packet-eap.c,v 1.35 2004/02/03 18:22:32 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/conversation.h>
33 #include "ppptypes.h"
34 #include "reassemble.h"
35
36 static int proto_eap = -1;
37 static int hf_eap_code = -1;
38 static int hf_eap_identifier = -1;
39 static int hf_eap_len = -1;
40 static int hf_eap_type = -1;
41 static int hf_eap_type_nak = -1;
42
43 static gint ett_eap = -1;
44
45 static dissector_handle_t ssl_handle;
46
47 #define EAP_REQUEST     1
48 #define EAP_RESPONSE    2
49 #define EAP_SUCCESS     3
50 #define EAP_FAILURE     4
51
52 static const value_string eap_code_vals[] = {
53     { EAP_REQUEST,  "Request" },
54     { EAP_RESPONSE, "Response" },
55     { EAP_SUCCESS,  "Success" },
56     { EAP_FAILURE,  "Failure" },
57     { 0,            NULL }
58 };
59
60 /*
61 References:
62   1) http://www.iana.org/assignments/ppp-numbers
63                         PPP EAP REQUEST/RESPONSE TYPES
64   2) http://www.ietf.org/internet-drafts/draft-ietf-pppext-rfc2284bis-02.txt
65   3) RFC2284
66 */
67
68 #define EAP_TYPE_ID     1
69 #define EAP_TYPE_NOTIFY 2
70 #define EAP_TYPE_NAK    3
71 #define EAP_TYPE_TLS    13
72 #define EAP_TYPE_LEAP   17
73 #define EAP_TYPE_TTLS   21
74
75 static const value_string eap_type_vals[] = {
76   {EAP_TYPE_ID,  "Identity [RFC2284]" },
77   {EAP_TYPE_NOTIFY,"Notification [RFC2284]" },
78   {EAP_TYPE_NAK, "Nak (Response only) [RFC2284]" },
79   {  4,          "MD5-Challenge [RFC2284]" },
80   {  5,          "One Time Password (OTP) [RFC2289]" },
81   {  6,          "Generic Token Card [RFC2284]" },
82   {  7,          "?? RESERVED ?? " }, /* ??? */
83   {  8,          "?? RESERVED ?? " }, /* ??? */
84   {  9,          "RSA Public Key Authentication [Whelan]" },
85   { 10,          "DSS Unilateral [Nace]" },
86   { 11,          "KEA [Nace]" },
87   { 12,          "KEA-VALIDATE [Nace]" },
88   {EAP_TYPE_TLS, "EAP-TLS [RFC2716] [Aboba]" },
89   { 14,          "Defender Token (AXENT) [Rosselli]" },
90   { 15,          "RSA Security SecurID EAP [Asnes, Liberman]" },
91   { 16,          "Arcot Systems EAP [Jerdonek]" },
92   {EAP_TYPE_LEAP,"EAP-Cisco Wireless (LEAP) [Norman]" },
93   { 18,          "Nokia IP smart card authentication [Haverinen]" },
94   { 19,          "SRP-SHA1 Part 1 [Carlson]" },
95   { 20,          "SRP-SHA1 Part 2 [Carlson]" },
96   {EAP_TYPE_TTLS,"EAP-TTLS [Funk]" },
97   { 22,          "Remote Access Service [Fields]" },
98   { 23,          "UMTS Authentication and Key Agreement [Haverinen]" },
99   { 24,          "EAP-3Com Wireless [Young]" },
100   { 25,          "PEAP [Palekar]" },
101   { 26,          "MS-EAP-Authentication [Palekar]" },
102   { 27,          "Mutual Authentication w/Key Exchange (MAKE)[Berrendonner]" },
103   { 28,          "CRYPTOCard [Webb]" },
104   { 29,          "EAP-MSCHAP-V2 [Potter]" },
105   { 30,          "DynamID [Merlin]" },
106   { 31,          "Rob EAP [Ullah]" },
107   { 32,          "SecurID EAP [Josefsson]" },
108   { 33,          "MS-Authentication-TLV [Palekar]" },
109   { 34,          "SentriNET [Kelleher]" },
110   { 35,          "EAP-Actiontec Wireless [Chang]" },
111   { 36,          "Cogent Systems Biometrics Authentication EAP [Xiong]" },
112   { 37,          "AirFortress EAP [Hibbard]" },
113   { 38,          "EAP-HTTP Digest [Tavakoli]" },
114   { 39,          "SecureSuite EAP [Clements]" },
115   { 40,          "DeviceConnect EAP [Pitard]" },
116   { 41,          "EAP-SPEKE [Zick]" },
117   { 255,         "Vendor-specific [draft-ietf-pppext-rfc2284bis-02.txt]" },
118   { 0,          NULL }
119
120 };
121
122 /*
123  * State information for EAP-TLS (RFC2716) and Lightweight EAP:
124  *
125  *      http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
126  *
127  * Attach to all conversations:
128  *
129  *      a sequence number to be handed to "fragment_add_seq()" as
130  *      the fragment sequence number - if it's -1, no reassembly
131  *      is in progress, but if it's not, it's the sequence number
132  *      to use for the current fragment;
133  *
134  *      a value to be handed to "fragment_add_seq()" as the
135  *      reassembly ID - when a reassembly is started, it's set to
136  *      the frame number of the current frame, i.e. the frame
137  *      that starts the reassembly;
138  *
139  *      an indication of the current state of LEAP negotiation,
140  *      with -1 meaning no LEAP negotiation is in progress.
141  *
142  * Attach to frames containing fragments of EAP-TLS messages the
143  * reassembly ID for those fragments, so we can find the reassembled
144  * data after the first pass through the packets.
145  *
146  * Attach to LEAP frames the state of the LEAP negotiation when the
147  * frame was processed, so we can properly dissect
148  * the LEAP message after the first pass through the packets.
149  *
150  * Attach to all conversations both pieces of information, to keep
151  * track of EAP-TLS reassembly and the LEAP state machine.
152  */
153 static GMemChunk *conv_state_chunk = NULL;
154
155 typedef struct {
156         int     eap_tls_seq;
157         guint32 eap_reass_cookie;
158         int     leap_state;
159 } conv_state_t;
160
161 static GMemChunk *frame_state_chunk = NULL;
162
163 typedef struct {
164         int     info;   /* interpretation depends on EAP message type */
165 } frame_state_t;
166
167 /*********************************************************************
168                            EAP-TLS
169 RFC2716
170 **********************************************************************/
171
172 /*
173 from RFC2716, pg 17
174
175    Flags
176
177       0 1 2 3 4 5 6 7 8
178       +-+-+-+-+-+-+-+-+
179       |L M S R R R R R|
180       +-+-+-+-+-+-+-+-+
181
182       L = Length included
183       M = More fragments
184       S = EAP-TLS start
185       R = Reserved
186 */
187
188 #define EAP_TLS_FLAG_L 0x80 /* Length included */
189 #define EAP_TLS_FLAG_M 0x40 /* More fragments  */
190 #define EAP_TLS_FLAG_S 0x20 /* EAP-TLS start   */
191
192 /*
193  * reassembly of EAP-TLS
194  */
195 static GHashTable *eaptls_fragment_table = NULL;
196
197 static int   hf_eaptls_fragment  = -1;
198 static int   hf_eaptls_fragments = -1;
199 static int   hf_eaptls_fragment_overlap = -1;
200 static int   hf_eaptls_fragment_overlap_conflict = -1;
201 static int   hf_eaptls_fragment_multiple_tails = -1;
202 static int   hf_eaptls_fragment_too_long_fragment = -1;
203 static int   hf_eaptls_fragment_error = -1;
204 static gint ett_eaptls_fragment  = -1;
205 static gint ett_eaptls_fragments = -1;
206
207 static const fragment_items eaptls_frag_items = {
208         &ett_eaptls_fragment,
209         &ett_eaptls_fragments,
210         &hf_eaptls_fragments,
211         &hf_eaptls_fragment,
212         &hf_eaptls_fragment_overlap,
213         &hf_eaptls_fragment_overlap_conflict,
214         &hf_eaptls_fragment_multiple_tails,
215         &hf_eaptls_fragment_too_long_fragment,
216         &hf_eaptls_fragment_error,
217         NULL,
218         "fragments"
219 };
220
221 /*********************************************************************
222 **********************************************************************/
223
224 static gboolean
225 test_flag(unsigned char flag, unsigned char mask)
226 {
227   return ( ( flag & mask ) != 0 );
228 }
229
230 static void
231 eaptls_defragment_init(void)
232 {
233   fragment_table_init(&eaptls_fragment_table);
234 }
235
236 static void
237 eap_init_protocol(void)
238 {
239   if (conv_state_chunk != NULL)
240     g_mem_chunk_destroy(conv_state_chunk);
241   if (frame_state_chunk != NULL)
242     g_mem_chunk_destroy(frame_state_chunk);
243
244   conv_state_chunk = g_mem_chunk_new("conv_state_chunk",
245                                      sizeof (conv_state_t),
246                                      10 * sizeof (conv_state_t),
247                                      G_ALLOC_ONLY);
248
249   frame_state_chunk = g_mem_chunk_new("frame_state_chunk",
250                                       sizeof (frame_state_t),
251                                      100 * sizeof (frame_state_t),
252                                      G_ALLOC_ONLY);
253 }
254
255 static int
256 dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
257                  gboolean fragmented)
258 {
259   guint8      eap_code;
260   guint8      eap_id;
261   guint16     eap_len;
262   guint8      eap_type;
263   gint        len;
264   conversation_t *conversation;
265   conv_state_t *conversation_state;
266   frame_state_t *packet_state;
267   int leap_state;
268   proto_tree *ti;
269   proto_tree *eap_tree = NULL;
270
271   if (check_col(pinfo->cinfo, COL_PROTOCOL))
272     col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP");
273   if (check_col(pinfo->cinfo, COL_INFO))
274     col_clear(pinfo->cinfo, COL_INFO);
275
276   eap_code = tvb_get_guint8(tvb, 0);
277
278   if (check_col(pinfo->cinfo, COL_INFO))
279     col_add_str(pinfo->cinfo, COL_INFO,
280                 val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)"));
281
282   /*
283    * Find a conversation to which we belong; create one if we don't find
284    * it.
285    *
286    * We use the source and destination addresses, and the *matched* port
287    * number, because if this is running over RADIUS, there's no guarantee
288    * that the source port number for request and the destination port
289    * number for replies will be the same in all messages - the client
290    * may use different port numbers for each request.
291    *
292    * We have to pair up the matched port number with the corresponding
293    * address; we determine which that is by comparing it with the
294    * destination port - if it matches, we matched on the destination
295    * port (this is a request), otherwise we matched on the source port
296    * (this is a reply).
297    *
298    * XXX - what if we're running over a TCP or UDP protocol with a
299    * heuristic dissector, meaning the matched port number won't be set?
300    *
301    * XXX - what if we have a capture file with captures on multiple
302    * PPP interfaces, with LEAP traffic on all of them?  How can we
303    * keep them separate?  (Or is that not going to happen?)
304    */
305   if (pinfo->destport == pinfo->match_port) {
306     conversation = find_conversation(&pinfo->dst, &pinfo->src,
307                                      pinfo->ptype, pinfo->destport,
308                                      0, NO_PORT_B);
309   } else {
310     conversation = find_conversation(&pinfo->src, &pinfo->dst,
311                                      pinfo->ptype, pinfo->srcport,
312                                      0, NO_PORT_B);
313   }
314   if (conversation == NULL) {
315     if (pinfo->destport == pinfo->match_port) {
316       conversation = conversation_new(&pinfo->dst, &pinfo->src,
317                                       pinfo->ptype, pinfo->destport,
318                                       0, NO_PORT2);
319     } else {
320       conversation = conversation_new(&pinfo->src, &pinfo->dst,
321                                       pinfo->ptype, pinfo->srcport,
322                                       0, NO_PORT2);
323     }
324   }
325
326   /*
327    * Get the state information for the conversation; attach some if
328    * we don't find it.
329    */
330   conversation_state = conversation_get_proto_data(conversation, proto_eap);
331   if (conversation_state == NULL) {
332     /*
333      * Attach state information to the conversation.
334      */
335     conversation_state = g_mem_chunk_alloc(conv_state_chunk);
336     conversation_state->eap_tls_seq = -1;
337     conversation_state->eap_reass_cookie = 0;
338     conversation_state->leap_state = -1;
339     conversation_add_proto_data(conversation, proto_eap, conversation_state);
340   }
341
342   /*
343    * Set this now, so that it gets remembered even if we throw an exception
344    * later.
345    */
346   if (eap_code == EAP_FAILURE)
347     conversation_state->leap_state = -1;
348
349   eap_id = tvb_get_guint8(tvb, 1);
350
351   eap_len = tvb_get_ntohs(tvb, 2);
352   len = eap_len;
353
354   if (fragmented) {
355     /*
356      * This is an EAP fragment inside, for example, RADIUS.  If we don't
357      * have all of the packet data, return the negative of the amount of
358      * additional data we need.
359      */
360     int reported_len = tvb_reported_length_remaining(tvb, 0);
361
362     if (reported_len < len)
363       return -(len - reported_len);
364   }
365
366   if (tree) {
367     ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE);
368     eap_tree = proto_item_add_subtree(ti, ett_eap);
369
370     proto_tree_add_uint(eap_tree, hf_eap_code, tvb, 0, 1, eap_code);
371   }
372
373   if (tree)
374     proto_tree_add_item(eap_tree, hf_eap_identifier, tvb, 1, 1, FALSE);
375
376   if (tree)
377     proto_tree_add_uint(eap_tree, hf_eap_len, tvb, 2, 2, eap_len);
378
379   switch (eap_code) {
380
381   case EAP_SUCCESS:
382   case EAP_FAILURE:
383     break;
384
385   case EAP_REQUEST:
386   case EAP_RESPONSE:
387     eap_type = tvb_get_guint8(tvb, 4);
388
389     if (check_col(pinfo->cinfo, COL_INFO))
390       col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
391                       val_to_str(eap_type, eap_type_vals,
392                                  "Unknown type (0x%02X)"));
393     if (tree)
394       proto_tree_add_uint(eap_tree, hf_eap_type, tvb, 4, 1, eap_type);
395
396     if (len > 5) {
397       int     offset = 5;
398       gint    size   = len - offset;
399
400       switch (eap_type) {
401       /*********************************************************************
402       **********************************************************************/
403       case EAP_TYPE_ID:
404         if (tree) {
405           proto_tree_add_text(eap_tree, tvb, offset, size,
406                               "Identity (%d byte%s): %s",
407                               size, plurality(size, "", "s"),
408                               tvb_format_text(tvb, offset, size));
409          }
410         if(!pinfo->fd->flags.visited)
411           conversation_state->leap_state = 0;
412         break;
413
414       /*********************************************************************
415       **********************************************************************/
416       case EAP_TYPE_NOTIFY:
417         if (tree) {
418           proto_tree_add_text(eap_tree, tvb, offset, size,
419                               "Notification (%d byte%s): %s",
420                               size, plurality(size, "", "s"),
421                               tvb_format_text(tvb, offset, size));
422         }
423         break;
424       /*********************************************************************
425       **********************************************************************/
426       case EAP_TYPE_NAK:
427         if (tree) {
428           proto_tree_add_item(eap_tree, hf_eap_type_nak, tvb,
429                               offset, 1, FALSE);
430         }
431         break;
432       /*********************************************************************
433                                   EAP-TLS
434       **********************************************************************/
435       case EAP_TYPE_TTLS:
436       case EAP_TYPE_TLS:
437         {
438         guint8 flags   = tvb_get_guint8(tvb, offset);
439         gboolean more_fragments;
440         gboolean has_length;
441         guint32 length;
442         int eap_tls_seq = -1;
443         guint32 eap_reass_cookie = 0;
444         gboolean needs_reassembly = FALSE;
445
446         more_fragments = test_flag(flags,EAP_TLS_FLAG_M);
447         has_length = test_flag(flags,EAP_TLS_FLAG_L);
448
449         /* Flags field, 1 byte */
450         if (tree)
451           proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(0x%X): %s%s%s",
452                               flags,
453                               has_length                      ? "Length ":"",
454                               more_fragments                  ? "More "  :"",
455                               test_flag(flags,EAP_TLS_FLAG_S) ? "Start " :"");
456         size--;
457         offset++;
458
459         /* Length field, 4 bytes, OPTIONAL. */
460         if ( has_length ) {
461           length = tvb_get_ntohl(tvb, offset);
462           if (tree)
463             proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",length);
464           size   -= 4;
465           offset += 4;
466         }
467
468         if (size>0) {
469
470           tvbuff_t *next_tvb;
471           gint tvb_len;
472           gboolean save_fragmented;
473
474           tvb_len = tvb_length_remaining(tvb, offset);
475           if (size < tvb_len)
476             tvb_len = size;
477
478             /*
479                EAP/TLS is weird protocol (it comes from
480                Microsoft after all).
481
482                If we have series of fragmented packets,
483                then there's no way of knowing that from
484                the packet itself, if it is the last packet
485                in series, that is that the packet part of
486                bigger fragmented set of data.
487
488                The only way to know is, by knowing
489                that we are already in defragmentation
490                "mode" and we are expecing packet
491                carrying fragment of data. (either
492                because we have not received expected
493                amount of data, or because the packet before
494                had "F"ragment flag set.)
495
496                The situation is alleviated by fact that it
497                is simple ack/nack protcol so there's no
498                place for out-of-order packets like it is
499                possible with IP.
500
501                Anyway, point of this lengthy essay is that
502                we have to keep state information in the
503                conversation, so that we can put ourselves in
504                defragmenting mode and wait for the last packet,
505                and have to attach state to frames as well, so
506                that we can handle defragmentation after the
507                first pass through the capture.
508             */
509           /* See if we have a remembered defragmentation EAP ID. */
510           packet_state = p_get_proto_data(pinfo->fd, proto_eap);
511           if (packet_state == NULL) {
512             /*
513              * We haven't - does this message require reassembly?
514              */
515             if (!pinfo->fd->flags.visited) {
516               /*
517                * This is the first time we've looked at this frame,
518                * so it wouldn't have any remembered information.
519                *
520                * Therefore, we check whether this conversation has
521                * a reassembly operation in progress, or whether
522                * this frame has the Fragment flag set.
523                */
524               if (conversation_state->eap_tls_seq != -1) {
525                 /*
526                  * There's a reassembly in progress; the sequence number
527                  * of the previous fragment is
528                  * "conversation_state->eap_tls_seq", and the reassembly
529                  * ID is "conversation_state->eap_reass_cookie".
530                  *
531                  * We must include this frame in the reassembly.
532                  * We advance the sequence number, giving us the
533                  * sequence number for this fragment.
534                  */
535                 needs_reassembly = TRUE;
536                 conversation_state->eap_tls_seq++;
537
538                 eap_reass_cookie = conversation_state->eap_reass_cookie;
539                 eap_tls_seq = conversation_state->eap_tls_seq;
540               } else if (more_fragments && has_length) {
541                 /*
542                  * This message has the Fragment flag set, so it requires
543                  * reassembly.  It's the message containing the first
544                  * fragment (if it's a later fragment, the sequence
545                  * number in the conversation state would not be -1).
546                  *
547                  * If it doesn't include a length, however, we can't
548                  * do reassembly (either the message is in error, as
549                  * the first fragment *must* contain a length, or we
550                  * didn't capture the first fragment, and this just
551                  * happens to be the first fragment we saw), so we
552                  * also check that we have a length;
553                  */
554                 needs_reassembly = TRUE;
555                 conversation_state->eap_reass_cookie = pinfo->fd->num;
556
557                 /*
558                  * Start the reassembly sequence number at 0.
559                  */
560                 conversation_state->eap_tls_seq = 0;
561
562                 eap_tls_seq = conversation_state->eap_tls_seq;
563                 eap_reass_cookie = conversation_state->eap_reass_cookie;
564               }
565
566               if (needs_reassembly) {
567                 /*
568                  * This frame requires reassembly; remember the reassembly
569                  * ID for subsequent accesses to it.
570                  */
571                 packet_state = g_mem_chunk_alloc(frame_state_chunk);
572                 packet_state->info = eap_reass_cookie;
573                 p_add_proto_data(pinfo->fd, proto_eap, packet_state);
574               }
575             }
576           } else {
577             /*
578              * This frame has a reassembly cookie associated with it, so
579              * it requires reassembly.  We've already done the
580              * reassembly in the first pass, so "fragment_add_seq()"
581              * won't look at the sequence number; set it to 0.
582              *
583              * XXX - a frame isn't supposed to have more than one
584              * EAP message in it, but if it includes both an EAP-TLS
585              * message and a LEAP message, we might be mistakenly
586              * concluding it requires reassembly because the "info"
587              * field isn't -1.  We could, I guess, pack both EAP-TLS
588              * ID and LEAP state into the structure, but that doesn't
589              * work if you have multiple EAP-TLS or LEAP messages in
590              * the frame.
591              *
592              * But it's not clear how much work we should do to handle
593              * a bogus message such as that; as long as we don't crash
594              * or do something else equally horrible, we may not
595              * have to worry about this at all.
596              */
597             needs_reassembly = TRUE;
598             eap_reass_cookie = packet_state->info;
599             eap_tls_seq = 0;
600           }
601
602           /*
603              We test here to see whether EAP-TLS packet
604              carry fragmented of TLS data.
605
606              If this is the case, we do reasembly below,
607              otherwise we just call dissector.
608           */
609           if (needs_reassembly) {
610             fragment_data   *fd_head = NULL;
611
612             /*
613              * Yes, this frame contains a fragment that requires
614              * reassembly.
615              */
616             save_fragmented = pinfo->fragmented;
617             pinfo->fragmented = TRUE;
618             fd_head = fragment_add_seq(tvb, offset, pinfo,
619                                    eap_reass_cookie,
620                                    eaptls_fragment_table,
621                                    eap_tls_seq,
622                                    size,
623                                    more_fragments);
624
625             if (fd_head != NULL)            /* Reassembled  */
626               {
627
628                 next_tvb = tvb_new_real_data(fd_head->data,
629                                              fd_head->len,
630                                              fd_head->len);
631                 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
632                 add_new_data_source(pinfo, next_tvb, "Reassembled EAP-TLS");
633
634                 show_fragment_seq_tree(fd_head, &eaptls_frag_items,
635                     eap_tree, pinfo, next_tvb);
636
637                 call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
638
639                 /*
640                  * We're finished reassembing this frame.
641                  * Reinitialize the reassembly state.
642                  */
643                 if (!pinfo->fd->flags.visited)
644                   conversation_state->eap_tls_seq = -1;
645               }
646
647             pinfo->fragmented = save_fragmented;
648
649           } else { /* this data is NOT fragmented */
650             next_tvb = tvb_new_subset(tvb, offset, tvb_len, size);
651             call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
652           }
653         }
654         }
655         break; /*  EAP_TYPE_TLS */
656       /*********************************************************************
657                                   Cisco's Lightweight EAP (LEAP)
658       http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
659       **********************************************************************/
660       case EAP_TYPE_LEAP:
661         {
662           guint8  field,count,namesize;
663
664           /* Version (byte) */
665           if (tree) {
666             field = tvb_get_guint8(tvb, offset);
667             proto_tree_add_text(eap_tree, tvb, offset, 1,
668                                 "Version: %i",field);
669           }
670           size--;
671           offset++;
672
673           /* Unused  (byte) */
674           if (tree) {
675             field = tvb_get_guint8(tvb, offset);
676             proto_tree_add_text(eap_tree, tvb, offset, 1,
677                                 "Reserved: %i",field);
678           }
679           size--;
680           offset++;
681
682           /* Count   (byte) */
683           count = tvb_get_guint8(tvb, offset);
684           if (tree) {
685             proto_tree_add_text(eap_tree, tvb, offset, 1,
686                                 "Count: %i",count);
687           }
688           size--;
689           offset++;
690
691           /* Data    (byte*Count) */
692           /* This part is state-dependent. */
693
694           /* See if we've already remembered the state. */
695           packet_state = p_get_proto_data(pinfo->fd, proto_eap);
696           if (packet_state == NULL) {
697             /*
698              * We haven't - compute the state based on the current
699              * state in the conversation.
700              */
701             leap_state = conversation_state->leap_state;
702
703             /* Advance the state machine. */
704             if (leap_state==0) leap_state =  1; else
705             if (leap_state==1) leap_state =  2; else
706             if (leap_state==2) leap_state =  3; else
707             if (leap_state==3) leap_state =  4; else
708             if (leap_state==4) leap_state = -1;
709
710             /*
711              * Remember the state for subsequent accesses to this
712              * frame.
713              */
714             packet_state = g_mem_chunk_alloc(frame_state_chunk);
715             packet_state->info = leap_state;
716             p_add_proto_data(pinfo->fd, proto_eap, packet_state);
717
718             /*
719              * Update the conversation's state.
720              */
721             conversation_state->leap_state = leap_state;
722           }
723
724           /* Get the remembered state. */
725           leap_state = packet_state->info;
726
727           if (tree) {
728
729             if        (leap_state==1) {
730               proto_tree_add_text(eap_tree, tvb, offset, count,
731                                   "Peer Challenge [8] Random Value:\"%s\"",
732                                   tvb_bytes_to_str(tvb, offset, count));
733             } else if (leap_state==2) {
734               proto_tree_add_text(eap_tree, tvb, offset, count,
735                                   "Peer Response [24] NtChallengeResponse(%s)",
736                                   tvb_bytes_to_str(tvb, offset, count));
737             } else if (leap_state==3) {
738               proto_tree_add_text(eap_tree, tvb, offset, count,
739                                   "AP Challenge [8] Random Value:\"%s\"",
740                                   tvb_bytes_to_str(tvb, offset, count));
741             } else if (leap_state==4) {
742               proto_tree_add_text(eap_tree, tvb, offset, count,
743                                   "AP Response [24] ChallengeResponse(%s)",
744                                   tvb_bytes_to_str(tvb, offset, count));
745             } else {
746               proto_tree_add_text(eap_tree, tvb, offset, count,
747                                 "Data (%d byte%s): \"%s\"",
748                                 count, plurality(count, "", "s"),
749                                 tvb_bytes_to_str(tvb, offset, count));
750             }
751
752           } /* END: if (tree) */
753
754
755           size   -= count;
756           offset += count;
757
758           /* Name    (Length-(8+Count)) */
759           namesize = eap_len - (8+count);
760           if (tree) {
761             proto_tree_add_text(eap_tree, tvb, offset, namesize,
762                                 "Name (%d byte%s): %s",
763                                 namesize, plurality(count, "", "s"),
764                                 tvb_format_text(tvb, offset, namesize));
765           }
766           size   -= namesize;
767           offset += namesize;
768         }
769
770         break; /* EAP_TYPE_LEAP */
771       /*********************************************************************
772       **********************************************************************/
773       default:
774         if (tree) {
775           proto_tree_add_text(eap_tree, tvb, offset, size,
776                               "Type-Data (%d byte%s) Value: %s",
777                               size, plurality(size, "", "s"),
778                               tvb_bytes_to_str(tvb, offset, size));
779         }
780         break;
781       /*********************************************************************
782       **********************************************************************/
783       } /* switch (eap_type) */
784
785     }
786
787   } /* switch (eap_code) */
788
789   return tvb_length(tvb);
790 }
791
792 static int
793 dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
794 {
795   return dissect_eap_data(tvb, pinfo, tree, FALSE);
796 }
797
798 static int
799 dissect_eap_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
800 {
801   return dissect_eap_data(tvb, pinfo, tree, TRUE);
802 }
803
804 void
805 proto_register_eap(void)
806 {
807   static hf_register_info hf[] = {
808         { &hf_eap_code, {
809                 "Code", "eap.code", FT_UINT8, BASE_DEC,
810                 VALS(eap_code_vals), 0x0, "", HFILL }},
811         { &hf_eap_identifier, {
812                 "Id", "eap.id", FT_UINT8, BASE_DEC,
813                 NULL, 0x0, "", HFILL }},
814         { &hf_eap_len, {
815                 "Length", "eap.len", FT_UINT16, BASE_DEC,
816                 NULL, 0x0, "", HFILL }},
817         { &hf_eap_type, {
818                 "Type", "eap.type", FT_UINT8, BASE_DEC,
819                 VALS(eap_type_vals), 0x0, "", HFILL }},
820         { &hf_eap_type_nak, {
821                 "Desired Auth Type", "eap.desired_type", FT_UINT8, BASE_DEC,
822                 VALS(eap_type_vals), 0x0, "", HFILL }},
823         { &hf_eaptls_fragment,
824           { "EAP-TLS Fragment", "eaptls.fragment",
825                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
826                 "EAP-TLS Fragment", HFILL }},
827         { &hf_eaptls_fragments,
828           { "EAP-TLS Fragments", "eaptls.fragments",
829                 FT_NONE, BASE_NONE, NULL, 0x0,
830                 "EAP-TLS Fragments", HFILL }},
831         { &hf_eaptls_fragment_overlap,
832           { "Fragment overlap", "eaptls.fragment.overlap",
833                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
834                 "Fragment overlaps with other fragments", HFILL }},
835         { &hf_eaptls_fragment_overlap_conflict,
836           { "Conflicting data in fragment overlap",     "eaptls.fragment.overlap.conflict",
837                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
838                 "Overlapping fragments contained conflicting data", HFILL }},
839         { &hf_eaptls_fragment_multiple_tails,
840           { "Multiple tail fragments found",    "eaptls.fragment.multipletails",
841                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
842                 "Several tails were found when defragmenting the packet", HFILL }},
843         { &hf_eaptls_fragment_too_long_fragment,
844           { "Fragment too long",        "eaptls.fragment.toolongfragment",
845                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
846                 "Fragment contained data past end of packet", HFILL }},
847         { &hf_eaptls_fragment_error,
848           { "Defragmentation error", "eaptls.fragment.error",
849                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
850                 "Defragmentation error due to illegal fragments", HFILL }},
851   };
852   static gint *ett[] = {
853         &ett_eap,
854         &ett_eaptls_fragment,
855         &ett_eaptls_fragments,
856   };
857
858   proto_eap = proto_register_protocol("Extensible Authentication Protocol",
859                                       "EAP", "eap");
860   proto_register_field_array(proto_eap, hf, array_length(hf));
861   proto_register_subtree_array(ett, array_length(ett));
862   register_init_routine(&eap_init_protocol);
863
864   new_register_dissector("eap", dissect_eap, proto_eap);
865   new_register_dissector("eap_fragment", dissect_eap_fragment, proto_eap);
866   register_init_routine(eaptls_defragment_init);
867 }
868
869 void
870 proto_reg_handoff_eap(void)
871 {
872   dissector_handle_t eap_handle;
873
874   /*
875    * Get a handle for the SSL/TLS dissector.
876    */
877   ssl_handle = find_dissector("ssl");
878
879   eap_handle = find_dissector("eap");
880   dissector_add("ppp.protocol", PPP_EAP, eap_handle);
881 }