/* packet-lwapp.c * * Routines for LWAPP encapsulated packet disassembly * draft-calhoun-seamoby-lwapp-N (the current draft is 3) * * $Id: packet-lwapp.c,v 1.4 2003/09/24 23:35:39 guy Exp $ * * Copyright (c) 2003 by David Frascone * * Ethereal - Network traffic analyzer * By Gerald Combs * 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 #include #include #include #include #include #include #include "xmlstub.h" #include #include #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 wlan_bsfc_handle; static dissector_handle_t data_handle; /* Set by preferences */ static gboolean swap_frame_control; 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)) { col_append_str(pinfo->cinfo, COL_INFO, val_to_str(header.type, control_msg_vals, "Bad Type: 0x%02x")); } /* 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 */ next_client = tvb_new_subset(tvb, sizeof(LWAPP_Header), -1, -1); if ((header.flags & LWAPP_FLAGS_T) == 0) { call_dissector(swap_frame_control ? wlan_bsfc_handle : wlan_handle, next_client, pinfo, tree); } else { 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 }; module_t *lwapp_module; 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)); lwapp_module = prefs_register_protocol(proto_lwapp, NULL); prefs_register_bool_preference(lwapp_module,"swap_fc","Swap Frame Control", "Swap frame control bytes (needed for some APs", &swap_frame_control); } /* 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"); wlan_bsfc_handle = find_dissector("wlan_bsfc"); 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); }