Add an additional "protocol index" argument to "{old_}dissector_add()",
[obnox/wireshark/wip.git] / packet-ieee80211.c
1 /* packet-ieee80211.c
2  * Routines for Wireless LAN (IEEE 802.11) dissection
3  * Copyright 2000, Axis Communications AB 
4  * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
5  *
6  * $Id: packet-ieee80211.c,v 1.9 2001/01/09 06:31:36 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@unicom.net>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from README.developer
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif
43
44 #ifdef NEED_SNPRINTF_H
45 # ifdef HAVE_STDARG_H
46 #  include <stdarg.h>
47 # else
48 #  include <varargs.h>
49 # endif
50 # include "snprintf.h"
51 #endif
52
53 #include <string.h>
54 #include <glib.h>
55 #include "bitswap.h"
56 #include "proto.h"
57 #include "etypes.h"
58 #include "packet.h"
59 #include "packet-llc.h"
60 #include "packet-ieee80211.h"
61
62 /* ************************************************************************* */
63 /*                          Miscellaneous Constants                          */
64 /* ************************************************************************* */
65 #define SHORT_STR 128
66 #define MGT_FRAME_LEN 24
67
68 /* ************************************************************************* */
69 /*  Define some very useful macros that are used to analyze frame types etc. */
70 /* ************************************************************************* */
71 #define COMPOSE_FRAME_TYPE(x) (((x & 0x0C)<< 2)+((x & 0xF0) >> 4))      /* Create key to (sub)type */
72 #define COOK_PROT_VERSION(x)  ((x & 0x3))
73 #define COOK_FRAME_TYPE(x)    ((x & 0xC) >> 2)
74 #define COOK_FRAME_SUBTYPE(x) ((x & 0xF0) >> 4)
75 #define COOK_ADDR_SELECTOR(x) (((x & 0x200) >> 8) + ((x & 0x100) >> 8))
76
77 #define COOK_FRAGMENT_NUMBER(x) (x & 0x000F)
78 #define COOK_SEQUENCE_NUMBER(x) ((x & 0xFFF0) >> 4)
79 #define COOK_FLAGS(x)           ((x & 0xFF00) >> 8)
80 #define COOK_DS_STATUS(x)       (x & 0x3)
81 #define COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \
82 col_add_str(fd,COL_INFO,info);
83
84 #define IS_TO_DS(x)            ((x & 0x100) >> 8)
85 #define IS_FROM_DS(x)          ((x & 0x200) >> 9)
86 #define HAVE_FRAGMENTS(x)      ((x & 0x400) >> 10)
87 #define IS_RETRY(x)            ((x & 0x800) >> 11)
88 #define POWER_MGT_STATUS(x)    ((x & 0x1000))
89 #define HAS_MORE_DATA(x)       ((x & 0x2000))
90 #define IS_WEP(x)              ((x & 0x4000))
91 #define IS_STRICTLY_ORDERED(x) ((x & 0x8000))
92
93 #define MGT_RESERVED_RANGE(x) (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F)))
94 #define CTRL_RESERVED_RANGE(x) ((x>=0x10)&&(x<=0x19))
95 #define DATA_RESERVED_RANGE(x) ((x>=0x28)&&(x<=0x2f))
96 #define SPEC_RESERVED_RANGE(x) ((x>=0x30)&&(x<=0x3f))
97
98
99 /* ************************************************************************* */
100 /*              Constants used to identify cooked frame types                */
101 /* ************************************************************************* */
102 #define MGT_FRAME            0x00       /* Frame type is management */
103 #define CONTROL_FRAME        0x01       /* Frame type is control */
104 #define DATA_FRAME           0x02       /* Frame type is Data */
105
106 #define DATA_SHORT_HDR_LEN     24
107 #define DATA_LONG_HDR_LEN      30
108 #define MGT_FRAME_HDR_LEN      24       /* Length of Managment frame-headers */
109 #define CTLR
110 #define MGT_ASSOC_REQ        0x00       /* Management - association request        */
111 #define MGT_ASSOC_RESP       0x01       /* Management - association response       */
112 #define MGT_REASSOC_REQ      0x02       /* Management - reassociation request      */
113 #define MGT_REASSOC_RESP     0x03       /* Management - reassociation response     */
114 #define MGT_PROBE_REQ        0x04       /* Management - Probe request              */
115 #define MGT_PROBE_RESP       0x05       /* Management - Probe response             */
116 #define MGT_BEACON           0x08       /* Management - Beacon frame               */
117 #define MGT_ATIM             0x09       /* Management - ATIM                       */
118 #define MGT_DISASS           0x0A       /* Management - Disassociation             */
119 #define MGT_AUTHENTICATION   0x0B       /* Management - Authentication             */
120 #define MGT_DEAUTHENTICATION 0x0C       /* Management - Deauthentication           */
121
122 #define CTRL_PS_POLL         0x1A       /* Control - power-save poll               */
123 #define CTRL_RTS             0x1B       /* Control - request to send               */
124 #define CTRL_CTS             0x1C       /* Control - clear to send                 */
125 #define CTRL_ACKNOWLEDGEMENT 0x1D       /* Control - acknowledgement               */
126 #define CTRL_CFP_END         0x1E       /* Control - contention-free period end    */
127 #define CTRL_CFP_ENDACK      0x1F       /* Control - contention-free period end/ack */
128
129 #define DATA                 0x20       /* Data - Data                             */
130 #define DATA_CF_ACK          0x21       /* Data - Data + CF acknowledge            */
131 #define DATA_CF_POLL         0x22       /* Data - Data + CF poll                   */
132 #define DATA_CF_ACK_POLL     0x23       /* Data - Data + CF acknowledge & CF poll  */
133 #define DATA_NULL_FUNCTION   0x24       /* Data - Null function (no data)          */
134 #define DATA_CF_ACK_NOD      0x25       /* Data - CF ack (no data)                 */
135 #define DATA_CF_ACK_POLL_NOD 0x26       /* Data - CF ack + CF poll (no data)       */
136
137 #define DATA_ADDR_T1         0x00
138 #define DATA_ADDR_T2         0x01
139 #define DATA_ADDR_T3         0x02
140 #define DATA_ADDR_T4         0x03
141
142
143 /* ************************************************************************* */
144 /*          Macros used to extract information about fixed fields            */
145 /* ************************************************************************* */
146 #define ESS_SET(x) ((x & 0x0001))
147 #define IBSS_SET(x) ((x & 0x0002))
148
149
150
151 /* ************************************************************************* */
152 /*        Logical field codes (dissector's encoding of fixed fields)         */
153 /* ************************************************************************* */
154 #define FIELD_TIMESTAMP       0x01      /* 64-bit timestamp                       */
155 #define FIELD_BEACON_INTERVAL 0x02      /* 16-bit beacon interval                 */
156 #define FIELD_CAP_INFO        0x03      /* Add capability information tree        */
157 #define FIELD_AUTH_ALG        0x04      /* Authentication algorithm used          */
158 #define FIELD_AUTH_TRANS_SEQ  0x05      /* Authentication sequence number         */
159 #define FIELD_CURRENT_AP_ADDR 0x06
160 #define FIELD_LISTEN_IVAL     0x07
161 #define FIELD_REASON_CODE     0x08
162 #define FIELD_ASSOC_ID        0x09
163 #define FIELD_STATUS_CODE     0x0A
164
165 /* ************************************************************************* */
166 /*        Logical field codes (IEEE 802.11 encoding of tags)                 */
167 /* ************************************************************************* */
168 #define TAG_SSID           0x00
169 #define TAG_SUPP_RATES     0x01
170 #define TAG_FH_PARAMETER   0x02
171 #define TAG_DS_PARAMETER   0x03
172 #define TAG_CF_PARAMETER   0x04
173 #define TAG_TIM            0x05
174 #define TAG_IBSS_PARAMETER 0x06
175 #define TAG_CHALLENGE_TEXT 0x10
176
177
178 /* ************************************************************************* */
179 /*                Various constants used in this module                      */
180 /* ************************************************************************* */
181 static const char *capture_proto_name = "IEEE 802.11";
182
183
184 static int proto_wlan = -1;
185 /* ************************************************************************* */
186 /*                Header field info values for FC-field                      */
187 /* ************************************************************************* */
188 static int hf_fc_field = -1;
189 static int hf_fc_proto_version = -1;
190 static int hf_fc_frame_type = -1;
191 static int hf_fc_frame_subtype = -1;
192
193 static int hf_fc_flags = -1;
194 static int hf_fc_to_ds = -1;
195 static int hf_fc_from_ds = -1;
196 static int hf_fc_data_ds = -1;
197
198 static int hf_fc_more_frag = -1;
199 static int hf_fc_retry = -1;
200 static int hf_fc_pwr_mgt = -1;
201 static int hf_fc_more_data = -1;
202 static int hf_fc_wep = -1;
203 static int hf_fc_order = -1;
204
205
206 /* ************************************************************************* */
207 /*                   Header values for Duration/ID field                     */
208 /* ************************************************************************* */
209 static int hf_did_duration = -1;
210
211
212
213 /* ************************************************************************* */
214 /*         Header values for different address-fields (all 4 of them)        */
215 /* ************************************************************************* */
216 static int hf_addr_da = -1;     /* Destination address subfield */
217 static int hf_addr_sa = -1;     /* Source address subfield */
218 static int hf_addr_ra = -1;     /* Receiver address subfield */
219 static int hf_addr_ta = -1;     /* Transmitter address subfield */
220 static int hf_addr_bssid = -1;  /* address is bssid */
221
222
223
224 /* ************************************************************************* */
225 /*                Header values for sequence number field                    */
226 /* ************************************************************************* */
227 static int hf_frag_number = -1;
228 static int hf_seq_number = -1;
229
230 /* ************************************************************************* */
231 /*                   Header values for Frame Check field                     */
232 /* ************************************************************************* */
233 static int hf_fcs = -1;
234
235
236 /* ************************************************************************* */
237 /*                      Fixed fields found in mgt frames                     */
238 /* ************************************************************************* */
239 static int ff_auth_alg = -1;    /* Authentication algorithm field          */
240 static int ff_auth_seq = -1;    /* Authentication transaction sequence     */
241 static int ff_current_ap = -1;  /* Current AP MAC address                  */
242 static int ff_listen_ival = -1; /* Listen interval fixed field             */
243 static int ff_timestamp = -1;   /* 64 bit timestamp                        */
244 static int ff_beacon_interval = -1;     /* 16 bit Beacon interval                  */
245 static int ff_assoc_id = -1;    /* 16 bit AID field                        */
246 static int ff_reason = -1;      /* 16 bit reason code                      */
247 static int ff_status_code = -1; /* Status code                             */
248
249 /* ************************************************************************* */
250 /*            Flags found in the capability field (fixed field)              */
251 /* ************************************************************************* */
252 static int ff_capture = -1;
253 static int ff_cf_sta_poll = -1; /* CF pollable status for a STA            */
254 static int ff_cf_ap_poll = -1;  /* CF pollable status for an AP            */
255 static int ff_cf_ess = -1;
256 static int ff_cf_ibss = -1;
257 static int ff_cf_privacy = -1;
258
259 /* ************************************************************************* */
260 /*                       Tagged value format fields                          */
261 /* ************************************************************************* */
262 static int tag_number = -1;
263 static int tag_length = -1;
264 static int tag_interpretation = -1;
265
266
267
268 static int hf_fixed_parameters = -1;    /* Protocol payload for management frames */
269 static int hf_tagged_parameters = -1;   /* Fixed payload item */
270
271 /* ************************************************************************* */
272 /*                               Protocol trees                              */
273 /* ************************************************************************* */
274 static gint ett_80211 = -1;
275 static gint ett_proto_flags = -1;
276 static gint ett_cap_tree = -1;
277 static gint ett_fc_tree = -1;
278 static gint ett_fixed_parameters = -1;
279 static gint ett_tagged_parameters = -1;
280
281 static dissector_handle_t llc_handle;
282
283 /* ************************************************************************* */
284 /*                                                                           */
285 /* ************************************************************************* */
286 int
287 find_header_length (const u_char * pd, int offset)
288 {
289   guint16 frame_control;
290
291   frame_control = pntohs (pd);
292   return ((IS_FROM_DS (frame_control))
293           && (IS_TO_DS (frame_control))) ? 30 : 24;
294 }
295
296
297 /* ************************************************************************* */
298 /*          This is the capture function used to update packet counts        */
299 /* ************************************************************************* */
300 void
301 capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
302 {
303   guint16 fcf, hdr_length;
304
305   fcf = pntohs (*((guint *) pd));
306
307
308   hdr_length = MGT_FRAME_HDR_LEN;       /* Set the header length of the frame */
309
310   switch (COMPOSE_FRAME_TYPE (fcf))
311     {
312
313     case DATA:                  /* We got a data frame */
314       hdr_length = find_header_length (pd, offset);
315       capture_llc (pd, offset + hdr_length, ld);
316       break;
317
318     case DATA_CF_ACK:           /* Data with ACK */
319       hdr_length = find_header_length (pd, offset);
320       capture_llc (pd, offset + hdr_length, ld);
321       break;
322
323     case DATA_CF_POLL:
324       hdr_length = find_header_length (pd, offset);
325       capture_llc (pd, offset + hdr_length, ld);
326       break;
327
328     case DATA_CF_ACK_POLL:
329       hdr_length = find_header_length (pd, offset);
330       capture_llc (pd, offset + hdr_length, ld);
331       break;
332
333     default:
334       ld->other++;
335       break;
336     }
337 }
338
339
340
341 /* ************************************************************************* */
342 /*          Add the subtree used to store the fixed parameters               */
343 /* ************************************************************************* */
344 static proto_tree *
345 get_fixed_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size)
346 {
347   proto_item *fixed_fields;
348   fixed_fields =
349     proto_tree_add_uint_format (tree, hf_fixed_parameters, tvb, start,
350                                 size, size, "Fixed parameters (%d bytes)",
351                                 size);
352
353   return proto_item_add_subtree (fixed_fields, ett_fixed_parameters);
354 }
355
356
357 /* ************************************************************************* */
358 /*            Add the subtree used to store tagged parameters                */
359 /* ************************************************************************* */
360 static proto_tree *
361 get_tagged_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size)
362 {
363   proto_item *tagged_fields;
364
365   tagged_fields = proto_tree_add_uint_format (tree, hf_tagged_parameters,
366                                               tvb,
367                                               start,
368                                               size,
369                                               size,
370                                               "Tagged parameters (%d bytes)",
371                                               size);
372
373   return proto_item_add_subtree (tagged_fields, ett_tagged_parameters);
374 }
375
376
377
378 /* ************************************************************************* */
379 /*              Dissect and add fixed mgmt fields to protocol tree           */
380 /* ************************************************************************* */
381 static void
382 add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
383 {
384   guint8 *dataptr;
385   char out_buff[SHORT_STR];
386   guint16 *temp16;
387   proto_item *cap_item;
388   static proto_tree *cap_tree;
389
390   switch (lfcode)
391     {
392     case FIELD_TIMESTAMP:
393       dataptr = tvb_get_ptr (tvb, offset, 8);
394       memset (out_buff, 0, SHORT_STR);
395       snprintf (out_buff, SHORT_STR, "0x%02X%02X%02X%02X%02X%02X%02X%02X",
396                 BIT_SWAP (dataptr[7]),
397                 BIT_SWAP (dataptr[6]),
398                 BIT_SWAP (dataptr[5]),
399                 BIT_SWAP (dataptr[4]),
400                 BIT_SWAP (dataptr[3]),
401                 BIT_SWAP (dataptr[2]),
402                 BIT_SWAP (dataptr[1]),
403                 BIT_SWAP (dataptr[0]));
404
405       proto_tree_add_string (tree, ff_timestamp, tvb, offset, 8, out_buff);
406       break;
407
408
409     case FIELD_BEACON_INTERVAL:
410       dataptr = tvb_get_ptr (tvb, offset, 2);
411       out_buff[0] = BIT_SWAP (dataptr[1]);
412       out_buff[1] = BIT_SWAP (dataptr[0]);
413       temp16 = (guint16 *) out_buff;
414       proto_tree_add_uint (tree, ff_beacon_interval, tvb, offset, 2,
415                            pntohs (temp16));
416       break;
417
418
419     case FIELD_CAP_INFO:
420       dataptr = tvb_get_ptr (tvb, offset, 2);
421       out_buff[0] = BIT_SWAP (dataptr[1]);
422       out_buff[0] = BIT_SWAP (dataptr[0]);
423       temp16 = (guint16 *) out_buff;
424
425       cap_item = proto_tree_add_uint_format (tree, ff_capture, 
426                                              tvb, offset, 2,
427                                              pntohs (temp16),
428                                              "Capability Information: %04X",
429                                              pntohs (temp16));
430       cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
431       proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 1,
432                               pntohs (temp16));
433       proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1,
434                               pntohs (temp16));
435       proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1,
436                               pntohs (temp16));
437       if (ESS_SET (pntohs (temp16)) != 0)       /* This is an AP */
438         proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
439                              ((pntohs (temp16) & 0xC) >> 2));
440
441       else                      /* This is a STA */
442         proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
443                              ((pntohs (temp16) & 0xC) >> 2));
444       break;
445
446
447     case FIELD_AUTH_ALG:
448       dataptr = tvb_get_ptr (tvb, offset, 2);
449       out_buff[0] = BIT_SWAP (dataptr[1]);
450       out_buff[1] = BIT_SWAP (dataptr[0]);
451       temp16 = (guint16 *) out_buff;
452       proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2,
453                            pntohs (temp16));
454       break;
455
456
457     case FIELD_AUTH_TRANS_SEQ:
458       dataptr = tvb_get_ptr (tvb, offset, 2);
459       out_buff[0] = BIT_SWAP (dataptr[1]);
460       out_buff[1] = BIT_SWAP (dataptr[0]);
461       temp16 = (guint16 *) out_buff;
462       proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2,
463                            pntohs (temp16));
464       break;
465
466
467     case FIELD_CURRENT_AP_ADDR:
468       dataptr = tvb_get_ptr (tvb, offset, 6);
469       memset (out_buff, 0, SHORT_STR);
470       out_buff[0] = BIT_SWAP (dataptr[5]);
471       out_buff[1] = BIT_SWAP (dataptr[4]);
472       out_buff[2] = BIT_SWAP (dataptr[3]);
473       out_buff[3] = BIT_SWAP (dataptr[2]);
474       out_buff[4] = BIT_SWAP (dataptr[1]);
475       out_buff[5] = BIT_SWAP (dataptr[0]);
476
477       proto_tree_add_string (tree, ff_current_ap, tvb, offset, 6, out_buff);
478       break;
479
480
481     case FIELD_LISTEN_IVAL:
482       dataptr = tvb_get_ptr (tvb, offset, 2);
483       out_buff[0] = BIT_SWAP (dataptr[1]);
484       out_buff[1] = BIT_SWAP (dataptr[0]);
485       temp16 = (guint16 *) out_buff;
486       proto_tree_add_uint (tree, ff_listen_ival, tvb, offset, 2,
487                            pntohs (temp16));
488       break;
489
490
491     case FIELD_REASON_CODE:
492       dataptr = tvb_get_ptr (tvb, offset, 2);
493       out_buff[0] = BIT_SWAP (dataptr[1]);
494       out_buff[1] = BIT_SWAP (dataptr[0]);
495       temp16 = (guint16 *) out_buff;
496       proto_tree_add_uint (tree, ff_reason, tvb, offset, 2, pntohs (temp16));
497       break;
498
499
500     case FIELD_ASSOC_ID:
501       dataptr = tvb_get_ptr (tvb, offset, 2);
502       out_buff[0] = BIT_SWAP (dataptr[1]);
503       out_buff[1] = BIT_SWAP (dataptr[0]);
504       temp16 = (guint16 *) out_buff;
505       proto_tree_add_uint (tree, ff_assoc_id, tvb, offset, 2, pntohs (temp16));
506       break;
507
508     case FIELD_STATUS_CODE:
509       dataptr = tvb_get_ptr (tvb, offset, 2);
510       out_buff[0] = BIT_SWAP (dataptr[1]);
511       out_buff[1] = BIT_SWAP (dataptr[0]);
512       temp16 = (guint16 *) out_buff;
513       proto_tree_add_uint (tree, ff_status_code, tvb, offset, 2,
514                            pntohs (temp16));
515       break;
516     }
517 }
518
519
520 /* ************************************************************************* */
521 /*           Dissect and add tagged (optional) fields to proto tree          */
522 /* ************************************************************************* */
523 static int
524 add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
525 {
526   guint8 *tag_info_ptr;
527   guint8 *tag_data_ptr;
528   guint32 tag_no, tag_len;
529   int i, n;
530   char out_buff[SHORT_STR];
531
532
533   tag_info_ptr = tvb_get_ptr (tvb, offset, 2);
534   tag_no = tag_info_ptr[0];
535   tag_len = tag_info_ptr[1];
536
537   tag_data_ptr = tvb_get_ptr (tvb, offset + 2, tag_len);
538
539
540   if ((tag_no >= 17) && (tag_no <= 31))
541     {                           /* Reserved for challenge text */
542       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
543                                   "Tag Number: %d (Reserved for challenge text)",
544                                   tag_no);
545
546       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
547       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
548                              tag_len, "Not interpreted");
549       return (int) tag_len;
550     }
551
552   /* Next See if tag is reserved - if true, skip it! */
553   if (((tag_no >= 7) && (tag_no <= 15))
554       || ((tag_no >= 32) && (tag_no <= 255)))
555     {
556       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
557                                   "Tag Number: %d (Reserved tag number)",
558                                   tag_no);
559
560       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
561
562       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
563                              tag_len, "Not interpreted");
564       return (int) tag_len;
565     }
566
567
568   switch (tag_info_ptr[0])
569     {
570
571
572     case TAG_SSID:
573       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
574                                   "Tag Number: %d (SSID parameter set)",
575                                   tag_no);
576
577       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
578
579       memset (out_buff, 0, SHORT_STR);
580
581       memcpy (out_buff, tag_data_ptr, (size_t) tag_len);
582       out_buff[tag_len + 1] = 0;
583
584       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
585                              tag_len, out_buff);
586       break;
587
588
589
590     case TAG_SUPP_RATES:
591       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
592                                   "Tag Number: %d (Supported Rates)", tag_no);
593
594       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
595
596       memset (out_buff, 0, SHORT_STR);
597       strcpy (out_buff, "Supported rates: ");
598       n = strlen (out_buff);
599
600       for (i = 0; i < tag_len; i++)
601         {
602
603           if (tag_data_ptr[i] >= 128)
604             {
605               tag_data_ptr[i] -= 128;
606               n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f ", (float)
607                              (((float) tag_data_ptr[i]) * 0.5));
608             }
609
610           else
611             n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f ", (float)
612                            (((float) tag_data_ptr[i]) * 0.5));
613
614         }
615       snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]");
616
617       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
618                              tag_len, out_buff);
619       break;
620
621
622
623     case TAG_FH_PARAMETER:
624       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
625                                   "Tag Number: %d (FH Parameter set)",
626                                   tag_no);
627
628       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
629       memset (out_buff, 0, SHORT_STR);
630
631       snprintf (out_buff, SHORT_STR,
632                 "Dwell time 0x%04X, Hop Set %2d, Hop Pattern %2d, "
633                 "Hop Index %2d", pntohs (tag_data_ptr), tag_data_ptr[2],
634                 tag_data_ptr[3], tag_data_ptr[4]);
635
636       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
637                              tag_len, out_buff);
638       break;
639
640
641
642     case TAG_DS_PARAMETER:
643       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
644                                   "Tag Number: %d (DS Parameter set)",
645                                   tag_no);
646
647       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
648       memset (out_buff, 0, SHORT_STR);
649
650       snprintf (out_buff, SHORT_STR, "Current Channel: %d", tag_data_ptr[0]);
651       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
652                              tag_len, out_buff);
653       break;
654
655
656     case TAG_CF_PARAMETER:
657       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
658                                   "Tag Number: %d (CF Parameter set)",
659                                   tag_no);
660
661       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
662       memset (out_buff, 0, SHORT_STR);
663
664       snprintf (out_buff, SHORT_STR,
665                 "CFP count %d, CFP period %d, CFP max duration %d, "
666                 "CFP Remaining %d", tag_data_ptr[0], tag_data_ptr[1],
667                 pntohs (tag_data_ptr + 2), pntohs (tag_data_ptr + 4));
668
669       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
670                              tag_len, out_buff);
671       break;
672
673
674     case TAG_TIM:
675       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
676                                   "Tag Number: %d (CF Parameter set)",
677                                   tag_no);
678
679       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
680       memset (out_buff, 0, SHORT_STR);
681       snprintf (out_buff, SHORT_STR,
682                 "DTIM count %d, DTIM period %d, Bitmap control 0x%X, "
683                 "(Bitmap suppressed)", tag_data_ptr[0], tag_data_ptr[1],
684                 tag_data_ptr[2]);
685       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
686                              tag_len, out_buff);
687       break;
688
689
690
691     case TAG_IBSS_PARAMETER:
692       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
693                                   "Tag Number: %d (IBSS Parameter set)",
694                                   tag_no);
695
696       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
697       memset (out_buff, 0, SHORT_STR);
698       snprintf (out_buff, SHORT_STR, "ATIM window 0x%X",
699                 pntohs (tag_data_ptr));
700
701       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
702                              tag_len, out_buff);
703       break;
704
705
706
707     case TAG_CHALLENGE_TEXT:
708       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
709                                   "Tag Number: %d (Challenge text)", tag_no);
710
711       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
712       memset (out_buff, 0, SHORT_STR);
713       snprintf (out_buff, SHORT_STR, "Challenge text: %.47s", tag_data_ptr);
714       proto_tree_add_string (tree, tag_interpretation, tvb, offset, tag_len,
715                              out_buff);
716
717       break;
718
719     default:
720       return 0;
721     }
722
723   return tag_len + 2;
724 }
725
726
727
728 /* ************************************************************************* */
729 /*                          Dissect 802.11 frame                             */
730 /* ************************************************************************* */
731 void
732 dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
733 {
734   guint16 fcf, flags;
735   guint8 *src = NULL, *dst = NULL;
736   proto_item *ti;
737   proto_item *flag_item;
738   proto_item *fc_item;
739   static proto_tree *hdr_tree;
740   static proto_tree *flag_tree;
741   static proto_tree *fixed_tree;
742   static proto_tree *tagged_tree;
743   static proto_tree *fc_tree;
744   guint16 cap_len, hdr_len;
745   tvbuff_t *next_tvb;
746   guint32 next_idx;
747   guint32 addr_type;
748
749   cap_len = pinfo->captured_len;
750   fcf = tvb_get_letohs (tvb, 0);
751
752   CHECK_DISPLAY_AS_DATA(proto_wlan, tvb, pinfo, tree);
753
754   pinfo->current_proto = capture_proto_name;
755
756   if (check_col (pinfo->fd, COL_PROTOCOL))
757     col_set_str (pinfo->fd, COL_PROTOCOL, "IEEE 802.11");
758
759   /* Add the FC to the current tree */
760   if (tree)
761     {
762       hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
763       ti = proto_tree_add_protocol_format (tree, proto_wlan, tvb, 0, hdr_len,
764                                            "IEEE 802.11 Header");
765       hdr_tree = proto_item_add_subtree (ti, ett_80211);
766
767       fc_item =
768         proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2,
769                                     tvb_get_letohs (tvb, 0),
770                                     "Frame Control: 0x%04X",
771                                     tvb_get_letohs (tvb, 0));
772
773       fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree);
774
775
776       proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1,
777                            COOK_PROT_VERSION (tvb_get_letohs (tvb, 0)));
778
779       proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1,
780                            COOK_FRAME_TYPE (tvb_get_letohs (tvb, 0)));
781
782       proto_tree_add_uint (fc_tree, hf_fc_frame_subtype,
783                            tvb, 0, 1,
784                            COOK_FRAME_SUBTYPE (tvb_get_letohs (tvb, 0)));
785
786       flags = COOK_FLAGS (tvb_get_letohs (tvb, 0));
787
788       flag_item =
789         proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
790                                     flags, "Flags: 0x%X", flags);
791
792       flag_tree = proto_item_add_subtree (flag_item, ett_proto_flags);
793
794       proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 1, 1,
795                            COOK_DS_STATUS (flags));
796
797       /*      proto_tree_add_boolean(flag_tree,hf_fc_to_ds,tvb,1,1,
798          flags);
799
800          proto_tree_add_boolean(flag_tree,hf_fc_from_ds,tvb,1,1,
801          flags); */
802
803       proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1,
804                               flags);
805
806       proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 1, 1, flags);
807
808       proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 1, 1, flags);
809
810       proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 1, 1,
811                               flags);
812
813       proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags);
814
815       proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
816
817       proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
818                            tvb_get_ntohs (tvb, 2));
819
820     }
821
822   /* Perform Tasks which are common to a certain frame type */
823   switch (COOK_FRAME_TYPE (fcf))
824     {
825
826     case MGT_FRAME:             /* All management frames share a common header */
827       src = tvb_get_ptr (tvb, 10, 6);
828       dst = tvb_get_ptr (tvb, 4, 6);
829
830
831       if (check_col (pinfo->fd, COL_DEF_SRC))
832         col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X",
833                       src[0], src[1], src[2], src[3], src[4], src[5]);
834
835       if (check_col (pinfo->fd, COL_DEF_DST))
836         col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X",
837                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
838
839       if (tree)
840         {
841           proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
842                                 tvb_get_ptr (tvb, 4, 6));
843
844           proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
845                                 tvb_get_ptr (tvb, 10, 6));
846
847           proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
848                                 tvb_get_ptr (tvb, 16, 6));
849
850           proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
851                                COOK_FRAGMENT_NUMBER (tvb_get_ntohs
852                                                      (tvb, 22)));
853
854           proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
855                                COOK_SEQUENCE_NUMBER (tvb_get_ntohs
856                                                      (tvb, 22)));
857           cap_len = cap_len - MGT_FRAME_LEN - 4;
858         }
859       break;
860
861
862
863     case CONTROL_FRAME:
864       break;
865
866
867
868     case DATA_FRAME:
869       addr_type = COOK_ADDR_SELECTOR (fcf);
870
871       /* In order to show src/dst address we must always do the following */
872       switch (addr_type)
873         {
874
875         case DATA_ADDR_T1:
876           src = tvb_get_ptr (tvb, 10, 6);
877           dst = tvb_get_ptr (tvb, 4, 6);
878           break;
879
880
881         case DATA_ADDR_T2:
882           src = tvb_get_ptr (tvb, 16, 6);
883           dst = tvb_get_ptr (tvb, 4, 6);
884           break;
885
886
887         case DATA_ADDR_T3:
888           src = tvb_get_ptr (tvb, 10, 6);
889           dst = tvb_get_ptr (tvb, 16, 6);
890           break;
891
892
893         case DATA_ADDR_T4:
894           src = tvb_get_ptr (tvb, 24, 6);
895           dst = tvb_get_ptr (tvb, 16, 6);
896           break;
897         }
898
899       if (check_col (pinfo->fd, COL_DEF_SRC))
900         col_add_fstr (pinfo->fd, COL_DEF_SRC,
901                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
902                       src[0], src[1], src[2], src[3], src[4], src[5]);
903
904       if (check_col (pinfo->fd, COL_DEF_DST))
905         col_add_fstr (pinfo->fd, COL_DEF_DST,
906                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
907                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
908
909       /* Now if we have a tree we start adding stuff */
910       if (tree)
911         {
912
913
914           switch (addr_type)
915             {
916
917             case DATA_ADDR_T1:
918               proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
919                                     tvb_get_ptr (tvb, 4, 6));
920               proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
921                                     tvb_get_ptr (tvb, 10, 6));
922               proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
923                                     tvb_get_ptr (tvb, 16, 6));
924               break;
925
926
927             case DATA_ADDR_T2:
928               proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
929                                     tvb_get_ptr (tvb, 4, 6));
930               proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
931                                     tvb_get_ptr (tvb, 10, 6));
932               proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 16, 6,
933                                     tvb_get_ptr (tvb, 16, 6));
934               break;
935
936
937             case DATA_ADDR_T3:
938               proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
939                                     tvb_get_ptr (tvb, 4, 6));
940               proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
941                                     tvb_get_ptr (tvb, 10, 6));
942               proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6,
943                                     tvb_get_ptr (tvb, 16, 6));
944               break;
945
946
947             case DATA_ADDR_T4:
948               proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
949                                     tvb_get_ptr (tvb, 4, 6));
950               proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
951                                     tvb_get_ptr (tvb, 10, 6));
952               proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6,
953                                     tvb_get_ptr (tvb, 16, 6));
954               proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6,
955                                     tvb_get_ptr (tvb, 24, 6));
956               break;
957
958             }
959
960         }
961       break;
962     }
963
964
965   switch (COMPOSE_FRAME_TYPE (fcf))
966     {
967
968     case MGT_ASSOC_REQ:
969       COL_SHOW_INFO (pinfo->fd, "Association Request");
970       if (tree)
971         {
972           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 4);
973           add_fixed_field (fixed_tree, tvb, MGT_FRAME_HDR_LEN,
974                            FIELD_CAP_INFO);
975           add_fixed_field (fixed_tree, tvb, MGT_FRAME_HDR_LEN + 2,
976                            FIELD_LISTEN_IVAL);
977
978           next_idx = MGT_FRAME_HDR_LEN + 4;     /* Size of fixed fields */
979           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
980                                                    pinfo->captured_len - 4 -
981                                                    next_idx);
982
983
984           while (pinfo->captured_len > (next_idx + 4))
985             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
986         }
987       break;
988
989
990
991     case MGT_ASSOC_RESP:
992       COL_SHOW_INFO (pinfo->fd, "Association Response");
993
994       if (tree)
995         {
996           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 6);
997           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
998           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
999                            FIELD_STATUS_CODE);
1000           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
1001                            FIELD_ASSOC_ID);
1002
1003           next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
1004
1005           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
1006                                                    pinfo->captured_len - 4 -
1007                                                    next_idx);
1008
1009           while (pinfo->captured_len > (next_idx + 4))
1010             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1011
1012         }
1013       break;
1014
1015     case MGT_REASSOC_REQ:
1016       COL_SHOW_INFO (pinfo->fd, "Reassociation Request");
1017       if (tree)
1018         {
1019           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 10);
1020           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
1021           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
1022                            FIELD_LISTEN_IVAL);
1023           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
1024                            FIELD_CURRENT_AP_ADDR);
1025
1026           next_idx = MGT_FRAME_LEN + 10;        /* Size of fixed fields */
1027           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
1028                                                    pinfo->captured_len - 4 -
1029                                                    next_idx);
1030
1031           while ((pinfo->captured_len) > (next_idx + 4))
1032             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1033         }
1034       break;
1035
1036     case MGT_REASSOC_RESP:
1037       COL_SHOW_INFO (pinfo->fd, "Reassociation Response");
1038       if (tree)
1039         {
1040           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 10);
1041           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
1042           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
1043                            FIELD_STATUS_CODE);
1044           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
1045                            FIELD_ASSOC_ID);
1046
1047           next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
1048           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
1049                                                    pinfo->captured_len - 4 -
1050                                                    next_idx);
1051
1052           while (pinfo->captured_len > (next_idx + 4))
1053             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1054
1055
1056         }
1057       break;
1058
1059     case MGT_PROBE_REQ:
1060       COL_SHOW_INFO (pinfo->fd, "Probe Request");
1061       if (tree)
1062         {
1063           next_idx = MGT_FRAME_LEN;
1064           tagged_tree = get_tagged_parameter_tree (tree, tvb, MGT_FRAME_LEN,
1065                                                    pinfo->captured_len - 4 -
1066                                                    next_idx);
1067
1068           while (pinfo->captured_len > (next_idx + 4))
1069             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1070         }
1071       break;
1072
1073
1074
1075     case MGT_PROBE_RESP:
1076       COL_SHOW_INFO (pinfo->fd, "Probe Response");
1077       if (tree)
1078         {
1079           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 12);
1080           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_TIMESTAMP);
1081           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 8,
1082                            FIELD_BEACON_INTERVAL);
1083           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 10,
1084                            FIELD_CAP_INFO);
1085
1086           next_idx = MGT_FRAME_LEN + 12;        /* Size of fixed fields */
1087           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
1088                                                    pinfo->captured_len - 4 -
1089                                                    next_idx);
1090
1091           while ((pinfo->captured_len) > (next_idx + 4))
1092             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1093         }
1094       break;
1095
1096
1097     case MGT_BEACON:            /* Dissect protocol payload fields  */
1098       COL_SHOW_INFO (pinfo->fd, "Beacon frame");
1099
1100       if (tree)
1101         {
1102           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 12);
1103
1104           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_TIMESTAMP);
1105
1106           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 8,
1107                            FIELD_BEACON_INTERVAL);
1108           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 10,
1109                            FIELD_CAP_INFO);
1110
1111           next_idx = MGT_FRAME_LEN + 12;        /* Size of fixed fields */
1112           tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
1113                                                    pinfo->captured_len - 4 -
1114                                                    next_idx);
1115
1116           while (pinfo->captured_len > (next_idx + 4))
1117             next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1118
1119         }
1120       break;
1121
1122
1123
1124     case MGT_ATIM:
1125       COL_SHOW_INFO (pinfo->fd, "ATIM");
1126       if (tree)
1127         {
1128         }
1129       break;
1130
1131     case MGT_DISASS:
1132       COL_SHOW_INFO (pinfo->fd, "Dissassociate");
1133       if (tree)
1134         {
1135           fixed_tree =
1136             get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, cap_len);
1137           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_REASON_CODE);
1138         }
1139       break;
1140
1141     case MGT_AUTHENTICATION:
1142       COL_SHOW_INFO (pinfo->fd, "Authentication");
1143       if (tree)
1144         {
1145           fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 6);
1146           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_AUTH_ALG);
1147           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
1148                            FIELD_AUTH_TRANS_SEQ);
1149           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
1150                            FIELD_STATUS_CODE);
1151
1152           next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
1153
1154           if ((pinfo->captured_len - next_idx - 4) != 0)
1155             {
1156               tagged_tree = get_tagged_parameter_tree (tree,
1157                                                        tvb,
1158                                                        next_idx,
1159                                                        pinfo->captured_len -
1160                                                        next_idx - 4);
1161
1162               while ((pinfo->captured_len) > (next_idx - 4))
1163                 next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
1164             }
1165         }
1166       break;
1167
1168     case MGT_DEAUTHENTICATION:
1169       COL_SHOW_INFO (pinfo->fd, "Deauthentication");
1170       if (tree)
1171         {
1172           fixed_tree = get_fixed_parameter_tree (hdr_tree, tvb, MGT_FRAME_LEN, 2);
1173           add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_REASON_CODE);
1174         }
1175       break;
1176
1177
1178
1179     case CTRL_PS_POLL:
1180       COL_SHOW_INFO (pinfo->fd, "Power-Save poll");
1181
1182       src = tvb_get_ptr (tvb, 10, 6);
1183       dst = tvb_get_ptr (tvb, 4, 6);
1184
1185
1186       if (check_col (pinfo->fd, COL_DEF_SRC))
1187         col_add_fstr (pinfo->fd, COL_DEF_SRC,
1188                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (BSSID)",
1189                       src[0], src[1], src[2], src[3], src[4], src[5]);
1190
1191       if (check_col (pinfo->fd, COL_DEF_DST))
1192         col_add_fstr (pinfo->fd, COL_DEF_DST,
1193                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (TA)",
1194                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1195
1196       if (tree)
1197         {
1198           proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
1199                                 tvb_get_ptr (tvb, 4, 6));
1200
1201           proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
1202                                 tvb_get_ptr (tvb, 10, 6));
1203
1204         }
1205       break;
1206
1207
1208
1209     case CTRL_RTS:
1210       COL_SHOW_INFO (pinfo->fd, "Request-to-send");
1211       src = tvb_get_ptr (tvb, 10, 6);
1212       dst = tvb_get_ptr (tvb, 4, 6);
1213
1214
1215       if (check_col (pinfo->fd, COL_DEF_SRC))
1216         col_add_fstr (pinfo->fd, COL_DEF_SRC,
1217                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (TA)",
1218                       src[0], src[1], src[2], src[3], src[4], src[5]);
1219
1220       if (check_col (pinfo->fd, COL_DEF_DST))
1221         col_add_fstr (pinfo->fd, COL_DEF_DST,
1222                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
1223                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1224
1225       if (tree)
1226         {
1227           proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
1228                                 tvb_get_ptr (tvb, 4, 6));
1229
1230           proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
1231                                 tvb_get_ptr (tvb, 10, 6));
1232
1233         }
1234       break;
1235
1236
1237
1238     case CTRL_CTS:
1239       COL_SHOW_INFO (pinfo->fd, "Clear-to-send");
1240
1241       dst = tvb_get_ptr (tvb, 4, 6);
1242
1243       if (check_col (pinfo->fd, COL_DEF_DST))
1244         col_add_fstr (pinfo->fd, COL_DEF_DST,
1245                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
1246                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1247
1248       if (tree)
1249         {
1250           proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
1251                                 tvb_get_ptr (tvb, 4, 6));
1252
1253         }
1254       break;
1255
1256
1257
1258     case CTRL_ACKNOWLEDGEMENT:
1259       COL_SHOW_INFO (pinfo->fd, "Acknowledgement");
1260
1261       dst = tvb_get_ptr (tvb, 4, 6);
1262
1263       if (check_col (pinfo->fd, COL_DEF_DST))
1264         col_add_fstr (pinfo->fd, COL_DEF_DST,
1265                       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
1266                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1267
1268       if (tree)
1269         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
1270                               tvb_get_ptr (tvb, 4, 6));
1271       break;
1272
1273
1274
1275     case CTRL_CFP_END:
1276       COL_SHOW_INFO (pinfo->fd, "CF-End (Control-frame)");
1277
1278       src = tvb_get_ptr (tvb, 10, 6);
1279       dst = tvb_get_ptr (tvb, 4, 6);
1280
1281
1282       if (check_col (pinfo->fd, COL_DEF_SRC))
1283         col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X (BSSID)",
1284                       src[0], src[1], src[2], src[3], src[4], src[5]);
1285
1286       if (check_col (pinfo->fd, COL_DEF_DST))
1287         col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X (RA)",
1288                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1289
1290       if (tree)
1291         {
1292           proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
1293                                tvb_get_ntohs (tvb, 2));
1294
1295           proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
1296                                 tvb_get_ptr (tvb, 4, 6));
1297
1298           proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
1299                                 tvb_get_ptr (tvb, 10, 6));
1300
1301         }
1302       break;
1303
1304
1305
1306     case CTRL_CFP_ENDACK:
1307       COL_SHOW_INFO (pinfo->fd, "CF-End + CF-Ack (Control-frame)");
1308
1309       src = tvb_get_ptr (tvb, 10, 6);
1310       dst = tvb_get_ptr (tvb, 4, 6);
1311
1312       if (check_col (pinfo->fd, COL_DEF_SRC))
1313         col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X (BSSID)",
1314                       src[0], src[1], src[2], src[3], src[4], src[5]);
1315
1316       if (check_col (pinfo->fd, COL_DEF_DST))
1317         col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X (RA)",
1318                       dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
1319
1320       if (tree)
1321         {
1322           proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
1323                                tvb_get_ntohs (tvb, 2));
1324
1325           proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
1326                                 tvb_get_ptr (tvb, 4, 6));
1327
1328           proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
1329                                 tvb_get_ptr (tvb, 10, 6));
1330
1331         }
1332       break;
1333
1334
1335
1336     case DATA:
1337       COL_SHOW_INFO (pinfo->fd, "Data");
1338       if (tree)
1339         {
1340           hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
1341
1342           next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
1343           call_dissector (llc_handle, next_tvb, pinfo, tree);
1344         }
1345       break;
1346
1347
1348
1349     case DATA_CF_ACK:
1350       COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement");
1351       if (tree)
1352         {
1353           hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
1354
1355           next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
1356           call_dissector (llc_handle, next_tvb, pinfo, tree);
1357         }
1358       break;
1359
1360
1361
1362     case DATA_CF_POLL:
1363       COL_SHOW_INFO (pinfo->fd, "Data + CF-Poll");
1364       if (tree)
1365         {
1366           hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
1367           next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
1368           call_dissector (llc_handle, next_tvb, pinfo, tree);
1369         }
1370       break;
1371
1372
1373
1374     case DATA_CF_ACK_POLL:
1375       COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement/Poll");
1376       if (tree)
1377         {
1378           hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
1379           next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
1380           call_dissector (llc_handle, next_tvb, pinfo, tree);
1381         }
1382       break;
1383
1384
1385
1386     case DATA_NULL_FUNCTION:
1387       COL_SHOW_INFO (pinfo->fd, "Null function (No data)");
1388       break;
1389
1390
1391     case DATA_CF_ACK_NOD:
1392       COL_SHOW_INFO (pinfo->fd, "Data + Acknowledgement(No data)");
1393       break;
1394
1395
1396
1397     case DATA_CF_ACK_POLL_NOD:
1398       COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement/Poll (No data)");
1399       break;
1400
1401
1402
1403     default:
1404       COL_SHOW_INFO (pinfo->fd, "Unrecognized (Reserved frame)");
1405       break;
1406     }
1407 }
1408
1409
1410 void
1411 proto_register_wlan (void)
1412 {
1413
1414   static const value_string tofrom_ds[] = {
1415     {0, "Network operating in AD-HOC mode ( To DS: 0  From DS: 0)"},
1416     {1, "Frame is exiting DS (To DS: 0  From DS: 1)"},
1417     {2, "Frame is entering DS (To DS: 0  From DS: 1)"},
1418     {3, "Frame part of WDS (To DS: 1  From DS: 1)"},
1419     {0, NULL}
1420   };
1421
1422   static const true_false_string tods_flag = {
1423     "TO DS: Should be false",
1424     "Not used"
1425   };
1426
1427   static const true_false_string fromds_flag = {
1428     "FROM DS: Should be false",
1429     "Not used"
1430   };
1431
1432   static const true_false_string more_frags = {
1433     "MSDU/MMPDU is fragmented",
1434     "No fragments"
1435   };
1436
1437   static const true_false_string retry_flags = {
1438     "Frame is being retransmitted",
1439     "Frame is not being retransmitted"
1440   };
1441
1442   static const true_false_string pm_flags = {
1443     "STA will go to sleep",
1444     "STA will stay up"
1445   };
1446
1447   static const true_false_string md_flags = {
1448     "Data is buffered for STA at AP",
1449     "No data buffered"
1450   };
1451
1452   static const true_false_string wep_flags = {
1453     "WEP is enabled",
1454     "WEP is disabled"
1455   };
1456
1457   static const true_false_string order_flags = {
1458     "",
1459     ""
1460   };
1461
1462   static const true_false_string cf_ess_flags = {
1463     "Transmitter is an AP",
1464     "Transmitter is a STA"
1465   };
1466
1467
1468   static const true_false_string cf_privacy_flags = {
1469     "AP/STA can support WEP",
1470     "AP/STA cannot support WEP"
1471   };
1472
1473
1474   static const true_false_string cf_ibss_flags = {
1475     "Transmitter belongs to an IBSS",
1476     "Transmitter belongs to a BSS"
1477   };
1478
1479   static const value_string sta_cf_pollable[] = {
1480     {0x00, "Station is not CF-Pollable"},
1481     {0x02, "Station is CF-Pollable, "
1482      "not requesting to be placed on the  CF-polling list"},
1483     {0x01, "Station is CF-Pollable, "
1484      "requesting to be placed on the CF-polling list"},
1485     {0x03, "Station is CF-Pollable, requesting never to be polled"},
1486     {0, NULL}
1487   };
1488
1489   static const value_string ap_cf_pollable[] = {
1490     {0x00, "No point coordinator at AP"},
1491     {0x02, "Point coordinator at AP for delivery only (no polling)"},
1492     {0x01, "Point coordinator at AP for delivery and polling"},
1493     {0x03, "Reserved"},
1494     {0, NULL}
1495   };
1496
1497
1498   static const value_string auth_alg[] = {
1499     {0x00, "Open System"},
1500     {0x01, "Shared key"},
1501     {0, NULL}
1502   };
1503
1504   static const value_string reason_codes[] = {
1505     {0x00, "Reserved"},
1506     {0x01, "Unspecified reason"},
1507     {0x02, "Previous authentication no longer valid"},
1508     {0x03, "Deauthenticated because sending STA is leaving (has left) "
1509      "IBSS or ESS"},
1510     {0x04, "Disassociated due to inactivity"},
1511     {0x05, "Disassociated because AP is unable to handle all currently "
1512      "associated stations"},
1513     {0x06, "Class 2 frame received from nonauthenticated station"},
1514     {0x07, "Class 3 frame received from nonassociated station"},
1515     {0x08, "Disassociated because sending STA is leaving (has left) BSS"},
1516     {0x09, "Station requesting (re)association is not authenticated with "
1517      "responding station"},
1518     {0x00, NULL}
1519   };
1520
1521
1522   static const value_string status_codes[] = {
1523     {0x00, "Successful"},
1524     {0x01, "Unspecified failure"},
1525     {0x0A, "Cannot support all requested capabilities in the "
1526      "Capability information field"},
1527     {0x0B, "Reassociation denied due to inability to confirm that "
1528      "association exists"},
1529     {0x0C, "Association denied due to reason outside the scope of this "
1530      "standard"},
1531
1532     {0x0D, "Responding station does not support the specified authentication "
1533      "algorithm"},
1534     {0x0E, "Received an Authentication frame with authentication sequence "
1535      "transaction sequence number out of expected sequence"},
1536     {0x0F, "Authentication rejected because of challenge failure"},
1537     {0x10, "Authentication rejected due to timeout waiting for next "
1538      "frame in sequence"},
1539     {0x11, "Association denied because AP is unable to handle additional "
1540      "associated stations"},
1541     {0x12, "Association denied due to requesting station not supporting all "
1542      "of the datarates in the BSSBasicServiceSet Parameter"},
1543     {0x00, NULL}
1544   };
1545
1546
1547
1548   static hf_register_info hf[] = {
1549     {&hf_fc_field,
1550      {"Frame Control Field", "wlan.fc", FT_UINT16, BASE_HEX, NULL, 0,
1551       "MAC Frame control"}},
1552
1553     {&hf_fc_proto_version,
1554      {"Version", "wlan.fc.version", FT_UINT8, BASE_DEC, NULL, 0,
1555       "MAC Protocol version"}}, /* 0 */
1556
1557     {&hf_fc_frame_type,
1558      {"Type", "wlan.fc.type", FT_UINT8, BASE_DEC, NULL, 0,
1559       "Frame type"}},
1560
1561     {&hf_fc_frame_subtype,
1562      {"Subtype", "wlan.fc.subtype", FT_UINT8, BASE_DEC, NULL, 0,
1563       "Frame subtype"}},        /* 2 */
1564
1565     {&hf_fc_flags,
1566      {"Protocol Flags", "wlan.flags", FT_UINT8, BASE_HEX, NULL, 0,
1567       "Protocol flags"}},
1568
1569     {&hf_fc_data_ds,
1570      {"DS status", "wlan.fc.ds", FT_UINT8, BASE_HEX, TFS (&tofrom_ds), 0,
1571       "Data-frame DS-traversal status"}},       /* 3 */
1572
1573     {&hf_fc_to_ds,
1574      {"To DS", "wlan.fc.tods", FT_BOOLEAN, 8, TFS (&tods_flag), 0x1,
1575       "To DS flag"}},           /* 4 */
1576
1577     {&hf_fc_from_ds,
1578      {"From DS", "wlan.fc.fromds", FT_BOOLEAN, 8, TFS (&fromds_flag), 0x2,
1579       "From DS flag"}},         /* 5 */
1580
1581     {&hf_fc_more_frag,
1582      {"Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), 0x4,
1583       "More Fragments flag"}},  /* 6 */
1584
1585     {&hf_fc_retry,
1586      {"Retry", "wlan.fc.retry", FT_BOOLEAN, 8, TFS (&retry_flags), 0x8,
1587       "Retransmission flag"}},
1588
1589     {&hf_fc_pwr_mgt,
1590      {"PWR MGT", "wlan.fc.pwrmgt", FT_BOOLEAN, 8, TFS (&pm_flags), 0x10,
1591       "Power management status"}},
1592
1593     {&hf_fc_more_data,
1594      {"More Data", "wlan.fc.moredata", FT_BOOLEAN, 8, TFS (&md_flags), 0x20,
1595       "More data flag"}},
1596
1597     {&hf_fc_wep,
1598      {"WEP flag", "wlan.fc.wep", FT_BOOLEAN, 8, TFS (&wep_flags), 0x40,
1599       "WEP flag"}},
1600
1601     {&hf_fc_order,
1602      {"Order flag", "wlan.fc.order", FT_BOOLEAN, 8, TFS (&order_flags), 0x80,
1603       "Strictly ordered flag"}},
1604
1605     {&hf_did_duration,
1606      {"Duration", "wlan.duration", FT_UINT16, BASE_DEC, NULL, 0,
1607       "Duration field"}},
1608
1609     {&hf_addr_da,
1610      {"Destination address", "wlan.da", FT_ETHER, BASE_NONE, NULL, 0,
1611       "Destination Hardware address"}},
1612
1613     {&hf_addr_sa,
1614      {"Source address", "wlan.sa", FT_ETHER, BASE_NONE, NULL, 0,
1615       "Source Hardware address"}},
1616
1617     {&hf_addr_ra,
1618      {"Receiver address", "wlan.ra", FT_ETHER, BASE_NONE, NULL, 0,
1619       "Receiving Station Hardware Address"}},
1620
1621     {&hf_addr_ta,
1622      {"Transmitter address", "wlan.ta", FT_ETHER, BASE_NONE, NULL, 0,
1623       "Transmitting Station Hardware Address"}},
1624
1625     {&hf_addr_bssid,
1626      {"BSS Id", "wlan.bssid", FT_ETHER, BASE_NONE, NULL, 0,
1627       "Basic Service Set ID"}},
1628
1629     {&hf_frag_number,
1630      {"Fragment number", "wlan.frag", FT_UINT16, BASE_HEX, NULL, 0,
1631       "Fragment number"}},
1632
1633     {&hf_seq_number,
1634      {"Sequence number", "wlan.seq", FT_UINT16, BASE_HEX, NULL, 0,
1635       "Fragment number"}},
1636
1637     {&hf_fcs,
1638      {"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX,
1639       NULL, 0, ""}},
1640
1641     {&ff_timestamp,
1642      {"Timestamp", "wlan.fixed.timestamp", FT_STRING, BASE_NONE,
1643       NULL, 0, ""}},
1644
1645     {&ff_auth_alg,
1646      {"Authentication Algorithm", "wlan.fixed.auth.alg",
1647       FT_UINT16, BASE_DEC, VALS (&auth_alg), 0, ""}},
1648
1649     {&ff_beacon_interval,
1650      {"Beacon Interval", "wlan.fixed.beacon", FT_UINT16, BASE_DEC, NULL, 0,
1651       ""}},
1652
1653     {&hf_fixed_parameters,
1654      {"Fixed parameters", "wlan.fixed.all", FT_UINT16, BASE_DEC, NULL, 0,
1655       ""}},
1656
1657     {&hf_tagged_parameters,
1658      {"Tagged parameters", "wlan.tagged.all", FT_UINT16, BASE_DEC, NULL, 0,
1659       ""}},
1660
1661     {&ff_capture,
1662      {"Capabilities", "wlan.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
1663       "Capability information"}},
1664
1665     {&ff_cf_sta_poll,
1666      {"CFP participation capabilities", "wlan.fixed.capabilities.cfpoll.sta",
1667       FT_UINT16, BASE_HEX, VALS (&sta_cf_pollable), 0,
1668       "CF-Poll capabilities for a STA"}},
1669
1670     {&ff_cf_ap_poll,
1671      {"CFP participation capabilities", "wlan.fixed.capabilities.cfpoll.ap",
1672       FT_UINT16, BASE_HEX, VALS (&ap_cf_pollable), 0,
1673       "CF-Poll capabilities for an AP"}},
1674
1675     {&ff_cf_ess,
1676      {"ESS capabilities", "wlan.fixed.capabilities.ess",
1677       FT_BOOLEAN, 1, TFS (&cf_ess_flags), 0x0001, "ESS capabilities"}},
1678
1679
1680     {&ff_cf_ibss,
1681      {"IBSS status", "wlan.fixed.capabilities.ibss",
1682       FT_BOOLEAN, 1, TFS (&cf_ibss_flags), 0x0002, "IBSS participation"}},
1683
1684     {&ff_cf_privacy,
1685      {"Privacy", "wlan.fixed.capabilities.privacy",
1686       FT_BOOLEAN, 1, TFS (&cf_privacy_flags), 0x0010, "WEP support"}},
1687
1688
1689     {&ff_auth_seq,
1690      {"Authentication SEQ", "wlan.fixed.auth_seq",
1691       FT_UINT16, BASE_HEX, NULL, 0, "Authentication sequence number"}},
1692
1693     {&ff_assoc_id,
1694      {"Association ID", "wlan.fixed.aid",
1695       FT_UINT16, BASE_HEX, NULL, 0, "Association ID"}},
1696
1697     {&ff_listen_ival,
1698      {"Listen Interval", "wlan.fixed.listen_ival",
1699       FT_UINT16, BASE_HEX, NULL, 0, "Listen Interval"}},
1700
1701     {&ff_current_ap,
1702      {"Current AP", "wlan.fixed.current_ap",
1703       FT_ETHER, BASE_NONE, NULL, 0, "MAC address of current AP"}},
1704
1705     {&ff_reason,
1706      {"Reason code", "wlan.fixed.reason_code",
1707       FT_UINT16, BASE_HEX, VALS (&reason_codes), 0,
1708       "Reason for unsolicited notification"}},
1709
1710     {&ff_status_code,
1711      {"Status code", "wlan.fixed.status_code",
1712       FT_UINT16, BASE_HEX, VALS (&status_codes), 0,
1713       "Status of requested event"}},
1714
1715     {&tag_number,
1716      {"Tag", "wlan.tag.number",
1717       FT_UINT16, BASE_DEC, NULL, 0,
1718       "Element ID"}},
1719
1720     {&tag_length,
1721      {"Tag length", "wlan.tag.length",
1722       FT_UINT16, BASE_DEC, NULL, 0, "Length of tag"}},
1723
1724     {&tag_interpretation,
1725      {"Tag interpretation", "wlan.tag.interpretation",
1726       FT_STRING, BASE_NONE, NULL, 0, "Interpretation of tag"}}
1727
1728
1729   };
1730
1731
1732   static gint *tree_array[] = { &ett_80211,
1733     &ett_fc_tree,
1734     &ett_proto_flags,
1735     &ett_fixed_parameters,
1736     &ett_tagged_parameters,
1737     &ett_cap_tree,
1738   };
1739
1740   proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN",
1741                                         "IEEE 802.11", "wlan");
1742   proto_register_field_array (proto_wlan, hf, array_length (hf));
1743   proto_register_subtree_array (tree_array, array_length (tree_array));
1744 }
1745
1746 void
1747 proto_reg_handoff_wlan(void)
1748 {
1749   /*
1750    * Get a handle for the LLC dissector.
1751    */
1752   llc_handle = find_dissector("llc");
1753
1754   dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, dissect_ieee80211,
1755                 proto_wlan);
1756 }