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