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