ANNOUNCEMENT: Live Wireshark University & Allegro Packets online APAC Wireshark Training Session
July 17th, 2024 | 10:00am-11:55am SGT (UTC+8) | Online

Ethereal-dev: [Ethereal-dev] LWAPP Dissector

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: David Frascone <dave@xxxxxxxxxxxx>
Date: Fri, 29 Aug 2003 15:10:59 -0500
Attached is a patch file and source file for a dissector for LWAPP
(Light Weight Access Point Protocol).  It is currently chartering in the
IETF.

The dissector supports LWAPP over two L2 ethertypes (0xbbbb, and
0x88bb), and encapsulated in udp over port 12222.  It also support
encapsulated 802.3 over udp frames on port 12220.  All the types / ports
are currently needed as the protocol fleshes out.  I'll clean them up as
things get stabilized.  (Currently, it doesn't impact any other
dissectors)

Also, I'm resubmitting my 802.11 patch to add a flag (preference) to
swap the word on the frame control register.  Some atheros chipsets send
those over lwapp with the bytes swapped.  I'm not sure why it happens,
but since it's been going on for over a year, I don't think it's going
to get fixed any time soon, and I'd like to be able to see my traffic!

Dumps to test available upon request.

-Dave

-- 
David Frascone

          Iraq won the toss... and elected to receive.
Index: Makefile.am
===================================================================
RCS file: /cvsroot/ethereal/Makefile.am,v
retrieving revision 1.615
diff -u -r1.615 Makefile.am
--- Makefile.am	29 Aug 2003 02:27:28 -0000	1.615
+++ Makefile.am	29 Aug 2003 20:04:54 -0000
@@ -273,6 +273,7 @@
 	packet-lmi.c   \
 	packet-lmp.c   \
 	packet-lpd.c   \
+	packet-lwapp.c \
 	packet-m2pa.c  \
 	packet-m2tp.c  \
 	packet-m2ua.c  \
Index: Makefile.nmake
===================================================================
RCS file: /cvsroot/ethereal/Makefile.nmake,v
retrieving revision 1.328
diff -u -r1.328 Makefile.nmake
--- Makefile.nmake	29 Aug 2003 02:27:28 -0000	1.328
+++ Makefile.nmake	29 Aug 2003 20:04:55 -0000
@@ -214,6 +214,7 @@
 	packet-lmi.c   \
 	packet-lmp.c   \
 	packet-lpd.c   \
+	packet-lwapp.c \
 	packet-m2pa.c  \
 	packet-m2tp.c  \
 	packet-m2ua.c  \
Index: packet-ieee80211.c
===================================================================
RCS file: /cvsroot/ethereal/packet-ieee80211.c,v
retrieving revision 1.96
diff -u -r1.96 packet-ieee80211.c
--- packet-ieee80211.c	28 Aug 2003 04:19:28 -0000	1.96
+++ packet-ieee80211.c	29 Aug 2003 20:04:56 -0000
@@ -68,6 +68,9 @@
 /* Ignore the WEP bit; assume packet is decrypted */
 static gboolean wlan_ignore_wep = FALSE;
 
+/* Frame Control Broken */
+static gboolean wlan_broken_fc = FALSE;
+
 /* Tables for reassembly of fragments. */
 static GHashTable *wlan_fragment_table = NULL;
 static GHashTable *wlan_reassembled_table = NULL;
@@ -1291,6 +1294,11 @@
     col_clear (pinfo->cinfo, COL_INFO);
 
   fcf = tvb_get_letohs (tvb, 0);
+  if (wlan_broken_fc) {
+      // Swap bytes
+      fcf = ((fcf & 0xff) << 8) | (((fcf & 0xff00) >> 8) & 0xff);
+  }
+
   if (fixed_length_header)
     hdr_len = DATA_LONG_HDR_LEN;
   else
@@ -1331,10 +1339,11 @@
       }
 
       proto_tree_add_uint (hdr_tree, hf_fc_frame_type_subtype,
-			   tvb, 0, 1,
+			   tvb, wlan_broken_fc?1:0, 1,
 			   frame_type_subtype);
 
-      fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2,
+      fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 
+                                            wlan_broken_fc?1:0, 2,
 					    fcf,
 					    "Frame Control: 0x%04X",
 					    fcf);
@@ -1342,42 +1351,42 @@
       fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree);
 
 
-      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1,
+      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, wlan_broken_fc?1:0, 1,
 			   COOK_PROT_VERSION (fcf));
 
-      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1,
+      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, wlan_broken_fc?1:0, 1,
 			   COOK_FRAME_TYPE (fcf));
 
       proto_tree_add_uint (fc_tree, hf_fc_frame_subtype,
-			   tvb, 0, 1,
+			   tvb, wlan_broken_fc?1:0, 1,
 			   COOK_FRAME_SUBTYPE (fcf));
 
       flag_item =
-	proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
+	proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, wlan_broken_fc?0:1, 1,
 				    flags, "Flags: 0x%X", flags);
 
       flag_tree = proto_item_add_subtree (flag_item, ett_proto_flags);
 
-      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 1, 1,
+      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, wlan_broken_fc?0:1, 1,
 			   COOK_DS_STATUS (flags));
       proto_tree_add_boolean_hidden (flag_tree, hf_fc_to_ds, tvb, 1, 1, 
 				     flags);
       proto_tree_add_boolean_hidden (flag_tree, hf_fc_from_ds, tvb, 1, 1, 
 				     flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1,
+      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, wlan_broken_fc?0:1, 1,
 			      flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 1, 1,
+      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, wlan_broken_fc?0:1, 1,
 			      flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, wlan_broken_fc?0:1, 1, flags);
 
       if (frame_type_subtype == CTRL_PS_POLL)
 	proto_tree_add_uint(hdr_tree, hf_assoc_id,tvb,2,2,
@@ -2513,6 +2522,11 @@
 				 "Ignore the WEP bit",
 				 "Some 802.11 cards leave the WEP bit set even though the packet is decrypted.",
 				 &wlan_ignore_wep);
+
+  prefs_register_bool_preference(wlan_module, "broken_fc",
+				 "Swapped Frame Control",
+				 "Some 802.11 access points swap the Frame Control bytes.",
+				 &wlan_broken_fc);
 
 #ifndef USE_ENV
   prefs_register_enum_preference(wlan_module, "wep_keys",
/* packet-lwapp.c
 *
 * Routines for LWAPP encapsulated packet disassembly
 *
 * $Id: packet-lwapp.c,v 1.2 2003/08/29 16:56:13 codemonkey Exp $
 *
 * Copyright (c) 2003 by David Frascone <dave@xxxxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <glib.h>
#include <epan/filesystem.h>
#include "xmlstub.h"
#include <epan/packet.h>
#include <epan/resolv.h>
#include "prefs.h"


#ifdef NEED_SNPRINTF_H
# include "snprintf.h"
#endif

#define LWAPP_FLAGS_T 0x04
#define LWAPP_FLAGS_F 0x02
#define LWAPP_FLAGS_FT 0x01

static gint proto_lwapp = -1;
static gint proto_lwapp_l3 = -1;
static gint proto_lwapp_control = -1;
static gint ett_lwapp = -1;
static gint ett_lwapp_l3 = -1;
static gint ett_lwapp_flags = -1;
static gint ett_lwapp_control = -1;

static gint hf_lwapp_version = -1;
static gint hf_lwapp_slotid = -1;
static gint hf_lwapp_flags_type = -1;
static gint hf_lwapp_flags_fragment = -1;
static gint hf_lwapp_flags_fragment_type = -1;
static gint hf_lwapp_fragment_id = -1;
static gint hf_lwapp_length = -1;
static gint hf_lwapp_rssi = -1;
static gint hf_lwapp_snr = -1;
static gint hf_lwapp_control = -1;
static gint hf_lwapp_control_type = -1;
static gint hf_lwapp_control_seq_no = -1;
static gint hf_lwapp_control_length = -1;

static dissector_handle_t eth_handle;
static dissector_handle_t wlan_handle;
static dissector_handle_t data_handle;

typedef struct {
    guint8 flags;
    guint8 fragmentId;
    guint16 length;
    guint8 rssi;
    guint8 snr;
} LWAPP_Header;

typedef struct {
    guint8   tag;
    guint16  length;
} CNTL_Data_Header;

typedef struct {
    guint8    type;
    guint8    seqNo;
    guint16   length;
} CNTL_Header;

typedef enum {
    RESULT_CODE = 1,
    MWAR_ADDR_PAYLOAD,
    RAD_PAYLOAD,
    RAD_SLOT_PAYLOAD,
    RAD_NAME_PAYLOAD,
    MWAR_PAYLOAD,
    VAP_PAYLOAD,
    STATION_CFG_PAYLOAD,
    OPERATION_RATE_SET_PAYLOAD,
    MULTI_DOMAIN_CAPABILITY_PAYLOAD,
    MAC_OPERATION_PAYLOAD,
    PHY_TX_POWER_PAYLOAD,
    PHY_TX_POWER_LEVEL_PAYLOAD,
    PHY_DSSS_PAYLOAD,
    PHY_OFDM_PAYLOAD,
    SUPPORTED_RATES_PAYLOAD,
    AUTH_PAYLOAD,
    TEST_PAYLOAD,
    RRM_NEIGHBOR_CTRL_PAYLOAD,
    RRM_NOISE_CTRL_PAYLOAD,
    RRM_NOISE_DATA_PAYLOAD,
    RRM_INTERFERENCE_CTRL_PAYLOAD,
    RRM_INTERFERENCE_DATA_PAYLOAD,
    RRM_LOAD_CTRL_PAYLOAD,
    RRM_LOAD_DATA_PAYLOAD,
    CHANGE_STATE_EVENT_PAYLOAD,
    ADMIN_STATE_PAYLOAD,
    DELETE_VAP_PAYLOAD,
    ADD_MOBILE_PAYLOAD,
    DELETE_MOBILE_PAYLOAD
} control_tags;

typedef enum
  {
    DISCOVERY_REQUEST = 1,
    DISCOVERY_REPLY,
    JOIN_REQUEST,
    JOIN_REPLY,
    HANDOFF_REQUEST,
    HANDOFF_REPLY,
    HANDOFF_COMMAND,
    HANDOFF_RESPONSE,
    HANDOFF_CONFIRM,
    CONFIGURE_REQUEST,
    CONFIGURE_RESPONSE,
    CONFIGURE_COMMAND,
    CONFIGURE_COMMAND_RES,
    STATISTICS_INFO,
    CHANGE_STATE_EVENT,
    CHANGE_STATE_EVENT_RES,
    RRM_CONTROL_REQ,
    RRM_CONTROL_RES,
    RRM_DATA_REQ,
    RRM_DATA_RES,
    ECHO_REQUEST,
    ECHO_RESPONSE,
    I_AM_UP_REQ,
    I_AM_UP_RES
  }CNTLMsgType;

const value_string control_msg_vals[] = {
    {DISCOVERY_REQUEST, "DISCOVERY_REQUEST"},
    {DISCOVERY_REPLY, "DISCOVERY_REPLY"},
    {JOIN_REQUEST, "JOIN_REQUEST"},
    {JOIN_REPLY, "JOIN_REPLY"},
    {HANDOFF_REQUEST, "HANDOFF_REQUEST"},
    {HANDOFF_REPLY, "HANDOFF_REPLY"},
    {HANDOFF_COMMAND, "HANDOFF_COMMAND"},
    {HANDOFF_RESPONSE, "HANDOFF_RESPONSE"},
    {HANDOFF_CONFIRM, "HANDOFF_CONFIRM"},
    {CONFIGURE_REQUEST, "CONFIGURE_REQUEST"},
    {CONFIGURE_RESPONSE, "CONFIGURE_RESPONSE"},
    {CONFIGURE_COMMAND, "CONFIGURE_COMMAND"},
    {CONFIGURE_COMMAND_RES, "CONFIGURE_COMMAND_RES"},
    {STATISTICS_INFO, "STATISTICS_INFO"},
    {CHANGE_STATE_EVENT, "CHANGE_STATE_EVENT"},
    {CHANGE_STATE_EVENT_RES, "CHANGE_STATE_EVENT_RES"},
    {RRM_CONTROL_REQ, "RRM_CONTROL_REQ"},
    {RRM_CONTROL_RES, "RRM_CONTROL_RES"},
    {RRM_DATA_REQ, "RRM_DATA_REQ"},
    {RRM_DATA_RES, "RRM_DATA_RES"},
    {ECHO_REQUEST, "ECHO_REQUEST"},
    {ECHO_RESPONSE, "ECHO_RESPONSE"},
    {I_AM_UP_REQ, "I_AM_UP_REQ"},
    {I_AM_UP_RES, "I_AM_UP_RES"},

    { 0, NULL}
};
const value_string control_tag_vals[] = {

    {RESULT_CODE, "RESULT_CODE"},
    {MWAR_ADDR_PAYLOAD, "MWAR_ADDR_PAYLOAD"},
    {RAD_PAYLOAD, "RAD_PAYLOAD"},
    {RAD_SLOT_PAYLOAD, "RAD_SLOT_PAYLOAD"},
    {RAD_NAME_PAYLOAD, "RAD_NAME_PAYLOAD"},
    {MWAR_PAYLOAD, "MWAR_PAYLOAD"},
    {VAP_PAYLOAD, "VAP_PAYLOAD"},
    {STATION_CFG_PAYLOAD, "STATION_CFG_PAYLOAD"},
    {OPERATION_RATE_SET_PAYLOAD, "OPERATION_RATE_SET_PAYLOAD"},
    {MULTI_DOMAIN_CAPABILITY_PAYLOAD, "MULTI_DOMAIN_CAPABILITY_PAYLOAD"},
    {MAC_OPERATION_PAYLOAD, "MAC_OPERATION_PAYLOAD"},
    {PHY_TX_POWER_PAYLOAD, "PHY_TX_POWER_PAYLOAD"},
    {PHY_TX_POWER_LEVEL_PAYLOAD, "PHY_TX_POWER_LEVEL_PAYLOAD"},
    {PHY_DSSS_PAYLOAD, "PHY_DSSS_PAYLOAD"},
    {PHY_OFDM_PAYLOAD, "PHY_OFDM_PAYLOAD"},
    {SUPPORTED_RATES_PAYLOAD, "SUPPORTED_RATES_PAYLOAD"},
    {AUTH_PAYLOAD, "AUTH_PAYLOAD"},
    {TEST_PAYLOAD, "TEST_PAYLOAD"},
    {RRM_NEIGHBOR_CTRL_PAYLOAD, "RRM_NEIGHBOR_CTRL_PAYLOAD"},
    {RRM_NOISE_CTRL_PAYLOAD, "RRM_NOISE_CTRL_PAYLOAD"},
    {RRM_NOISE_DATA_PAYLOAD, "RRM_NOISE_DATA_PAYLOAD"},
    {RRM_INTERFERENCE_CTRL_PAYLOAD, "RRM_INTERFERENCE_CTRL_PAYLOAD"},
    {RRM_INTERFERENCE_DATA_PAYLOAD, "RRM_INTERFERENCE_DATA_PAYLOAD"},
    {RRM_LOAD_CTRL_PAYLOAD, "RRM_LOAD_CTRL_PAYLOAD"},
    {RRM_LOAD_DATA_PAYLOAD, "RRM_LOAD_DATA_PAYLOAD"},
    {CHANGE_STATE_EVENT_PAYLOAD, "CHANGE_STATE_EVENT_PAYLOAD"},
    {ADMIN_STATE_PAYLOAD, "ADMIN_STATE_PAYLOAD"},
    {DELETE_VAP_PAYLOAD, "DELETE_VAP_PAYLOAD"},
    {ADD_MOBILE_PAYLOAD, "ADD_MOBILE_PAYLOAD"},
    {DELETE_MOBILE_PAYLOAD, "DELETE_MOBILE_PAYLOAD"},
    {0, NULL}
};

static const true_false_string lwapp_flags_type = {
    "LWAPP Control Packet" ,
    "Encapsulated 80211"
};

static const true_false_string lwapp_set_truth = {
    "Not Set",
    "Set" 
};

/* 
 * dissect lwapp control packets.  This is not fully implemented,
 * but it's a good start.
 */
static void dissect_control(tvbuff_t *tvb, packet_info *pinfo,
                         proto_tree *tree)
{
    CNTL_Header header;
    proto_tree      *control_tree;
    tvbuff_t        *next_tvb;

    /* Set up structures needed to add the protocol subtree and manage it */
    proto_item      *ti;
    size_t           offset=0;

    /* Make entries in Protocol column and Info column on summary display */
    if (check_col(pinfo->cinfo, COL_PROTOCOL))
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP");
    if (check_col(pinfo->cinfo, COL_INFO)) {
	col_clear(pinfo->cinfo, COL_INFO);
        col_add_str(pinfo->cinfo, COL_INFO,
                    "CNTL ");
    }

    /* Copy our header */
    tvb_memcpy(tvb, (guint8*) &header, offset, sizeof(header));

    /* 
     * Fix the length (network byte ordering), and set our version &
     * slot id
     */
    header.length = g_ntohs(header.length);

    if (check_col(pinfo->cinfo, COL_INFO)) {
        gchar *description;

        description = match_strval(header.type, control_msg_vals);
        if (!description) {
            description = alloca(120);
            sprintf(description, "Bad Type: 0x%02x", header.type);
        }
        col_append_str(pinfo->cinfo, COL_INFO, description);
    }

    /* In the interest of speed, if "tree" is NULL, don't do any work not
       necessary to generate protocol tree items. */
    if (tree) {
	/* create display subtree for the protocol */
	ti = proto_tree_add_item(tree, proto_lwapp_control, tvb, offset,
				 -1, FALSE);
	control_tree = proto_item_add_subtree(ti, ett_lwapp_control);
        
	proto_tree_add_uint(control_tree, hf_lwapp_control_type, 
                               tvb, offset, 1, header.type);
        offset++;

	proto_tree_add_uint(control_tree, hf_lwapp_control_seq_no, 
                               tvb, offset, 1, header.seqNo);
        offset++;

	proto_tree_add_uint(control_tree, hf_lwapp_control_length, 
                               tvb, offset, 2, header.length);
        offset += 2;

        /* Dissect rest of packet as data */
        next_tvb = tvb_new_subset(tvb, offset, -1, -1);
        call_dissector(data_handle,next_tvb, pinfo, tree);
    }

} /* dissect_control */

/*
 * This lwapp dissector assumes that there is an 802.3 header at
 * the start of the packet, so it simply re-calls the ethernet
 * dissector on the packet.
 */
static void dissect_lwapp_l3(tvbuff_t *tvb, packet_info *pinfo,
                            proto_tree *tree)
{
    /* Set up structures needed to add the protocol subtree and manage it */
    proto_item      *ti;
    proto_tree      *lwapp_tree;
    size_t           offset=0;
    tvbuff_t        *next_client;

    /* Make entries in Protocol column and Info column on summary display */
    if (check_col(pinfo->cinfo, COL_PROTOCOL))
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP-L3");
    if (check_col(pinfo->cinfo, COL_INFO)) {
	col_clear(pinfo->cinfo, COL_INFO);
        col_add_str(pinfo->cinfo, COL_INFO, "802.3 Packets over Layer 3");
    }

    if (tree) {
	/* create display subtree for the protocol */
	ti = proto_tree_add_item(tree, proto_lwapp_l3, tvb, offset,
				 -1, FALSE);
	lwapp_tree = proto_item_add_subtree(ti, ett_lwapp_l3);
    }

    /* Dissect as Ethernet */
    next_client	= tvb_new_subset(tvb, 0, -1, -1);
    call_dissector(eth_handle, next_client, pinfo, tree);
    return;

} /* dissect_lwapp_l3*/


/*
 * This dissector dissects the lwapp protocol itself.  It assumes an 
 * lwapp payload in the data, and doesn't care whether the data was
 * from a UDP packet, or a Layer 2 one.
 */
static void dissect_lwapp(tvbuff_t *tvb, packet_info *pinfo,
                        proto_tree *tree)
{
    LWAPP_Header header;
    guint8     slotId;
    guint8     version;
    proto_tree      *lwapp_tree;
    proto_tree      *flags_tree;
    tvbuff_t        *next_client;

    /* Set up structures needed to add the protocol subtree and manage it */
    proto_item      *ti;
    size_t           offset=0;

    /* Make entries in Protocol column and Info column on summary display */
    if (check_col(pinfo->cinfo, COL_PROTOCOL))
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "LWAPP");
    if (check_col(pinfo->cinfo, COL_INFO)) {
	col_clear(pinfo->cinfo, COL_INFO);
        col_add_str(pinfo->cinfo, COL_INFO,
                    "LWAPP IP or Layer 2");
    }

    /* Copy our header */
    tvb_memcpy(tvb, (guint8*) &header, offset, sizeof(header));

    /* 
     * Fix the length (network byte ordering), and set our version &
     * slot id
     */
    header.length = g_ntohs(header.length);
    version = (header.flags & 0xc0) >> 6;
    slotId = (header.flags & 0x38) >> 3;

    if (check_col(pinfo->cinfo, COL_INFO)) {
        if ((header.flags & LWAPP_FLAGS_T) != 0)
            col_append_str(pinfo->cinfo, COL_INFO,
                           " Control Packet");
        else
            col_append_str(pinfo->cinfo, COL_INFO,
                           " 802.11 Packet");
    }

    /* In the interest of speed, if "tree" is NULL, don't do any work not
       necessary to generate protocol tree items. */
    if (tree) {

	/* create display subtree for the protocol */
	ti = proto_tree_add_item(tree, proto_lwapp, tvb, offset,
				 tvb_length(tvb), FALSE);
	lwapp_tree = proto_item_add_subtree(ti, ett_lwapp);

	proto_tree_add_uint(lwapp_tree, hf_lwapp_version, 
                               tvb, offset, 1, version);
	proto_tree_add_uint(lwapp_tree, hf_lwapp_slotid, 
                               tvb, offset, 1, slotId);

	flags_tree = proto_item_add_subtree(lwapp_tree, ett_lwapp_flags);
	proto_tree_add_boolean(flags_tree, hf_lwapp_flags_type, 
                               tvb, offset, 1, header.flags);
	proto_tree_add_boolean(flags_tree, hf_lwapp_flags_fragment, 
                               tvb, offset, 1, header.flags);
	proto_tree_add_boolean(flags_tree, hf_lwapp_flags_fragment_type, 
                               tvb, offset, 1, header.flags);
        offset++;

	proto_tree_add_uint(lwapp_tree, hf_lwapp_fragment_id, 
                               tvb, offset, 1, header.fragmentId);
        offset++;

	proto_tree_add_uint(lwapp_tree, hf_lwapp_length, 
                               tvb, offset, 2, header.length);
        offset += 2;

	proto_tree_add_uint(lwapp_tree, hf_lwapp_rssi, 
                               tvb, offset, 1, header.rssi);
        offset++;
	proto_tree_add_uint(lwapp_tree, hf_lwapp_snr, 
                               tvb, offset, 1, header.snr);
        offset++;


    }  /* tree */

    if ((header.flags & LWAPP_FLAGS_T) == 0) {
        next_client	= tvb_new_subset(tvb, sizeof(LWAPP_Header), -1, -1);
        call_dissector(wlan_handle, next_client, pinfo, tree);
    } else {
        next_client	= tvb_new_subset(tvb, sizeof(LWAPP_Header), -1, -1);
        dissect_control(next_client, pinfo, tree);
    }
    return;

} /* dissect_lwapp*/

/* registration with the filtering engine */
void
proto_register_lwapp(void)
{
    static hf_register_info hf[] = {
        { &hf_lwapp_version,
          { "Version", "lwapp.version", FT_UINT8, BASE_DEC, NULL, 0x00,
            "", HFILL }},
        { &hf_lwapp_slotid,
          { "slotId","lwapp.slotId", FT_UINT24, BASE_DEC, NULL, 0x0,
            "", HFILL }},
        { &hf_lwapp_flags_type,
          { "Type", "lwapp.flags.type", FT_BOOLEAN, 8, 
            TFS(&lwapp_flags_type), LWAPP_FLAGS_T, "", HFILL }},
        { &hf_lwapp_flags_fragment,
          { "Fragment", "lwapp.flags.fragment", FT_BOOLEAN, 8,
            TFS(&lwapp_set_truth), LWAPP_FLAGS_F,
            "", HFILL }},
        { &hf_lwapp_flags_fragment_type,
          { "Fragment Type", "lwapp.flags.fragmentType", FT_BOOLEAN, 8,
            TFS(&lwapp_set_truth), LWAPP_FLAGS_FT,
            "", HFILL }},
        { &hf_lwapp_fragment_id,
          { "Fragment Id","lwapp.fragmentId", FT_UINT8, BASE_HEX,
            NULL, 0x0, "", HFILL }},
        { &hf_lwapp_length,
          { "Length","lwapp.Length", FT_UINT16, BASE_DEC,
            NULL, 0x0, "", HFILL }},
        { &hf_lwapp_rssi,
          { "RSSI","lwapp.rssi", FT_UINT8, BASE_HEX,
            NULL, 0x0, "", HFILL }},
        { &hf_lwapp_snr,
          { "SNR","lwapp.snr", FT_UINT8, BASE_HEX,
            NULL, 0x0, "", HFILL }},
        { &hf_lwapp_control,
          { "Control Data (not dissected yet)","lwapp.control", FT_BYTES, BASE_NONE,
            NULL, 0x0, "", HFILL }},
        { &hf_lwapp_control_type,
          { "Control Type", "lwapp.control.type", FT_UINT8, BASE_DEC, NULL, 0x00,
            "", HFILL }},
        { &hf_lwapp_control_seq_no,
          { "Control Sequence Number", "lwapp.control.seqno", FT_UINT8, BASE_DEC, NULL, 0x00,
            "", HFILL }},
        { &hf_lwapp_control_length,
          { "Control Length","lwapp.control.length", FT_UINT16, BASE_DEC,
            NULL, 0x0, "", HFILL }},
    };
    static gint *ett[] = {
        &ett_lwapp_l3,
        &ett_lwapp,
        &ett_lwapp_control,
        &ett_lwapp_flags
    };

    proto_lwapp = proto_register_protocol ("LWAPP Encapsulated Packet", 
                                         "LWAPP", "lwapp");

    proto_lwapp_l3 = proto_register_protocol ("LWAPP Layer 3 Packet", 
                                         "LWAPP-L3", "lwapp-l3");

    proto_lwapp_control = proto_register_protocol ("LWAP Control Message", 
                                         "LWAPP-CNTL", "lwapp-cntl");
    proto_register_field_array(proto_lwapp, hf, array_length(hf));
    proto_register_subtree_array(ett, array_length(ett));

} /* proto_register_diameter */

void
proto_reg_handoff_lwapp(void)
{
    dissector_handle_t lwapp_l3_handle;
    dissector_handle_t lwapp_handle;

    /*
     * Get handles for the Ethernet, and wireless dissectors.
     */
    eth_handle = find_dissector("eth");
    wlan_handle = find_dissector("wlan");
    data_handle = find_dissector("data");


    /* This dissector assumes lwapp packets in an 802.3 frame */
    lwapp_l3_handle = create_dissector_handle(dissect_lwapp_l3, proto_lwapp_l3);

    /* This dissector assumes a lwapp packet */
    lwapp_handle = create_dissector_handle(dissect_lwapp, proto_lwapp);

    /*
     * Ok, the following deserves some comments.  We have four 
     * different ways lwapp can appear on the wire.  Mostly, this is
     * because lwapp is such a new protocol.
     * 
     * First, lwapp can join on multiple udp ports, as encapsulated
     * packets on top of UDP.  In this case, there is a full raw
     * ethernet frame inside of the UDP packet.  This method is 
     * becoming obscelete, but we still wanted to dissect the 
     * packets.
     *
     * Next, lwapp can be over UDP, but packged for L3 tunneling.  This
     * is the new-style.  In this case, LWAP headers are just transmitted
     * via UDP.  
     *
     * The last method is lwapp directly over layer 2.  For this, we
     * dissect two different ethertypes (until IANA gives us one)
     *
     */

    /* Obsceleted LWAP via encapsulated 802.3 over UDP */

    dissector_add("udp.port", 12220, lwapp_l3_handle);

    /* new-style lwapp directly over UDP: L3-lwapp*/
    dissector_add("udp.port", 12222, lwapp_handle);

    /* Lwapp over L2 */
    dissector_add("ethertype", 0x88bb, lwapp_handle);
    dissector_add("ethertype", 0xbbbb, lwapp_handle);

}