As the gtk2 directory is no longer needed (GTK1 and 2 are using the same sources...
[obnox/wireshark/wip.git] / packet-lwapp.c
1 /* packet-lwapp.c
2  *
3  * Routines for LWAPP encapsulated packet disassembly
4  * draft-calhoun-seamoby-lwapp-N (the current draft is 3)
5  *
6  * $Id$
7  *
8  * Copyright (c) 2003 by David Frascone <dave@frascone.com>
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
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 #include <string.h>
36 #include <ctype.h>
37 #include <time.h>
38 #include <glib.h>
39 #include <epan/filesystem.h>
40 #include "xmlstub.h"
41 #include <epan/packet.h>
42 #include <epan/resolv.h>
43 #include "prefs.h"
44
45
46 #ifdef NEED_SNPRINTF_H
47 # include "snprintf.h"
48 #endif
49
50 #define LWAPP_FLAGS_T 0x04
51 #define LWAPP_FLAGS_F 0x02
52 #define LWAPP_FLAGS_FT 0x01
53
54 static gint proto_lwapp = -1;
55 static gint proto_lwapp_l3 = -1;
56 static gint proto_lwapp_control = -1;
57 static gint ett_lwapp = -1;
58 static gint ett_lwapp_l3 = -1;
59 static gint ett_lwapp_flags = -1;
60 static gint ett_lwapp_control = -1;
61
62 static gint hf_lwapp_version = -1;
63 static gint hf_lwapp_slotid = -1;
64 static gint hf_lwapp_flags_type = -1;
65 static gint hf_lwapp_flags_fragment = -1;
66 static gint hf_lwapp_flags_fragment_type = -1;
67 static gint hf_lwapp_fragment_id = -1;
68 static gint hf_lwapp_length = -1;
69 static gint hf_lwapp_rssi = -1;
70 static gint hf_lwapp_snr = -1;
71 static gint hf_lwapp_control = -1;
72 static gint hf_lwapp_control_mac = -1;
73 static gint hf_lwapp_control_type = -1;
74 static gint hf_lwapp_control_seq_no = -1;
75 static gint hf_lwapp_control_length = -1;
76
77 static dissector_handle_t eth_handle;
78 static dissector_handle_t wlan_handle;
79 static dissector_handle_t wlan_bsfc_handle;
80 static dissector_handle_t data_handle;
81
82 /* Set by preferences */
83 static gboolean swap_frame_control;
84
85 typedef struct {
86     guint8 flags;
87     guint8 fragmentId;
88     guint16 length;
89     guint8 rssi;
90     guint8 snr;
91 } LWAPP_Header;
92
93 typedef struct {
94     guint8   tag;
95     guint16  length;
96 } CNTL_Data_Header;
97
98 typedef struct {
99     guint8    type;
100     guint8    seqNo;
101     guint16   length;
102 } CNTL_Header;
103
104 typedef enum {
105     RESULT_CODE = 1,
106     MWAR_ADDR_PAYLOAD,
107     RAD_PAYLOAD,
108     RAD_SLOT_PAYLOAD,
109     RAD_NAME_PAYLOAD,
110     MWAR_PAYLOAD,
111     VAP_PAYLOAD,
112     STATION_CFG_PAYLOAD,
113     OPERATION_RATE_SET_PAYLOAD,
114     MULTI_DOMAIN_CAPABILITY_PAYLOAD,
115     MAC_OPERATION_PAYLOAD,
116     PHY_TX_POWER_PAYLOAD,
117     PHY_TX_POWER_LEVEL_PAYLOAD,
118     PHY_DSSS_PAYLOAD,
119     PHY_OFDM_PAYLOAD,
120     SUPPORTED_RATES_PAYLOAD,
121     AUTH_PAYLOAD,
122     TEST_PAYLOAD,
123     RRM_NEIGHBOR_CTRL_PAYLOAD,
124     RRM_NOISE_CTRL_PAYLOAD,
125     RRM_NOISE_DATA_PAYLOAD,
126     RRM_INTERFERENCE_CTRL_PAYLOAD,
127     RRM_INTERFERENCE_DATA_PAYLOAD,
128     RRM_LOAD_CTRL_PAYLOAD,
129     RRM_LOAD_DATA_PAYLOAD,
130     CHANGE_STATE_EVENT_PAYLOAD,
131     ADMIN_STATE_PAYLOAD,
132     DELETE_VAP_PAYLOAD,
133     ADD_MOBILE_PAYLOAD,
134     DELETE_MOBILE_PAYLOAD
135 } control_tags;
136
137 typedef enum
138   {
139     DISCOVERY_REQUEST = 1,
140     DISCOVERY_REPLY,
141     JOIN_REQUEST,
142     JOIN_REPLY,
143     HANDOFF_REQUEST,
144     HANDOFF_REPLY,
145     HANDOFF_COMMAND,
146     HANDOFF_RESPONSE,
147     HANDOFF_CONFIRM,
148     CONFIGURE_REQUEST,
149     CONFIGURE_RESPONSE,
150     CONFIGURE_COMMAND,
151     CONFIGURE_COMMAND_RES,
152     STATISTICS_INFO,
153     CHANGE_STATE_EVENT,
154     CHANGE_STATE_EVENT_RES,
155     RRM_CONTROL_REQ,
156     RRM_CONTROL_RES,
157     RRM_DATA_REQ,
158     RRM_DATA_RES,
159     ECHO_REQUEST,
160     ECHO_RESPONSE,
161     I_AM_UP_REQ,
162     I_AM_UP_RES
163   }CNTLMsgType;
164
165 const value_string control_msg_vals[] = {
166     {DISCOVERY_REQUEST, "DISCOVERY_REQUEST"},
167     {DISCOVERY_REPLY, "DISCOVERY_REPLY"},
168     {JOIN_REQUEST, "JOIN_REQUEST"},
169     {JOIN_REPLY, "JOIN_REPLY"},
170     {HANDOFF_REQUEST, "HANDOFF_REQUEST"},
171     {HANDOFF_REPLY, "HANDOFF_REPLY"},
172     {HANDOFF_COMMAND, "HANDOFF_COMMAND"},
173     {HANDOFF_RESPONSE, "HANDOFF_RESPONSE"},
174     {HANDOFF_CONFIRM, "HANDOFF_CONFIRM"},
175     {CONFIGURE_REQUEST, "CONFIGURE_REQUEST"},
176     {CONFIGURE_RESPONSE, "CONFIGURE_RESPONSE"},
177     {CONFIGURE_COMMAND, "CONFIGURE_COMMAND"},
178     {CONFIGURE_COMMAND_RES, "CONFIGURE_COMMAND_RES"},
179     {STATISTICS_INFO, "STATISTICS_INFO"},
180     {CHANGE_STATE_EVENT, "CHANGE_STATE_EVENT"},
181     {CHANGE_STATE_EVENT_RES, "CHANGE_STATE_EVENT_RES"},
182     {RRM_CONTROL_REQ, "RRM_CONTROL_REQ"},
183     {RRM_CONTROL_RES, "RRM_CONTROL_RES"},
184     {RRM_DATA_REQ, "RRM_DATA_REQ"},
185     {RRM_DATA_RES, "RRM_DATA_RES"},
186     {ECHO_REQUEST, "ECHO_REQUEST"},
187     {ECHO_RESPONSE, "ECHO_RESPONSE"},
188     {I_AM_UP_REQ, "I_AM_UP_REQ"},
189     {I_AM_UP_RES, "I_AM_UP_RES"},
190
191     { 0, NULL}
192 };
193 const value_string control_tag_vals[] = {
194
195     {RESULT_CODE, "RESULT_CODE"},
196     {MWAR_ADDR_PAYLOAD, "MWAR_ADDR_PAYLOAD"},
197     {RAD_PAYLOAD, "RAD_PAYLOAD"},
198     {RAD_SLOT_PAYLOAD, "RAD_SLOT_PAYLOAD"},
199     {RAD_NAME_PAYLOAD, "RAD_NAME_PAYLOAD"},
200     {MWAR_PAYLOAD, "MWAR_PAYLOAD"},
201     {VAP_PAYLOAD, "VAP_PAYLOAD"},
202     {STATION_CFG_PAYLOAD, "STATION_CFG_PAYLOAD"},
203     {OPERATION_RATE_SET_PAYLOAD, "OPERATION_RATE_SET_PAYLOAD"},
204     {MULTI_DOMAIN_CAPABILITY_PAYLOAD, "MULTI_DOMAIN_CAPABILITY_PAYLOAD"},
205     {MAC_OPERATION_PAYLOAD, "MAC_OPERATION_PAYLOAD"},
206     {PHY_TX_POWER_PAYLOAD, "PHY_TX_POWER_PAYLOAD"},
207     {PHY_TX_POWER_LEVEL_PAYLOAD, "PHY_TX_POWER_LEVEL_PAYLOAD"},
208     {PHY_DSSS_PAYLOAD, "PHY_DSSS_PAYLOAD"},
209     {PHY_OFDM_PAYLOAD, "PHY_OFDM_PAYLOAD"},
210     {SUPPORTED_RATES_PAYLOAD, "SUPPORTED_RATES_PAYLOAD"},
211     {AUTH_PAYLOAD, "AUTH_PAYLOAD"},
212     {TEST_PAYLOAD, "TEST_PAYLOAD"},
213     {RRM_NEIGHBOR_CTRL_PAYLOAD, "RRM_NEIGHBOR_CTRL_PAYLOAD"},
214     {RRM_NOISE_CTRL_PAYLOAD, "RRM_NOISE_CTRL_PAYLOAD"},
215     {RRM_NOISE_DATA_PAYLOAD, "RRM_NOISE_DATA_PAYLOAD"},
216     {RRM_INTERFERENCE_CTRL_PAYLOAD, "RRM_INTERFERENCE_CTRL_PAYLOAD"},
217     {RRM_INTERFERENCE_DATA_PAYLOAD, "RRM_INTERFERENCE_DATA_PAYLOAD"},
218     {RRM_LOAD_CTRL_PAYLOAD, "RRM_LOAD_CTRL_PAYLOAD"},
219     {RRM_LOAD_DATA_PAYLOAD, "RRM_LOAD_DATA_PAYLOAD"},
220     {CHANGE_STATE_EVENT_PAYLOAD, "CHANGE_STATE_EVENT_PAYLOAD"},
221     {ADMIN_STATE_PAYLOAD, "ADMIN_STATE_PAYLOAD"},
222     {DELETE_VAP_PAYLOAD, "DELETE_VAP_PAYLOAD"},
223     {ADD_MOBILE_PAYLOAD, "ADD_MOBILE_PAYLOAD"},
224     {DELETE_MOBILE_PAYLOAD, "DELETE_MOBILE_PAYLOAD"},
225     {0, NULL}
226 };
227
228 static const true_false_string lwapp_flags_type = {
229     "LWAPP Control Packet" ,
230     "Encapsulated 80211"
231 };
232
233 static const true_false_string lwapp_set_truth = {
234     "Not Set",
235     "Set" 
236 };
237
238 /* 
239  * dissect lwapp control packets.  This is not fully implemented,
240  * but it's a good start.
241  */
242 static void dissect_control(tvbuff_t *tvb, packet_info *pinfo,
243                          proto_tree *tree)
244 {
245     CNTL_Header header;
246     proto_tree      *control_tree;
247     tvbuff_t        *next_tvb;
248
249     /* Set up structures needed to add the protocol subtree and manage it */
250     proto_item      *ti;
251     size_t           offset=0;
252
253     /* Make entries in Protocol column and Info column on summary display */
254     if (check_col(pinfo->cinfo, COL_PROTOCOL))
255         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP");
256     if (check_col(pinfo->cinfo, COL_INFO)) {
257         col_clear(pinfo->cinfo, COL_INFO);
258         col_add_str(pinfo->cinfo, COL_INFO,
259                     "CNTL ");
260     }
261
262     /* Copy our header */
263     tvb_memcpy(tvb, (guint8*) &header, offset, sizeof(header));
264
265     /* 
266      * Fix the length (network byte ordering), and set our version &
267      * slot id
268      */
269     header.length = g_ntohs(header.length);
270
271     if (check_col(pinfo->cinfo, COL_INFO)) {
272         col_append_str(pinfo->cinfo, COL_INFO,
273             val_to_str(header.type, control_msg_vals, "Bad Type: 0x%02x"));
274     }
275
276     /* In the interest of speed, if "tree" is NULL, don't do any work not
277        necessary to generate protocol tree items. */
278     if (tree) {
279         /* create display subtree for the protocol */
280         ti = proto_tree_add_item(tree, proto_lwapp_control, tvb, offset,
281                                  -1, FALSE);
282         control_tree = proto_item_add_subtree(ti, ett_lwapp_control);
283         
284         proto_tree_add_uint(control_tree, hf_lwapp_control_type, 
285                                tvb, offset, 1, header.type);
286         offset++;
287
288         proto_tree_add_uint(control_tree, hf_lwapp_control_seq_no, 
289                                tvb, offset, 1, header.seqNo);
290         offset++;
291
292         proto_tree_add_uint(control_tree, hf_lwapp_control_length, 
293                                tvb, offset, 2, header.length);
294         offset += 2;
295
296         /* Dissect rest of packet as data */
297         next_tvb = tvb_new_subset(tvb, offset, -1, -1);
298         call_dissector(data_handle,next_tvb, pinfo, tree);
299     }
300
301 } /* dissect_control */
302
303 /*
304  * This lwapp dissector assumes that there is an 802.3 header at
305  * the start of the packet, so it simply re-calls the ethernet
306  * dissector on the packet.
307  */
308 static void dissect_lwapp_l3(tvbuff_t *tvb, packet_info *pinfo,
309                             proto_tree *tree)
310 {
311     /* Set up structures needed to add the protocol subtree and manage it */
312     proto_item      *ti;
313     proto_tree      *lwapp_tree;
314     size_t           offset=0;
315     tvbuff_t        *next_client;
316
317     /* Make entries in Protocol column and Info column on summary display */
318     if (check_col(pinfo->cinfo, COL_PROTOCOL))
319         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP-L3");
320     if (check_col(pinfo->cinfo, COL_INFO)) {
321         col_clear(pinfo->cinfo, COL_INFO);
322         col_add_str(pinfo->cinfo, COL_INFO, "802.3 Packets over Layer 3");
323     }
324
325     if (tree) {
326         /* create display subtree for the protocol */
327         ti = proto_tree_add_item(tree, proto_lwapp_l3, tvb, offset,
328                                  -1, FALSE);
329         lwapp_tree = proto_item_add_subtree(ti, ett_lwapp_l3);
330     }
331
332     /* Dissect as Ethernet */
333     next_client = tvb_new_subset(tvb, 0, -1, -1);
334     call_dissector(eth_handle, next_client, pinfo, tree);
335     return;
336
337 } /* dissect_lwapp_l3*/
338
339
340 /*
341  * This dissector dissects the lwapp protocol itself.  It assumes an 
342  * lwapp payload in the data, and doesn't care whether the data was
343  * from a UDP packet, or a Layer 2 one.
344  */
345 static void dissect_lwapp(tvbuff_t *tvb, packet_info *pinfo,
346                         proto_tree *tree)
347 {
348     LWAPP_Header header;
349     guint8       slotId;
350     guint8       version;
351     proto_tree  *lwapp_tree;
352     proto_tree  *flags_tree;
353     tvbuff_t    *next_client;
354     char         dest_mac[6];
355     guint8       have_destmac=0;
356
357     /* Set up structures needed to add the protocol subtree and manage it */
358     proto_item      *ti;
359     size_t           offset=0;
360
361     /* Make entries in Protocol column and Info column on summary display */
362     if (check_col(pinfo->cinfo, COL_PROTOCOL))
363         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP");
364     if (check_col(pinfo->cinfo, COL_INFO)) {
365         col_clear(pinfo->cinfo, COL_INFO);
366         col_add_str(pinfo->cinfo, COL_INFO,
367                     "LWAPP IP or Layer 2");
368     }
369
370     /* First, set up our dest mac, if we're a control packet with a
371      * dest of port 12223 */
372     if (pinfo->destport == 12223 ) {
373         tvb_memcpy(tvb, (guint8*)dest_mac, offset, 6);
374         have_destmac = 1;
375         
376         /* Copy our header */
377         tvb_memcpy(tvb, (guint8*) &header, offset + 6, sizeof(header));
378     } else {
379
380         /* Copy our header */
381         tvb_memcpy(tvb, (guint8*) &header, offset, sizeof(header));
382     }
383
384
385     /* 
386      * Fix the length (network byte ordering), and set our version &
387      * slot id
388      */
389     header.length = g_ntohs(header.length);
390     version = (header.flags & 0xc0) >> 6;
391     slotId = (header.flags & 0x38) >> 3;
392
393     if (check_col(pinfo->cinfo, COL_INFO)) {
394         if ((header.flags & LWAPP_FLAGS_T) != 0)
395             col_append_str(pinfo->cinfo, COL_INFO,
396                            " Control Packet");
397         else
398             col_append_str(pinfo->cinfo, COL_INFO,
399                            " 802.11 Packet");
400     }
401
402     /* In the interest of speed, if "tree" is NULL, don't do any work not
403        necessary to generate protocol tree items. */
404     if (tree) {
405
406         /* create display subtree for the protocol */
407         ti = proto_tree_add_item(tree, proto_lwapp, tvb, offset,
408                                  tvb_length(tvb), FALSE);
409         lwapp_tree = proto_item_add_subtree(ti, ett_lwapp);
410
411         if (have_destmac) {
412             proto_tree_add_ether(lwapp_tree, hf_lwapp_control_mac, tvb, offset,
413                          6, dest_mac);
414             offset += 6;
415         }
416
417         proto_tree_add_uint(lwapp_tree, hf_lwapp_version, 
418                                tvb, offset, 1, version);
419         proto_tree_add_uint(lwapp_tree, hf_lwapp_slotid, 
420                                tvb, offset, 1, slotId);
421
422         flags_tree = proto_item_add_subtree(lwapp_tree, ett_lwapp_flags);
423         proto_tree_add_boolean(flags_tree, hf_lwapp_flags_type, 
424                                tvb, offset, 1, header.flags);
425         proto_tree_add_boolean(flags_tree, hf_lwapp_flags_fragment, 
426                                tvb, offset, 1, header.flags);
427         proto_tree_add_boolean(flags_tree, hf_lwapp_flags_fragment_type, 
428                                tvb, offset, 1, header.flags);
429         offset++;
430
431         proto_tree_add_uint(lwapp_tree, hf_lwapp_fragment_id, 
432                                tvb, offset, 1, header.fragmentId);
433         offset++;
434
435         proto_tree_add_uint(lwapp_tree, hf_lwapp_length, 
436                                tvb, offset, 2, header.length);
437         offset += 2;
438
439         proto_tree_add_uint(lwapp_tree, hf_lwapp_rssi, 
440                                tvb, offset, 1, header.rssi);
441         offset++;
442         proto_tree_add_uint(lwapp_tree, hf_lwapp_snr, 
443                                tvb, offset, 1, header.snr);
444         offset++;
445
446
447     }  /* tree */
448
449     next_client = tvb_new_subset(tvb, (have_destmac?6:0) + sizeof(LWAPP_Header), -1, -1);
450     if ((header.flags & LWAPP_FLAGS_T) == 0) {
451         call_dissector(swap_frame_control ? wlan_bsfc_handle : wlan_handle,
452                         next_client, pinfo, tree);
453     } else {
454         dissect_control(next_client, pinfo, tree);
455     }
456     return;
457
458 } /* dissect_lwapp*/
459
460 /* registration with the filtering engine */
461 void
462 proto_register_lwapp(void)
463 {
464     static hf_register_info hf[] = {
465         { &hf_lwapp_version,
466           { "Version", "lwapp.version", FT_UINT8, BASE_DEC, NULL, 0x00,
467             "", HFILL }},
468         { &hf_lwapp_slotid,
469           { "slotId","lwapp.slotId", FT_UINT24, BASE_DEC, NULL, 0x0,
470             "", HFILL }},
471         { &hf_lwapp_flags_type,
472           { "Type", "lwapp.flags.type", FT_BOOLEAN, 8, 
473             TFS(&lwapp_flags_type), LWAPP_FLAGS_T, "", HFILL }},
474         { &hf_lwapp_flags_fragment,
475           { "Fragment", "lwapp.flags.fragment", FT_BOOLEAN, 8,
476             TFS(&lwapp_set_truth), LWAPP_FLAGS_F,
477             "", HFILL }},
478         { &hf_lwapp_flags_fragment_type,
479           { "Fragment Type", "lwapp.flags.fragmentType", FT_BOOLEAN, 8,
480             TFS(&lwapp_set_truth), LWAPP_FLAGS_FT,
481             "", HFILL }},
482         { &hf_lwapp_fragment_id,
483           { "Fragment Id","lwapp.fragmentId", FT_UINT8, BASE_HEX,
484             NULL, 0x0, "", HFILL }},
485         { &hf_lwapp_length,
486           { "Length","lwapp.Length", FT_UINT16, BASE_DEC,
487             NULL, 0x0, "", HFILL }},
488         { &hf_lwapp_rssi,
489           { "RSSI","lwapp.rssi", FT_UINT8, BASE_HEX,
490             NULL, 0x0, "", HFILL }},
491         { &hf_lwapp_snr,
492           { "SNR","lwapp.snr", FT_UINT8, BASE_HEX,
493             NULL, 0x0, "", HFILL }},
494         { &hf_lwapp_control,
495           { "Control Data (not dissected yet)","lwapp.control", FT_BYTES, BASE_NONE,
496             NULL, 0x0, "", HFILL }},
497         { &hf_lwapp_control_mac,
498           { "AP Identity", "lwapp.apid", FT_ETHER, BASE_NONE, NULL, 0x0,
499               "Access Point Identity", HFILL }},
500         { &hf_lwapp_control_type,
501           { "Control Type", "lwapp.control.type", FT_UINT8, BASE_DEC, NULL, 0x00,
502             "", HFILL }},
503         { &hf_lwapp_control_seq_no,
504           { "Control Sequence Number", "lwapp.control.seqno", FT_UINT8, BASE_DEC, NULL, 0x00,
505             "", HFILL }},
506         { &hf_lwapp_control_length,
507           { "Control Length","lwapp.control.length", FT_UINT16, BASE_DEC,
508             NULL, 0x0, "", HFILL }},
509     };
510     static gint *ett[] = {
511         &ett_lwapp_l3,
512         &ett_lwapp,
513         &ett_lwapp_control,
514         &ett_lwapp_flags
515     };
516     module_t *lwapp_module;
517
518     proto_lwapp = proto_register_protocol ("LWAPP Encapsulated Packet", 
519                                          "LWAPP", "lwapp");
520
521     proto_lwapp_l3 = proto_register_protocol ("LWAPP Layer 3 Packet", 
522                                          "LWAPP-L3", "lwapp-l3");
523
524     proto_lwapp_control = proto_register_protocol ("LWAP Control Message", 
525                                          "LWAPP-CNTL", "lwapp-cntl");
526     proto_register_field_array(proto_lwapp, hf, array_length(hf));
527     proto_register_subtree_array(ett, array_length(ett));
528
529     lwapp_module = prefs_register_protocol(proto_lwapp, NULL);
530
531     prefs_register_bool_preference(lwapp_module,"swap_fc","Swap Frame Control",
532                                    "Swap frame control bytes (needed for some APs",
533                                     &swap_frame_control);
534
535 } /* proto_register_diameter */
536
537 void
538 proto_reg_handoff_lwapp(void)
539 {
540     dissector_handle_t lwapp_l3_handle;
541     dissector_handle_t lwapp_handle;
542
543     /*
544      * Get handles for the Ethernet and wireless dissectors.
545      */
546     eth_handle = find_dissector("eth");
547     wlan_handle = find_dissector("wlan");
548     wlan_bsfc_handle = find_dissector("wlan_bsfc");
549     data_handle = find_dissector("data");
550
551     /* This dissector assumes lwapp packets in an 802.3 frame */
552     lwapp_l3_handle = create_dissector_handle(dissect_lwapp_l3, proto_lwapp_l3);
553
554     /* This dissector assumes a lwapp packet */
555     lwapp_handle = create_dissector_handle(dissect_lwapp, proto_lwapp);
556
557     /*
558      * Ok, the following deserves some comments.  We have four 
559      * different ways lwapp can appear on the wire.  Mostly, this is
560      * because lwapp is such a new protocol.
561      * 
562      * First, lwapp can join on multiple udp ports, as encapsulated
563      * packets on top of UDP.  In this case, there is a full raw
564      * ethernet frame inside of the UDP packet.  This method is 
565      * becoming obscelete, but we still wanted to dissect the 
566      * packets.
567      *
568      * Next, lwapp can be over UDP, but packged for L3 tunneling.  This
569      * is the new-style.  In this case, LWAP headers are just transmitted
570      * via UDP.  
571      *
572      * The last method is lwapp directly over layer 2.  For this, we
573      * dissect two different ethertypes (until IANA gives us one)
574      *
575      */
576
577     /* Obsceleted LWAP via encapsulated 802.3 over UDP */
578
579     dissector_add("udp.port", 12220, lwapp_l3_handle);
580
581     /* new-style lwapp directly over UDP: L3-lwapp*/
582     dissector_add("udp.port", 12222, lwapp_handle);
583     dissector_add("udp.port", 12223, lwapp_handle);
584
585     /* Lwapp over L2 */
586     dissector_add("ethertype", 0x88bb, lwapp_handle);
587     dissector_add("ethertype", 0xbbbb, lwapp_handle);
588
589 }