From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- plugins/epan/wimaxasncp/AUTHORS | 5 + plugins/epan/wimaxasncp/CMakeLists.txt | 70 + plugins/epan/wimaxasncp/ChangeLog | 16 + plugins/epan/wimaxasncp/packet-wimaxasncp.c | 3468 +++++++++++++++++++++++++++ plugins/epan/wimaxasncp/wimaxasncp_dict.h | 114 + plugins/epan/wimaxasncp/wimaxasncp_dict.l | 867 +++++++ 6 files changed, 4540 insertions(+) create mode 100644 plugins/epan/wimaxasncp/AUTHORS create mode 100644 plugins/epan/wimaxasncp/CMakeLists.txt create mode 100644 plugins/epan/wimaxasncp/ChangeLog create mode 100644 plugins/epan/wimaxasncp/packet-wimaxasncp.c create mode 100644 plugins/epan/wimaxasncp/wimaxasncp_dict.h create mode 100644 plugins/epan/wimaxasncp/wimaxasncp_dict.l (limited to 'plugins/epan/wimaxasncp') diff --git a/plugins/epan/wimaxasncp/AUTHORS b/plugins/epan/wimaxasncp/AUTHORS new file mode 100644 index 0000000..4a80a58 --- /dev/null +++ b/plugins/epan/wimaxasncp/AUTHORS @@ -0,0 +1,5 @@ +Authors : +Stephen Croll +Zhang Li +Wu Yanping +Terry Le diff --git a/plugins/epan/wimaxasncp/CMakeLists.txt b/plugins/epan/wimaxasncp/CMakeLists.txt new file mode 100644 index 0000000..4775ef9 --- /dev/null +++ b/plugins/epan/wimaxasncp/CMakeLists.txt @@ -0,0 +1,70 @@ +# CMakeLists.txt +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +include(WiresharkPlugin) + +# Plugin name and version info (major minor micro extra) +set_module_info(wimaxasncp 0 0 1 0) + +set(DISSECTOR_SRC + packet-wimaxasncp.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} +) + +add_lex_files(LEX_FILES PLUGIN_FILES + wimaxasncp_dict.l +) + +set_source_files_properties( + ${DISSECTOR_SRC} + PROPERTIES + COMPILE_FLAGS "${WERROR_COMMON_FLAGS}" +) + +register_plugin_files(plugin.c + plugin + ${DISSECTOR_SRC} +) + +add_wireshark_plugin_library(wimaxasncp epan) + +target_link_libraries(wimaxasncp epan) + +install_plugin(wimaxasncp epan) + +file(GLOB DISSECTOR_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.h") +CHECKAPI( + NAME + wimaxasncp + SWITCHES + --group dissectors-prohibited + --group dissectors-restricted + SOURCES + ${DISSECTOR_SRC} + ${DISSECTOR_HEADERS} +# LEX files commented out due to use of malloc, free etc. +# ${LEX_FILES} +) + +# +# Editor modelines - https://www.wireshark.org/tools/modelines.html +# +# Local variables: +# c-basic-offset: 8 +# tab-width: 8 +# indent-tabs-mode: t +# End: +# +# vi: set shiftwidth=8 tabstop=8 noexpandtab: +# :indentSize=8:tabSize=8:noTabs=false: +# diff --git a/plugins/epan/wimaxasncp/ChangeLog b/plugins/epan/wimaxasncp/ChangeLog new file mode 100644 index 0000000..dccc530 --- /dev/null +++ b/plugins/epan/wimaxasncp/ChangeLog @@ -0,0 +1,16 @@ +2007-08-29 Stephen Croll + + * initial version + +2007-10-09 Stephen Croll + + * TLVs defined in XML files. + + * packet-wimaxasncp.c: fixed memory leak in function + wimaxasncp_dissect_tlv_value() + +2007-11-04 Zhang Li + + * Add EAP support. EAP payload is dessected by calling EAP dissector + * Add port preference. + diff --git a/plugins/epan/wimaxasncp/packet-wimaxasncp.c b/plugins/epan/wimaxasncp/packet-wimaxasncp.c new file mode 100644 index 0000000..082d9ea --- /dev/null +++ b/plugins/epan/wimaxasncp/packet-wimaxasncp.c @@ -0,0 +1,3468 @@ +/* packet-wimaxasncp.c + * + * Routines for WiMAX ASN Control Plane packet dissection dissection + * + * Copyright 2007, Mobile Metrics - http://www.mobilemetrics.net + * + * Author: Stephen Croll + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wimaxasncp_dict.h" + +/* Forward declarations we need below */ +void proto_register_wimaxasncp(void); +void proto_reg_handoff_wimaxasncp(void); + +/* Initialize the protocol and registered fields */ +static int proto_wimaxasncp = -1; +static int hf_wimaxasncp_version = -1; +static int hf_wimaxasncp_flags = -1; +static int hf_wimaxasncp_function_type = -1; +static int hf_wimaxasncp_op_id = -1; +static int hf_wimaxasncp_message_type = -1; +/* static int hf_wimaxasncp_qos_msg = -1; */ +/* static int hf_wimaxasncp_ho_control_msg = -1; */ +/* static int hf_wimaxasncp_data_path_control_msg = -1; */ +/* static int hf_wimaxasncp_context_delivery_msg = -1; */ +/* static int hf_wimaxasncp_r3_mobility_msg = -1; */ +/* static int hf_wimaxasncp_paging_msg = -1; */ +/* static int hf_wimaxasncp_rrm_msg = -1; */ +/* static int hf_wimaxasncp_authentication_msg = -1; */ +/* static int hf_wimaxasncp_ms_state_msg = -1; */ +/* static int hf_wimaxasncp_reauthentication_msg = -1; */ +/* static int hf_wimaxasncp_session_msg = -1; */ +static int hf_wimaxasncp_length = -1; +static int hf_wimaxasncp_msid = -1; +static int hf_wimaxasncp_reserved1 = -1; +static int hf_wimaxasncp_transaction_id = -1; +static int hf_wimaxasncp_reserved2 = -1; +/* static int hf_wimaxasncp_tlv = -1; */ +static int hf_wimaxasncp_tlv_type = -1; +static int hf_wimaxasncp_tlv_length = -1; +static int hf_wimaxasncp_tlv_value_bytes = -1; +static int hf_wimaxasncp_tlv_value_bitflags8 = -1; +static int hf_wimaxasncp_tlv_value_bitflags16 = -1; +static int hf_wimaxasncp_tlv_value_bitflags32 = -1; +/* static int hf_wimaxasncp_tlv_value_protocol = -1; */ +/* static int hf_wimaxasncp_tlv_value_vendor_id = -1; */ + +/* Preferences */ +static gboolean show_transaction_id_d_bit = FALSE; +static gboolean debug_enabled = FALSE; + +/* Default WiMAX ASN control protocol port */ +#define WIMAXASNCP_DEF_UDP_PORT 2231 + + +/* Initialize the subtree pointers */ +static gint ett_wimaxasncp = -1; +static gint ett_wimaxasncp_flags = -1; +static gint ett_wimaxasncp_tlv = -1; +static gint ett_wimaxasncp_tlv_value_bitflags8 = -1; +static gint ett_wimaxasncp_tlv_value_bitflags16 = -1; +static gint ett_wimaxasncp_tlv_value_bitflags32 = -1; +static gint ett_wimaxasncp_tlv_protocol_list = -1; +static gint ett_wimaxasncp_tlv_port_range_list = -1; +static gint ett_wimaxasncp_tlv_ip_address_mask_list = -1; +static gint ett_wimaxasncp_tlv_ip_address_mask = -1; +static gint ett_wimaxasncp_tlv_eap = -1; +static gint ett_wimaxasncp_tlv_vendor_specific_information_field = -1; +static gint ett_wimaxasncp_port_range = -1; + +static expert_field ei_wimaxasncp_tlv_type = EI_INIT; +static expert_field ei_wimaxasncp_function_type = EI_INIT; +static expert_field ei_wimaxasncp_op_id = EI_INIT; +static expert_field ei_wimaxasncp_message_type = EI_INIT; +static expert_field ei_wimaxasncp_length_bad = EI_INIT; + +/* Header size, up to, but not including, the TLV fields. */ +#define WIMAXASNCP_HEADER_SIZE 20 + +/* Offset to end of the length field in the headder. */ +#define WIMAXASNCP_HEADER_LENGTH_END 6 + +#define WIMAXASNCP_BIT32(n) (1U << (31 - (n))) +#define WIMAXASNCP_BIT16(n) (1U << (15 - (n))) +#define WIMAXASNCP_BIT8(n) (1U << ( 7 - (n))) + +#define WIMAXASNCP_FLAGS_T WIMAXASNCP_BIT8(6) +#define WIMAXASNCP_FLAGS_R WIMAXASNCP_BIT8(7) + +typedef struct { + wmem_array_t* hf; + wmem_array_t* ett; +} wimaxasncp_build_dict_t; + +static wimaxasncp_dict_t *wimaxasncp_dict = NULL; + +wimaxasncp_build_dict_t wimaxasncp_build_dict; + +static wimaxasncp_dict_tlv_t wimaxasncp_tlv_not_found = +{ + 0, "Unknown", NULL, WIMAXASNCP_TLV_UNKNOWN, 0, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + NULL, NULL, NULL +}; + +static dissector_handle_t wimaxasncp_handle; +static dissector_handle_t eap_handle; + +/* ------------------------------------------------------------------------- */ + +static const value_string wimaxasncp_flag_vals[] = +{ + { WIMAXASNCP_BIT8(0), "Reserved" }, + { WIMAXASNCP_BIT8(1), "Reserved" }, + { WIMAXASNCP_BIT8(2), "Reserved" }, + { WIMAXASNCP_BIT8(3), "Reserved" }, + { WIMAXASNCP_BIT8(4), "Reserved" }, + { WIMAXASNCP_BIT8(5), "Reserved" }, + { WIMAXASNCP_FLAGS_T, "T - Source and Destination Identifier TLVs"}, + { WIMAXASNCP_FLAGS_R, "R - Reset Next Expected Transaction ID"}, + { 0, NULL} +}; + +/* ------------------------------------------------------------------------- */ + +static const value_string wimaxasncp_op_id_vals[] = +{ + { 0, "Invalid"}, + { 1, "Request/Initiation"}, + { 2, "Response"}, + { 3, "Ack"}, + { 4, "Indication"}, + { 5, "Reserved"}, + { 6, "Reserved"}, + { 7, "Reserved"}, + { 0, NULL} +}; + +/* ------------------------------------------------------------------------- */ + +#define WIMAXASNCP_FT_QOS 1 +#define WIMAXASNCP_FT_HO_CONTROL 2 +#define WIMAXASNCP_FT_DATA_PATH_CONTROL 3 +#define WIMAXASNCP_FT_CONTEXT_TRANSFER 4 +#define WIMAXASNCP_FT_R3_MOBILITY 5 +#define WIMAXASNCP_FT_PAGING 6 +#define WIMAXASNCP_FT_RRM 7 +#define WIMAXASNCP_FT_AUTHENTICATION 8 +#define WIMAXASNCP_FT_MS_STATE 9 +#define WIMAXASNCP_FT_REAUTHENTICATION 10 +/* since NWG R1 V1.2.0 */ +#define WIMAXASNCP_FT_IM_OPERATIONS 10 +/* since NWG R1 V1.2.1 */ +#define WIMAXASNCP_FT_ACCOUNTING 11 + +/* ------------------------------------------------------------------------- */ + +/* struct to hold a value_string tuple, per version */ +typedef struct _ver_value_string +{ + guint32 since; + value_string vs; +} ver_value_string; + +static const ver_value_string wimaxasncp_function_type_vals[] = +{ + {0, { WIMAXASNCP_FT_QOS, "QoS"}}, + {0, { WIMAXASNCP_FT_HO_CONTROL, "HO Control"}}, + {0, { WIMAXASNCP_FT_DATA_PATH_CONTROL, "Data Path Control"}}, + {0, { WIMAXASNCP_FT_CONTEXT_TRANSFER, "Context Transfer"}}, + {0, { WIMAXASNCP_FT_R3_MOBILITY, "R3 Mobility"}}, + {0, { WIMAXASNCP_FT_PAGING, "Paging"}}, + {0, { WIMAXASNCP_FT_RRM, "RRM"}}, + {0, { WIMAXASNCP_FT_AUTHENTICATION, "Authentication Relay"}}, + {0, { WIMAXASNCP_FT_MS_STATE, "MS State"}}, + {0, { WIMAXASNCP_FT_REAUTHENTICATION, "Re-Authentication"}}, + {WIMAXASNCP_NWGVER_R10_V120, {WIMAXASNCP_FT_IM_OPERATIONS, "IM Operations"}}, + {WIMAXASNCP_NWGVER_R10_V121, { WIMAXASNCP_FT_ACCOUNTING, "Accounting"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_qos_msg_vals[] = +{ + {0,{ 1, "RR_Req"}}, + {0,{ 2, "RR_Rsp"}}, + {0,{ 3, "RR_Ack"}}, + {0,{ 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_ho_control_msg_vals[] = +{ + {0, { 1, "HO_Ack"}}, + {0, { 2, "HO_Complete"}}, + {0, { 3, "HO_Cnf"}}, + {0, { 4, "HO_Req"}}, + {0, { 5, "HO_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "HO_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "HO_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "HO_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "HO_Cnf"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "HO_Complete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "HO_Directive"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "HO_Directive_Rsp"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_data_path_control_msg_vals[] = +{ + {0, { 1, "Path_Dereg_Ack"}}, + {0, { 2, "Path_Dereg_Req"}}, + {0, { 3, "Path_Dereg_Rsp"}}, + {0, { 4, "Path_Modification_Ack"}}, + {0, { 5, "Path_Modification_Req"}}, + {0, { 6, "Path_Modification_Rsp"}}, + {0, { 7, "Path_Prereg_Ack"}}, + {0, { 8, "Path_Prereg_Req"}}, + {0, { 9, "Path_Prereg_Rsp"}}, + {0, { 10, "Path_Reg_Ack"}}, + {0, { 11, "Path_Reg_Req"}}, + {0, { 12, "Path_Reg_Rsp"}}, + {0, { 13, "MS_Attachment_Req"}}, + {0, { 14, "MS_Attachment_Rsp"}}, + {0, { 15, "MS_Attachment_Ack"}}, + {0, { 16, "Key_Change_Directive"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "Path_Dereg_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "Path_Dereg_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "Path_Dereg_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "Path_Modification_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "Path_Modification_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "Path_Modification_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "Path_Prereg_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "Path_Prereg_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 9, "Path_Prereg_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 10, "Path_Reg_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 11, "Path_Reg_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 12, "Path_Reg_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 13, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 14, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 15, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 16, "Obsolete"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_context_transfer_msg_vals[] = +{ + {0, { 1, "Context_Rpt"}}, + {0, { 2, "Context_Req"}}, + {0, { 3, "Context_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "Context_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "Context_Rpt"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "CMAC_Key_Count_Update"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "CMAC_Key_Count_Update_ACK"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "CMAC_Key_Count_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "CMAC_Key_Count_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "Prepaid Request"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 9, "Prepaid Notify"}}, + {WIMAXASNCP_NWGVER_R10_V121, { 6, "VOID"}}, + {WIMAXASNCP_NWGVER_R10_V121, { 7, "VOID"}}, + {WIMAXASNCP_NWGVER_R10_V121, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_r3_mobility_msg_vals[] = +{ + {0, { 1, "Anchor_DPF_HO_Req"}}, + {0, { 2, "Anchor_DPF_HO_Trigger"}}, + {0, { 3, "Anchor_DPF_HO_Rsp"}}, + {0, { 4, "Anchor_DPF_Relocate_Req"}}, + {0, { 5, "FA_Register_Req"}}, + {0, { 6, "FA_Register_Rsp"}}, + {0, { 7, "Anchor_DPF_Relocate_Rsp"}}, + {0, { 8, "FA_Revoke_Req"}}, + {0, { 9, "FA_Revoke_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "Anchor_DPF_Relocate_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "FA_Register_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "FA_Register_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 10, "Anchor_DPF_Release_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 11, "Relocation_Ready_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 12, "Relocation_Ready_Rsp"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_paging_msg_vals[] = +{ + {0, { 1, "Initiate_Paging_Req"}}, + {0, { 2, "Initiate_Paging_Rsp"}}, + {0, { 3, "LU_Cnf"}}, + {0, { 4, "LU_Req"}}, + {0, { 5, "LU_Rsp"}}, + {0, { 6, "Paging_Announce"}}, + {0, { 7, "CMAC_Key_Count_Req"}}, + {0, { 8, "CMAC_Key_Count_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "Paging_Announce"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "Delete_MS_Entry_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "PC_Relocation_Ind"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "PC_Relocation_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "Obsolete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "Obsolete"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_rrm_msg_vals[] = +{ + {0, { 1, "R6 PHY_Parameters_Req"}}, + {0, { 2, "R6 PHY_Parameters_Rpt"}}, + {0, { 3, "R4/R6 Spare_Capacity_Req"}}, + {0, { 4, "R4/R6 Spare_Capacity_Rpt"}}, + {0, { 5, "R6 Neighbor_BS_Resource_Status_Update"}}, + {0, { 6, "R4/R6 Radio_Config_Update_Req"}}, + {0, { 7, "R4/R6 Radio_Config_Update_Rpt"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "R4/R6 Radio_Config_Update_Ack"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_authentication_msg_vals[] = +{ + {0, { 1, "AR_Authenticated_Eap_Start"}}, + {0, { 2, "AR_Authenticated_EAP_Transfer"}}, + {0, { 3, "AR_Eap_Start"}}, + {0, { 4, "AR_EAP_Transfer"}}, + {0, { 5, "AR_EAP_Complete"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "AR_EAP_Start"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "AR_EAP_Transfer"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "Bulk_Interim_Update"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "Bulk_Interim_Update_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "Obsolete"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_ms_state_msg_vals[] = +{ + {0, { 1, "IM_Entry_State_Change_Req"}}, + {0, { 2, "IM_Entry_State_Change_Rsp"}}, + {0, { 3, "IM_Exit_State_Change_Req"}}, + {0, { 4, "IM_Exit_State_Change_Rsp"}}, + {0, { 5, "NW_ReEntry_State_Change_Directive"}}, + {0, { 6, "MS_PreAttachment_Req"}}, + {0, { 7, "MS_PreAttachment_Rsp"}}, + {0, { 8, "MS_PreAttachment_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "MS_PreAttachment_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "MS_PreAttachment_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "MS_PreAttachment_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "MS_Attachment_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "MS_Attachment_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "MS_Attachment_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "Key_Change_Directive"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "Key_Change_Cnf"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 9, "Key_Change_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 10, "Relocation_Complete_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 11, "Relocation_Complete_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 12, "Relocation_Complete_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 13, "Relocation_Notify"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 14, "Relocation_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 15, "Relocation_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 16, "NetExit_MS_State_Change_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 17, "NetExit_MS_State_Change_Rsp"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +/* note - function type 10-im_operation, was once used for re-authrntication */ +static const ver_value_string wimaxasncp_im_operations_msg_vals[] = +{ + {0, { 1, "AR_EAP_Start"}}, + {0, { 2, "Key_Change_Directive"}}, + {0, { 3, "Key_Change_Cnf"}}, + {0, { 4, "Relocation_Cnf"}}, + {0, { 5, "Relocation_Confirm_Ack"}}, + {0, { 6, "Relocation_Notify"}}, + {0, { 7, "Relocation_Notify_Ack"}}, + {0, { 8, "Relocation_Req"}}, + {0, { 9, "Relocation_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 1, "IM_Entry_State_Change_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 2, "IM_Entry_State_Change_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 3, "IM_Entry_State_Change_Ack"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 4, "IM_Exit_State_Change_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 5, "IM_Exit_State_Change_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 6, "Initiate_Paging_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 7, "Initiate_Paging_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 8, "LU_Req"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 9, "LU_Rsp"}}, + {WIMAXASNCP_NWGVER_R10_V120, { 10, "LU_Cnf"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +static const ver_value_string wimaxasncp_accounting_msg_vals_r1v121[] = +{ + {WIMAXASNCP_NWGVER_R10_V121, { 1, "Hot_lining_Req"}}, + {WIMAXASNCP_NWGVER_R10_V121, { 2, "Hot_lining_Rsp"}}, + {0, { 0, NULL}} +}; + +/* ------------------------------------------------------------------------- */ + +/* supported NWG versions */ +static const enum_val_t wimaxasncp_nwg_versions[] = { + { "Release 1.0, Version 1.0.0" , "R1.0 v1.0.0" , WIMAXASNCP_NWGVER_R10_V100 }, + { "Release 1.0, Version 1.2.0" , "R1.0 v1.2.0" , WIMAXASNCP_NWGVER_R10_V120 }, + { "Release 1.0, Version 1.2.1" , "R1.0 v1.2.1" , WIMAXASNCP_NWGVER_R10_V121 }, + { NULL, NULL, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +/* NWG version */ +#define WIMAXASNCP_DEF_NWGVER WIMAXASNCP_NWGVER_R10_V121 +static guint global_wimaxasncp_nwg_ver = WIMAXASNCP_DEF_NWGVER; + +/* ========================================================================= */ + +typedef struct { + guint8 function_type; + const ver_value_string *vals; +} wimaxasncp_func_msg_t; + +/* ------------------------------------------------------------------------ */ + +static const wimaxasncp_func_msg_t wimaxasncp_func_to_msg_vals_map[] = +{ + { WIMAXASNCP_FT_QOS, wimaxasncp_qos_msg_vals }, + { WIMAXASNCP_FT_HO_CONTROL, wimaxasncp_ho_control_msg_vals }, + { WIMAXASNCP_FT_DATA_PATH_CONTROL, wimaxasncp_data_path_control_msg_vals }, + { WIMAXASNCP_FT_CONTEXT_TRANSFER, wimaxasncp_context_transfer_msg_vals }, + { WIMAXASNCP_FT_R3_MOBILITY, wimaxasncp_r3_mobility_msg_vals }, + { WIMAXASNCP_FT_PAGING, wimaxasncp_paging_msg_vals }, + { WIMAXASNCP_FT_RRM, wimaxasncp_rrm_msg_vals }, + { WIMAXASNCP_FT_AUTHENTICATION, wimaxasncp_authentication_msg_vals }, + { WIMAXASNCP_FT_MS_STATE, wimaxasncp_ms_state_msg_vals }, + { WIMAXASNCP_FT_IM_OPERATIONS, wimaxasncp_im_operations_msg_vals }, + { WIMAXASNCP_FT_ACCOUNTING, wimaxasncp_accounting_msg_vals_r1v121 } +}; + +/* ========================================================================= */ + +static const wimaxasncp_dict_tlv_t *wimaxasncp_get_tlv_info( + guint16 type) +{ + wimaxasncp_dict_tlv_t *res = NULL; + + if (wimaxasncp_dict) + { + wimaxasncp_dict_tlv_t *tlv; + + for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next) + { + if (tlv->type == type) + { + /* if the TLV is defined for current NWG version */ + if (tlv->since<= global_wimaxasncp_nwg_ver) + { + /* if the current TLV is newer then last found TLV, save it */ + if (!res || (tlv->since > res->since)) + { + res = tlv; + } + } + } + } + } + + if (debug_enabled && !res) + { + g_print("fix-me: unknown TLV type: %u\n", type); + } + + return res? res:&wimaxasncp_tlv_not_found; +} + +/* ========================================================================= */ + +static const gchar *wimaxasncp_get_enum_name( + const wimaxasncp_dict_tlv_t *tlv_info, + guint32 code) +{ + if (tlv_info->enum_vs) + { + return val_to_str_const(code, tlv_info->enum_vs, "Unknown"); + } + else + { + return "Unknown"; + } +} + +/* ========================================================================= */ + +static const value_string wimaxasncp_decode_type_vals[] = +{ + { WIMAXASNCP_TLV_UNKNOWN, "WIMAXASNCP_TLV_UNKNOWN"}, + { WIMAXASNCP_TLV_TBD, "WIMAXASNCP_TLV_TBD"}, + { WIMAXASNCP_TLV_COMPOUND, "WIMAXASNCP_TLV_COMPOUND"}, + { WIMAXASNCP_TLV_BYTES, "WIMAXASNCP_TLV_BYTES"}, + { WIMAXASNCP_TLV_ENUM8, "WIMAXASNCP_TLV_ENUM8"}, + { WIMAXASNCP_TLV_ENUM16, "WIMAXASNCP_TLV_ENUM16"}, + { WIMAXASNCP_TLV_ENUM32, "WIMAXASNCP_TLV_ENUM32"}, + { WIMAXASNCP_TLV_ETHER, "WIMAXASNCP_TLV_ETHER"}, + { WIMAXASNCP_TLV_ASCII_STRING, "WIMAXASNCP_TLV_ASCII_STRING"}, + { WIMAXASNCP_TLV_FLAG0, "WIMAXASNCP_TLV_FLAG0"}, + { WIMAXASNCP_TLV_BITFLAGS8, "WIMAXASNCP_TLV_BITFLAGS8"}, + { WIMAXASNCP_TLV_BITFLAGS16, "WIMAXASNCP_TLV_BITFLAGS16"}, + { WIMAXASNCP_TLV_BITFLAGS32, "WIMAXASNCP_TLV_BITFLAGS32"}, + { WIMAXASNCP_TLV_ID, "WIMAXASNCP_TLV_ID"}, + { WIMAXASNCP_TLV_HEX8, "WIMAXASNCP_TLV_HEX8"}, + { WIMAXASNCP_TLV_HEX16, "WIMAXASNCP_TLV_HEX16"}, + { WIMAXASNCP_TLV_HEX32, "WIMAXASNCP_TLV_HEX32"}, + { WIMAXASNCP_TLV_DEC8, "WIMAXASNCP_TLV_DEC8"}, + { WIMAXASNCP_TLV_DEC16, "WIMAXASNCP_TLV_DEC16"}, + { WIMAXASNCP_TLV_DEC32, "WIMAXASNCP_TLV_DEC32"}, + { WIMAXASNCP_TLV_IP_ADDRESS, "WIMAXASNCP_TLV_IP_ADDRESS"}, + { WIMAXASNCP_TLV_IPV4_ADDRESS, "WIMAXASNCP_TLV_IPV4_ADDRESS"}, + { WIMAXASNCP_TLV_PROTOCOL_LIST, "WIMAXASNCP_TLV_PROTOCOL_LIST"}, + { WIMAXASNCP_TLV_PORT_RANGE_LIST, "WIMAXASNCP_TLV_PORT_RANGE_LIST"}, + { WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST, "WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST"}, + { WIMAXASNCP_TLV_VENDOR_SPECIFIC, "WIMAXASNCP_TLV_VENDOR_SPECIFIC"}, + { 0, NULL} +}; + +/* ========================================================================= */ + +static void wimaxasncp_proto_tree_add_tlv_ipv4_value( + packet_info *pinfo, + tvbuff_t *tvb, + proto_tree *tree, + proto_item *tlv_item, + guint offset, + const wimaxasncp_dict_tlv_t *tlv_info) +{ + int hf_value; + guint32 ip; + const gchar *addr_res; + + if (tlv_info->hf_ipv4 != -1) + { + hf_value = tlv_info->hf_ipv4; + } + else + { + hf_value = tlv_info->hf_value; + } + + ip = tvb_get_ipv4(tvb, offset); + addr_res = tvb_address_with_resolution_to_str(pinfo->pool, tvb, AT_IPv4, offset); + + proto_tree_add_ipv4_format( + tree, hf_value, + tvb, offset, 4, ip, + "Value: %s", addr_res); + + proto_item_append_text( + tlv_item, " - %s", addr_res); +} + +/* ========================================================================= */ + +static void wimaxasncp_proto_tree_add_tlv_ipv6_value( + packet_info *pinfo, + tvbuff_t *tvb, + proto_tree *tree, + proto_item *tlv_item, + guint offset, + const wimaxasncp_dict_tlv_t *tlv_info) +{ + int hf_value; + ws_in6_addr ip; + const gchar *addr_res; + + if (tlv_info->hf_ipv4 != -1) + { + hf_value = tlv_info->hf_ipv6; + } + else + { + hf_value = tlv_info->hf_value; + } + + tvb_get_ipv6(tvb, offset, &ip); + addr_res = tvb_address_with_resolution_to_str(pinfo->pool, tvb, AT_IPv6, offset); + + proto_tree_add_ipv6_format( + tree, hf_value, + tvb, offset, 16, &ip, + "Value: %s", addr_res); + + proto_item_append_text( + tlv_item, " - %s", addr_res); +} + +/* ========================================================================= */ + +static void wimaxasncp_proto_tree_add_ether_value( + packet_info *pinfo, + tvbuff_t *tvb, + proto_tree *tree, + proto_item *tlv_item, + guint offset, + guint length, + const wimaxasncp_dict_tlv_t *tlv_info) +{ + int hf_value; + const guint8 *p; + const gchar *ether_name; + + if (tlv_info->hf_bsid != -1) + { + hf_value = tlv_info->hf_bsid; + } + else + { + hf_value = tlv_info->hf_value; + } + + p = tvb_get_ptr(tvb, offset, length); + ether_name = tvb_address_with_resolution_to_str(pinfo->pool, tvb, AT_ETHER, offset); + + proto_tree_add_ether_format( + tree, hf_value, + tvb, offset, length, p, + "Value: %s", + ether_name); + + proto_item_append_text( + tlv_item, " - %s", + ether_name); +} + +/* ========================================================================= */ + +static void wimaxasncp_dissect_tlv_value( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_item *tlv_item, + const wimaxasncp_dict_tlv_t *tlv_info) +{ + guint offset = 0; + guint length; + const guint max_show_bytes = 24; /* arbitrary */ + static const gchar *hex_note = "[hex]"; + + length = tvb_reported_length(tvb); + + switch (tlv_info->decoder) + { + case WIMAXASNCP_TLV_ENUM8: + { + if (length != 1) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + if (debug_enabled) + { + g_print("fix-me: enum values missing for TLV %s (%u)\n", + tlv_info->name, tlv_info->type); + } + } + + if (tree) + { + guint8 value; + const gchar *s; + + value = tvb_get_guint8(tvb, offset); + + s = wimaxasncp_get_enum_name(tlv_info, value); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %s (%u)", s, value); + + proto_item_append_text(tlv_item, " - %s", s); + } + + return; + } + case WIMAXASNCP_TLV_ENUM16: + { + if (length != 2) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + if (debug_enabled) + { + g_print("fix-me: enum values missing for TLV %s (%u)\n", + tlv_info->name, tlv_info->type); + } + } + + if (tree) + { + guint16 value; + const gchar *s; + + value = tvb_get_ntohs(tvb, offset); + + s = wimaxasncp_get_enum_name(tlv_info, value); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %s (%u)", s, value); + + proto_item_append_text(tlv_item, " - %s", s); + } + + return; + } + case WIMAXASNCP_TLV_ENUM32: + { + if (length != 4) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + if (debug_enabled) + { + g_print("fix-me: enum values missing for TLV %s (%u)\n", + tlv_info->name, tlv_info->type); + } + } + + if (tree) + { + guint32 value; + const gchar *s; + + value = tvb_get_ntohl(tvb, offset); + + s = wimaxasncp_get_enum_name(tlv_info, value); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %s (%u)", s, value); + + proto_item_append_text(tlv_item, " - %s", s); + } + + return; + } + case WIMAXASNCP_TLV_ETHER: + { + if (length != 6) + { + /* encoding error */ + break; + } + + if (tree) + { + wimaxasncp_proto_tree_add_ether_value( + pinfo, tvb, tree, tlv_item, offset, length, tlv_info); + } + + return; + } + case WIMAXASNCP_TLV_ASCII_STRING: + { + if (tree) + { + const gchar *s = tvb_get_string_enc(pinfo->pool, tvb, offset, length, ENC_ASCII); + + proto_tree_add_string_format( + tree, tlv_info->hf_value, + tvb, offset, length, s, + "Value: %s", s); + + proto_item_append_text( + tlv_item, " - %s", s); + } + + return; + } + case WIMAXASNCP_TLV_FLAG0: + { + if (length != 0) + { + /* encoding error */ + break; + } + + return; + } + case WIMAXASNCP_TLV_BITFLAGS8: + { + if (length != 1) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + /* enum values missing */ + } + + if (tree) + { + proto_tree *flags_tree; + proto_item *item; + guint8 value; + guint i; + + value = tvb_get_guint8(tvb, offset); + + item = proto_tree_add_item( + tree, tlv_info->hf_value, + tvb, offset, 1, ENC_NA); + + proto_item_append_text(tlv_item, " - 0x%02x", value); + + if (value != 0) + { + flags_tree = proto_item_add_subtree( + item, ett_wimaxasncp_tlv_value_bitflags8); + + for (i = 0; i < 8; ++i) + { + guint8 mask; + mask = 1U << (7 - i); + + if (value & mask) + { + const gchar *s; + + s = wimaxasncp_get_enum_name(tlv_info, value & mask); + + proto_tree_add_uint_format( + flags_tree, hf_wimaxasncp_tlv_value_bitflags8, + tvb, offset, length, value, + "Bit #%u is set: %s", i, s); + } + } + } + } + + return; + } + case WIMAXASNCP_TLV_BITFLAGS16: + { + if (length != 2) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + /* enum values missing */ + } + + if (tree) + { + proto_tree *flags_tree; + proto_item *item; + guint16 value; + guint i; + + value = tvb_get_ntohs(tvb, offset); + + item = proto_tree_add_item( + tree, tlv_info->hf_value, + tvb, offset, 2, ENC_BIG_ENDIAN); + + proto_item_append_text(tlv_item, " - 0x%04x", value); + + if (value != 0) + { + flags_tree = proto_item_add_subtree( + item, ett_wimaxasncp_tlv_value_bitflags16); + + for (i = 0; i < 16; ++i) + { + guint16 mask; + mask = 1U << (15 - i); + + if (value & mask) + { + const gchar *s; + + s = wimaxasncp_get_enum_name(tlv_info, value & mask); + + proto_tree_add_uint_format( + flags_tree, hf_wimaxasncp_tlv_value_bitflags16, + tvb, offset, length, value, + "Bit #%u is set: %s", i, s); + } + } + } + } + + return; + } + case WIMAXASNCP_TLV_BITFLAGS32: + { + if (length != 4) + { + /* encoding error */ + break; + } + + if (tlv_info->enums == NULL) + { + /* enum values missing */ + } + + if (tree) + { + proto_tree *flags_tree; + proto_item *item; + guint32 value; + guint i; + + value = tvb_get_ntohl(tvb, offset); + + item = proto_tree_add_item( + tree, tlv_info->hf_value, + tvb, offset, 4, ENC_BIG_ENDIAN); + + proto_item_append_text(tlv_item, " - 0x%08x", value); + + if (value != 0) + { + flags_tree = proto_item_add_subtree( + item, ett_wimaxasncp_tlv_value_bitflags32); + + for (i = 0; i < 32; ++i) + { + guint32 mask; + mask = 1U << (31 - i); + + if (value & mask) + { + const gchar *s; + s = wimaxasncp_get_enum_name(tlv_info, value & mask); + + proto_tree_add_uint_format( + flags_tree, hf_wimaxasncp_tlv_value_bitflags32, + tvb, offset, length, value, + "Bit #%u is set: %s", i, s); + } + } + } + } + + return; + } + case WIMAXASNCP_TLV_ID: + { + if (length == 4) + { + if (tree) + { + wimaxasncp_proto_tree_add_tlv_ipv4_value( + pinfo, tvb, tree, tlv_item, offset, tlv_info); + } + + return; + } + else if (length == 6) + { + if (tree) + { + wimaxasncp_proto_tree_add_ether_value( + pinfo, tvb, tree, tlv_item, offset, length, tlv_info); + } + + return; + } + else if (length == 16) + { + if (tree) + { + wimaxasncp_proto_tree_add_tlv_ipv6_value( + pinfo, tvb, tree, tlv_item, offset, tlv_info); + } + + return; + } + else + { + /* encoding error */ + break; + } + } + case WIMAXASNCP_TLV_BYTES: + { + if (tree) + { + proto_tree_add_item( + tree, tlv_info->hf_value, + tvb, offset, length, ENC_NA); + + if (length) { + const gchar* format; + if (length <= max_show_bytes) + { + format = " - %s"; + } + else + { + format = " - %s..."; + } + const gchar* s = tvb_bytes_to_str_punct( + pinfo->pool, tvb, offset, MIN(length, max_show_bytes), 0); + + proto_item_append_text( + tlv_item, format, s); + } else { + proto_item_append_text(tlv_item, " - "); + } + } + + return; + } + case WIMAXASNCP_TLV_HEX8: + { + if (length != 1) + { + /* encoding error */ + break; + } + + if (tree) + { + guint8 value; + + value = tvb_get_guint8(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: 0x%02x", value); + + proto_item_append_text(tlv_item, " - 0x%02x", value); + } + + return; + } + case WIMAXASNCP_TLV_HEX16: + { + if (length != 2) + { + /* encoding error */ + break; + } + + if (tree) + { + guint16 value; + + value = tvb_get_ntohs(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: 0x%04x", value); + + proto_item_append_text(tlv_item, " - 0x%04x", value); + } + + return; + } + case WIMAXASNCP_TLV_HEX32: + { + if (length != 4) + { + /* encoding error */ + break; + } + + if (tree) + { + guint32 value; + + value = tvb_get_ntohl(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: 0x%08x", value); + + proto_item_append_text(tlv_item, " - 0x%08x", value); + } + + return; + } + case WIMAXASNCP_TLV_DEC8: + { + if (length != 1) + { + /* encoding error */ + break; + } + + if (tree) + { + guint8 value; + + value = tvb_get_guint8(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %u", value); + + proto_item_append_text(tlv_item, " - %u", value); + } + + return; + } + case WIMAXASNCP_TLV_DEC16: + { + if (length != 2) + { + /* encoding error */ + break; + } + + if (tree) + { + guint16 value; + + value = tvb_get_ntohs(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %u", value); + + proto_item_append_text(tlv_item, " - %u", value); + } + + return; + } + case WIMAXASNCP_TLV_DEC32: + { + if (length != 4) + { + /* encoding error */ + break; + } + + if (tree) + { + guint32 value; + + value = tvb_get_ntohl(tvb, offset); + + proto_tree_add_uint_format( + tree, tlv_info->hf_value, + tvb, offset, length, value, + "Value: %u", value); + + proto_item_append_text(tlv_item, " - %u", value); + } + + return; + } + case WIMAXASNCP_TLV_TBD: + { + if (debug_enabled) + { + g_print( + "fix-me: TBD: TLV %s (%u)\n", tlv_info->name, tlv_info->type); + } + + if (tree) + { + if (length) { + const char *format; + const char *s = tvb_bytes_to_str_punct( + pinfo->pool, tvb, offset, length, 0); + + if (length <= max_show_bytes) { + format = "%s %s"; + } else { + format = "%s %s..."; + } + + proto_tree_add_bytes_format_value( + tree, tlv_info->hf_value, + tvb, offset, length, NULL, format, hex_note, s); + + } else { + proto_tree_add_bytes_format_value( + tree, tlv_info->hf_value, + tvb, offset, length, NULL, "%s", ""); + } + + proto_item_append_text(tlv_item, " - TBD"); + } + + return; + } + case WIMAXASNCP_TLV_IP_ADDRESS: + { + if (length == 4) + { + if (tree) + { + wimaxasncp_proto_tree_add_tlv_ipv4_value( + pinfo, tvb, tree, tlv_item, offset, tlv_info); + } + + return; + } + else if (length == 16) + { + if (tree) + { + wimaxasncp_proto_tree_add_tlv_ipv6_value( + pinfo, tvb, tree, tlv_item, offset, tlv_info); + } + + return; + } + else + { + /* encoding error */ + break; + } + } + case WIMAXASNCP_TLV_IPV4_ADDRESS: + { + if (length != 4) + { + /* encoding error */ + break; + } + + if (tree) + { + wimaxasncp_proto_tree_add_tlv_ipv4_value( + pinfo, tvb, tree, tlv_item, offset, tlv_info); + } + + return; + } + case WIMAXASNCP_TLV_PROTOCOL_LIST: + { + if (length % 2 != 0) + { + /* encoding error */ + break; + } + + if (tree && length > 0) + { + proto_tree *protocol_list_tree; + proto_item *item; + const guint max_protocols_in_tlv_item = 8; /* arbitrary */ + + protocol_list_tree = proto_tree_add_subtree( + tree, tvb, offset, length, + ett_wimaxasncp_tlv_protocol_list, NULL, "Value"); + + /* hidden item for filtering */ + item = proto_tree_add_item( + protocol_list_tree, tlv_info->hf_value, + tvb, offset, length, ENC_NA); + + proto_item_set_hidden(item); + + while (offset < tvb_reported_length(tvb)) + { + guint16 protocol; + const gchar *protocol_name; + + protocol = tvb_get_ntohs(tvb, offset); + protocol_name = ipprotostr(protocol); + + proto_tree_add_uint_format( + protocol_list_tree, tlv_info->hf_protocol, + tvb, offset, 2, protocol, + "Protocol: %s (%u)", protocol_name, protocol); + + if (offset == 0) + { + proto_item_append_text(tlv_item, " - %s", protocol_name); + } + else if (offset < 2 * max_protocols_in_tlv_item) + { + proto_item_append_text(tlv_item, ", %s", protocol_name); + } + else if (offset == 2 * max_protocols_in_tlv_item) + { + proto_item_append_text(tlv_item, ", ..."); + } + + offset += 2; + } + } + + return; + } + case WIMAXASNCP_TLV_PORT_RANGE_LIST: + { + if (length % 4 != 0) + { + /* encoding error */ + break; + } + + if (tree && length > 0) + { + proto_tree *port_range_list_tree; + proto_item *item; + const guint max_port_ranges_in_tlv_item = 3; /* arbitrary */ + + port_range_list_tree = proto_tree_add_subtree( + tree, tvb, offset, length, + ett_wimaxasncp_tlv_port_range_list, NULL, "Value"); + + /* hidden item for filtering */ + item = proto_tree_add_item( + port_range_list_tree, tlv_info->hf_value, + tvb, offset, length, ENC_NA); + + proto_item_set_hidden(item); + + while (offset < tvb_reported_length(tvb)) + { + guint16 portLow; + guint16 portHigh; + proto_tree* range_tree; + + portLow = tvb_get_ntohs(tvb, offset); + portHigh = tvb_get_ntohs(tvb, offset + 2); + + range_tree = proto_tree_add_subtree_format( + port_range_list_tree, tvb, offset, 4, + ett_wimaxasncp_port_range, NULL, "Port Range: %u-%u", portLow, portHigh); + + /* hidden items are for filtering */ + + item = proto_tree_add_item( + range_tree, tlv_info->hf_port_low, + tvb, offset, 2, ENC_BIG_ENDIAN); + + proto_item_set_hidden(item); + + item = proto_tree_add_item( + range_tree, tlv_info->hf_port_high, + tvb, offset + 2, 2, ENC_BIG_ENDIAN); + + proto_item_set_hidden(item); + + if (offset == 0) + { + proto_item_append_text( + tlv_item, " - %u-%u", portLow, portHigh); + } + else if (offset < 4 * max_port_ranges_in_tlv_item) + { + proto_item_append_text( + tlv_item, ", %u-%u", portLow, portHigh); + } + else if (offset == 4 * max_port_ranges_in_tlv_item) + { + proto_item_append_text(tlv_item, ", ..."); + } + + offset += 4; + } + } + + return; + } + case WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST: + { + /* -------------------------------------------------------------------- + * The definion of these TLVs are ambiguous. The length in octets is + * described as Nx8 (IPv4) or Nx32 (IPv6), but this function cannot + * always differentiate between IPv4 and IPv6. For example, if length + * = 32, then is it IPv4 where N=4 (4x8) or IPv6 where N=1 (1x32)? + * + * For now, we presume lengths that *can* indicate an IPv6 address and + * mask list *do* denote an IPv6 address and mask list. + * -------------------------------------------------------------------- + */ + + if (length % 8 != 0) + { + /* encoding error */ + break; + } + + if (tree && length > 0) + { + proto_tree *ip_address_mask_list_tree; + proto_item *item; + + ip_address_mask_list_tree = proto_tree_add_subtree( + tree, tvb, offset, length, + ett_wimaxasncp_tlv_ip_address_mask_list, NULL, "Value"); + + /* hidden item for filtering */ + item = proto_tree_add_item( + ip_address_mask_list_tree, tlv_info->hf_value, + tvb, offset, length, ENC_NA); + + proto_item_set_hidden(item); + + if (length % 32 == 0) + { + /* ------------------------------------------------------------ + * presume IPv6 + * ------------------------------------------------------------ + */ + + while (offset < tvb_reported_length(tvb)) + { + proto_tree *ip_address_mask_tree; + + ip_address_mask_tree = proto_tree_add_subtree( + ip_address_mask_list_tree, tvb, offset, 32, + ett_wimaxasncp_tlv_ip_address_mask, NULL, "IPv6 Address and Mask"); + + /* -------------------------------------------------------- + * address + * -------------------------------------------------------- + */ + + proto_tree_add_item( + ip_address_mask_tree, + tlv_info->hf_ipv6, + tvb, offset, 16, ENC_NA); + + /* too long to display ? + proto_item_append_text( + item, " - %s (%s)", + get_hostname6(&ip), ip6_to_str(&ip)); + */ + + offset += 16; + + /* -------------------------------------------------------- + * mask + * -------------------------------------------------------- + */ + proto_tree_add_item( + ip_address_mask_tree, + tlv_info->hf_ipv6_mask, + tvb, offset, 16, ENC_NA); + + /* too long to display ? + proto_item_append_text( + item, " / %s", s); + */ + + offset += 16; + } + } + else + { + /* ------------------------------------------------------------ + * IPv4 + * ------------------------------------------------------------ + */ + + while (offset < tvb_reported_length(tvb)) + { + proto_tree *ip_address_mask_tree; + guint32 ip; + const gchar *s; + + ip_address_mask_tree = proto_tree_add_subtree( + ip_address_mask_list_tree, tvb, offset, 8, + ett_wimaxasncp_tlv_ip_address_mask, NULL, "IPv4 Address and Mask"); + + /* -------------------------------------------------------- + * address + * -------------------------------------------------------- + */ + + ip = tvb_get_ipv4(tvb, offset); + + proto_tree_add_item( + ip_address_mask_tree, + tlv_info->hf_ipv4, + tvb, offset, 4, ENC_BIG_ENDIAN); + + proto_item_append_text( + item, " - %s (%s)", + get_hostname(ip), tvb_ip_to_str(pinfo->pool, tvb, offset)); + + offset += 4; + + /* -------------------------------------------------------- + * mask + * -------------------------------------------------------- + */ + + s = tvb_ip_to_str(pinfo->pool, tvb, offset); + + proto_tree_add_item( + ip_address_mask_tree, + tlv_info->hf_ipv4_mask, + tvb, offset, 4, ENC_BIG_ENDIAN); + + proto_item_append_text( + item, " / %s", s); + + offset += 4; + } + } + } + + return; + } + case WIMAXASNCP_TLV_EAP: + { + /* + * EAP payload, call eap dissector to dissect eap payload + */ + guint8 eap_code; + guint8 eap_type = 0; + + /* Get code */ + eap_code = tvb_get_guint8(tvb, offset); + if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE) + { + /* Get type */ + eap_type = tvb_get_guint8(tvb, offset + 4); + } + + /* Add code and type to info column */ + col_append_str(pinfo->cinfo, COL_INFO, " ["); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)")); + + if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE) + { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str_ext(eap_type, &eap_type_vals_ext, "Unknown type (0x%02X)")); + } + + col_append_str(pinfo->cinfo, COL_INFO, "]"); + + + { + proto_tree *eap_tree; + proto_item *item; + gboolean save_writable; + tvbuff_t *eap_tvb; + + /* Create EAP subtree */ + item = proto_tree_add_item(tree, tlv_info->hf_value, tvb, + offset, length, ENC_NA); + proto_item_set_text(item, "Value"); + eap_tree = proto_item_add_subtree(item, ett_wimaxasncp_tlv_eap); + + /* Also show high-level details in this root item */ + proto_item_append_text(item, " (%s", + val_to_str(eap_code, eap_code_vals, + "Unknown code (0x%02X)")); + if (eap_code == EAP_REQUEST || eap_code == EAP_RESPONSE) + { + proto_item_append_text(item, ", %s", + val_to_str_ext(eap_type, &eap_type_vals_ext, + "Unknown type (0x%02X)")); + } + proto_item_append_text(item, ")"); + + + /* Extract remaining bytes into new tvb */ + eap_tvb = tvb_new_subset_remaining(tvb, offset); + + /* Disable writing to info column while calling eap dissector */ + save_writable = col_get_writable(pinfo->cinfo, -1); + col_set_writable(pinfo->cinfo, -1, FALSE); + + /* Call the EAP dissector. */ + call_dissector(eap_handle, eap_tvb, pinfo, eap_tree); + + /* Restore previous writable state of info column */ + col_set_writable(pinfo->cinfo, -1, save_writable); + } + + return; + } + + case WIMAXASNCP_TLV_VENDOR_SPECIFIC: + { + /* -------------------------------------------------------------------- + * The format of the vendor specific information field (VSIF) is not + * clearly defined. It appears to be compound as the spec states + * that the vendor ID field shall be the first TLV embedded inside + * the VSIF. However, the vendor ID is shown as a 24-bit value. Does + * this mean the field is 24-bits? If so, how is alignment/padding + * handled? + * + * For now, we decode the vendor ID as a non-padded 24-bit value and + * dump the rest as hex. + * -------------------------------------------------------------------- + */ + + if (length < 3) + { + /* encoding error */ + break; + } + + if (tree) + { + proto_tree *vsif_tree; + proto_item *item; + guint32 vendorId; + const gchar *vendorName; + + vsif_tree = proto_tree_add_subtree( + tree, tvb, offset, length, + ett_wimaxasncp_tlv_vendor_specific_information_field, NULL, "Value"); + + /* hidden item for filtering */ + item = proto_tree_add_item( + vsif_tree, tlv_info->hf_value, + tvb, offset, length, ENC_NA); + + proto_item_set_hidden(item); + + /* ---------------------------------------------------------------- + * vendor ID (24-bit) + * ---------------------------------------------------------------- + */ + + vendorId = tvb_get_ntoh24(tvb, offset); + + vendorName = enterprises_lookup(vendorId, "Unknown"); + proto_tree_add_uint_format( + vsif_tree, tlv_info->hf_vendor_id, + tvb, offset, 3, vendorId, + "Vendor ID: %s (%u)", vendorName, vendorId); + + proto_item_append_text(tlv_item, " - %s", vendorName); + + offset += 3; + + /* ---------------------------------------------------------------- + * hex dump the rest + * ---------------------------------------------------------------- + */ + + if (offset < tvb_reported_length(tvb)) + { + proto_tree_add_item( + vsif_tree, tlv_info->hf_vendor_rest_of_info, + tvb, offset, length - offset, ENC_NA); + } + } + + return; + } + case WIMAXASNCP_TLV_UNKNOWN: + { + if (tree) + { + const char* s; + if (length) { + const char* format1; + const char* format2; + if (length <= max_show_bytes) + { + format1 = "%s %s"; + format2 = " - %s %s"; + } + else + { + format1 = "%s %s..."; + format2 = " - %s %s..."; + } + s = tvb_bytes_to_str_punct( + pinfo->pool, tvb, offset, MIN(length, max_show_bytes), 0); + + proto_tree_add_bytes_format_value( + tree, tlv_info->hf_value, + tvb, offset, length, NULL, format1, hex_note, s); + + proto_item_append_text( + tlv_item, format2, hex_note, s); + } + else { + proto_tree_add_bytes_format_value( + tree, tlv_info->hf_value, + tvb, offset, length, NULL, "%s", ""); + + proto_item_append_text(tlv_item, " - "); + } + + } + + return; + } + default: + if (debug_enabled) + { + g_print( + "fix-me: unknown decoder: %d\n", tlv_info->decoder); + } + break; + } + + /* default is hex dump */ + + if (tree) + { + if (length) { + const char* format; + const char *s = tvb_bytes_to_str_punct( + pinfo->pool, tvb, offset, MIN(length, max_show_bytes), 0); + + if (length <= max_show_bytes) { + format = "%s %s"; + } else { + format = "%s %s..."; + } + + proto_tree_add_bytes_format_value( + tree, hf_wimaxasncp_tlv_value_bytes, + tvb, offset, length, NULL, + format, hex_note, s); + } else { + proto_tree_add_bytes_format_value( + tree, hf_wimaxasncp_tlv_value_bytes, + tvb, offset, length, NULL, + "%s", ""); + } + } +} + +/* ========================================================================= */ + +static guint dissect_wimaxasncp_tlvs( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree) +{ + guint offset; + + offset = 0; + while (offset < tvb_reported_length(tvb)) + { + const wimaxasncp_dict_tlv_t *tlv_info; + + proto_tree *tlv_tree; + proto_item *tlv_item; + guint16 type; + guint16 length; + guint pad; + + /* -------------------------------------------------------------------- + * type and length + * -------------------------------------------------------------------- + */ + + type = tvb_get_ntohs(tvb, offset); + tlv_info = wimaxasncp_get_tlv_info(type); + + length = tvb_get_ntohs(tvb, offset + 2); +#if 0 /* Commented out padding; As there is no mention of padding in + the Latest specification */ + pad = 4 - (length % 4); + if (pad == 4) + { + pad = 0; + } +#endif + pad = 0; + { + proto_item *type_item; + + gint tree_length = MIN( + (gint)(4 + length + pad), tvb_captured_length_remaining(tvb, offset)); + + tlv_item = proto_tree_add_item( + tree, tlv_info->hf_root, + tvb, offset, tree_length, ENC_NA); + + /* Set label for tlv item */ + proto_item_set_text(tlv_item, "TLV: %s", tlv_info->name); + + /* Show code number if unknown */ + if (tlv_info->decoder == WIMAXASNCP_TLV_UNKNOWN) + { + proto_item_append_text(tlv_item, " (%u)", type); + } + + /* Indicate if a compound tlv */ + if (tlv_info->decoder == WIMAXASNCP_TLV_COMPOUND) + { + proto_item_append_text(tlv_item, " [Compound]"); + } + + /* Create TLV subtree */ + tlv_tree = proto_item_add_subtree( + tlv_item, ett_wimaxasncp_tlv); + + /* Type (expert item if unknown) */ + type_item = proto_tree_add_uint_format( + tlv_tree, hf_wimaxasncp_tlv_type, + tvb, offset, 2, type, + "Type: %s (%u)", tlv_info->name, type); + + if (tlv_info->decoder == WIMAXASNCP_TLV_UNKNOWN) + { + expert_add_info_format(pinfo, type_item, &ei_wimaxasncp_tlv_type, + "Unknown TLV type (%u)", + type); + } + + /* Length */ + proto_tree_add_uint( + tlv_tree, hf_wimaxasncp_tlv_length, + tvb, offset + 2, 2, length); + + } + + offset += 4; + + /* -------------------------------------------------------------------- + * value + * -------------------------------------------------------------------- + */ + + if (tlv_info->decoder == WIMAXASNCP_TLV_COMPOUND) + { + if (length == 0) + { + /* error? compound, but no TLVs inside */ + } + else if (tvb_reported_length_remaining(tvb, offset) > 0) + { + tvbuff_t *tlv_tvb; + + /* N.B. Not padding out tvb length */ + tlv_tvb = tvb_new_subset_length_caplen( + tvb, offset, + MIN(length, tvb_captured_length_remaining(tvb, offset)), + length); + + /* N.B. This is a recursive call... */ + dissect_wimaxasncp_tlvs(tlv_tvb, pinfo, tlv_tree); + } + else + { + /* this should throw */ + tvb_ensure_bytes_exist(tvb, offset, length + pad); + } + } + else + { + tvbuff_t *tlv_tvb; + + tvb_ensure_bytes_exist(tvb, offset, length + pad); + + tlv_tvb = tvb_new_subset_length_caplen( + tvb, offset, + MIN(length, tvb_captured_length_remaining(tvb, offset)), + length); + + wimaxasncp_dissect_tlv_value( + tlv_tvb, pinfo, tlv_tree, tlv_item, tlv_info); + } + + offset += length + pad; + } + + return offset; +} + +/* ========================================================================= */ + +static guint dissect_wimaxasncp_backend( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree) +{ + guint offset = 0; + guint16 ui16; + guint32 ui32; + const guint8 *pmsid; + guint16 tid = 0; + gboolean dbit_show; + + + /* ------------------------------------------------------------------------ + * MSID + * ------------------------------------------------------------------------ + */ + + if (tree) + { + proto_tree_add_item( + tree, hf_wimaxasncp_msid, + tvb, offset, 6, ENC_NA); + } + pmsid = tvb_ether_to_str(pinfo->pool, tvb, offset); + + offset += 6; + + /* ------------------------------------------------------------------------ + * reserved + * ------------------------------------------------------------------------ + */ + + ui32 = tvb_get_ntohl(tvb, offset); + + if (tree) + { + proto_tree_add_uint( + tree, hf_wimaxasncp_reserved1, + tvb, offset, 4, ui32); + } + + offset += 4; + + /* ------------------------------------------------------------------------ + * transaction ID + * ------------------------------------------------------------------------ + */ + + dbit_show = FALSE; + ui16 = tvb_get_ntohs(tvb, offset); + + if (show_transaction_id_d_bit) + { + const guint16 mask = 0x7fff; + + if (ui16 & 0x8000) + { + proto_tree_add_uint_format( + tree, hf_wimaxasncp_transaction_id, + tvb, offset, 2, ui16, + "Transaction ID: D + 0x%04x (0x%04x)", mask & ui16, ui16); + + tid = ui16 & mask; + dbit_show = TRUE; + } + else + { + proto_tree_add_uint_format( + tree, hf_wimaxasncp_transaction_id, + tvb, offset, 2, ui16, + "Transaction ID: 0x%04x", ui16); + + tid = ui16; + } + } + else + { + proto_tree_add_uint( + tree, hf_wimaxasncp_transaction_id, + tvb, offset, 2, ui16); + + tid = ui16; + } + + offset += 2; + + /* ------------------------------------------------------------------------ + * reserved + * ------------------------------------------------------------------------ + */ + + ui16 = tvb_get_ntohs(tvb, offset); + + if (tree) + { + proto_tree_add_uint( + tree, hf_wimaxasncp_reserved2, + tvb, offset, 2, ui16); + } + + offset += 2; + + /* ------------------------------------------------------------------------ + * TLVs + * ------------------------------------------------------------------------ + */ + + if (tvb_reported_length_remaining(tvb, offset) > 0) + { + tvbuff_t *tlv_tvb; + + tlv_tvb = tvb_new_subset_remaining(tvb, offset); + + offset += dissect_wimaxasncp_tlvs(tlv_tvb, pinfo, tree); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, " - MSID:%s", pmsid); + if (dbit_show) + { + col_append_fstr(pinfo->cinfo, COL_INFO, ", TID:D+0x%04x", tid); + } + else + { + col_append_fstr(pinfo->cinfo, COL_INFO, ", TID:0x%04x", tid); + } + + return offset; +} + +/* ========================================================================= */ + + +static const gchar* +match_ver_value_string( + const guint32 val, + const ver_value_string* const strings, + const guint32 max_ver) +{ + const ver_value_string* vvs; + const ver_value_string* res = NULL; + + /* loop on the levels, from max to 0 */ + for(vvs=strings; vvs->vs.strptr; vvs++) + { + if ((vvs->vs.value == val) && (vvs->since <= max_ver)) + { + if (!res || (vvs->since > res->since)) + { + res = vvs; + } + } + } + + return res? res->vs.strptr : NULL; +} + +static int +dissect_wimaxasncp( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data _U_) +{ + static const gchar unknown[] = "Unknown"; + + /* Set up structures needed to add the protocol subtree and manage it */ + proto_item *packet_item = NULL; + proto_item *item = NULL; + proto_tree *wimaxasncp_tree = NULL; + tvbuff_t *subtree; + + guint offset; + guint8 ui8; + + guint8 function_type; + const gchar *function_type_name; + proto_item *function_type_item; + guint16 length; + + const wimaxasncp_func_msg_t *p = NULL; + const gchar *message_name; + gsize i; + + /* ------------------------------------------------------------------------ + * First, we do some heuristics to check if the packet cannot be our + * protocol. + * ------------------------------------------------------------------------ + */ + + /* Should we check a minimum size? If so, uncomment out the following + * code. */ +#if 0 + if (tvb_reported_length(tvb) < WIMAXASNCP_HEADER_SIZE) + { + return 0; + } +#endif + + /* We currently only support version 1. */ + if (tvb_bytes_exist(tvb, 0, 1) && tvb_get_guint8(tvb, 0) != 1) + { + return 0; + } + + /* ------------------------------------------------------------------------ + * Initialize the protocol and info column. + * ------------------------------------------------------------------------ + */ + + /* Make entries in Protocol column and Info column on summary display */ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "WiMAX"); + + /* We'll fill in the "Info" column after fetch data, so we clear the + column first in case calls to fetch data from the packet throw an + exception. */ + col_clear(pinfo->cinfo, COL_INFO); + + /* ======================================================================== + * Disesction starts here + * ======================================================================== + */ + + /* ------------------------------------------------------------------------ + * total packet, we'll adjust after we read the length field + * ------------------------------------------------------------------------ + */ + + offset = 0; + + /* Register protocol fields, etc if haven't done yet. */ + if (hf_wimaxasncp_version == -1) + { + proto_registrar_get_byname("wimaxasncp.version"); + } + + if (tree) + { + packet_item = proto_tree_add_item( + tree, proto_wimaxasncp, + tvb, 0, MIN(WIMAXASNCP_HEADER_LENGTH_END, tvb_captured_length(tvb)), ENC_NA); + + wimaxasncp_tree = proto_item_add_subtree( + packet_item, ett_wimaxasncp); + } + + /* ------------------------------------------------------------------------ + * version + * ------------------------------------------------------------------------ + */ + + if (tree) + { + proto_tree_add_item( + wimaxasncp_tree, hf_wimaxasncp_version, + tvb, offset, 1, ENC_BIG_ENDIAN); + } + + offset += 1; + + /* ------------------------------------------------------------------------ + * flags + * ------------------------------------------------------------------------ + */ + + ui8 = tvb_get_guint8(tvb, offset); + + if (tree) + { + proto_tree *flags_tree; + + if (ui8 == 0) + { + proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_flags, + tvb, offset, 1, ui8, + "Flags: 0x%02x", ui8); + } + else + { + guint j; + item = proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_flags, + tvb, offset, 1, ui8, + "Flags: "); + + if (ui8 & (WIMAXASNCP_FLAGS_T | WIMAXASNCP_FLAGS_R)) + { + if (ui8 & WIMAXASNCP_FLAGS_T) + { + proto_item_append_text(item, "T"); + } + + if (ui8 & WIMAXASNCP_FLAGS_R) + { + proto_item_append_text(item, "R"); + } + + proto_item_append_text(item, " - "); + } + + proto_item_append_text(item, "0x%02x", ui8); + + flags_tree = proto_item_add_subtree( + item, ett_wimaxasncp_flags); + + for (j = 0; j < 8; ++j) + { + guint8 mask; + mask = 1U << (7 - j); + + /* Only add flags that are set */ + if (ui8 & mask) + { + proto_tree_add_uint_format( + flags_tree, hf_wimaxasncp_flags, + tvb, offset, 1, ui8, + "Bit #%u is set: %s", + j, + val_to_str( + ui8 & mask, wimaxasncp_flag_vals, "Unknown")); + } + } + } + } + + offset += 1; + + /* ------------------------------------------------------------------------ + * function type + * ------------------------------------------------------------------------ + */ + + function_type = tvb_get_guint8(tvb, offset); + + function_type_name = match_ver_value_string(function_type, + wimaxasncp_function_type_vals, + global_wimaxasncp_nwg_ver); + + if (function_type_name) + { + /* add the item to the tree */ + proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_function_type, + tvb, offset, 1, function_type, + "%s (%u)", function_type_name, function_type); + } + else + { + /* if not matched, add the item and append expert item */ + function_type_item = proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_function_type, + tvb, offset, 1, function_type, + "Unknown (%u)", function_type); + + expert_add_info_format(pinfo, function_type_item, + &ei_wimaxasncp_function_type, + "Unknown function type (%u)", + function_type); + } + + offset += 1; + + /* ------------------------------------------------------------------------ + * OP ID and message type + * ------------------------------------------------------------------------ + */ + + ui8 = tvb_get_guint8(tvb, offset); + + + /* -------------------------------------------------------------------- + * OP ID + * -------------------------------------------------------------------- + */ + + item = proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_op_id, + tvb, offset, 1, ui8, + "OP ID: %s", val_to_str(ui8 >> 5, wimaxasncp_op_id_vals, unknown)); + + proto_item_append_text(item, " (%u)", ((ui8 >> 5) & 7)); + + + /* use the function type to find the message vals */ + for (i = 0; i < array_length(wimaxasncp_func_to_msg_vals_map); ++i) + { + p = &wimaxasncp_func_to_msg_vals_map[i]; + + if (function_type == p->function_type) + { + break; + } + } + + /* -------------------------------------------------------------------- + * message type + * -------------------------------------------------------------------- + */ + + message_name = p ? match_ver_value_string(0x1f & ui8, p->vals, global_wimaxasncp_nwg_ver) : unknown; + if (message_name == NULL) + { + message_name = unknown; + } + + item = proto_tree_add_uint_format( + wimaxasncp_tree, hf_wimaxasncp_message_type, + tvb, offset, 1, ui8, + "Message Type: %s", message_name); + + proto_item_append_text(item, " (%u)", ui8 & 0x1F); + + /* Add expert item if not matched */ + if (strcmp(message_name, unknown) == 0) + { + expert_add_info_format(pinfo, item, &ei_wimaxasncp_message_type, + "Unknown message type (%u)", + 0x1f & ui8); + } + + col_add_str(pinfo->cinfo, COL_INFO, message_name); + + offset += 1; + + /* ------------------------------------------------------------------------ + * length + * ------------------------------------------------------------------------ + */ + + length = tvb_get_ntohs(tvb, offset); + + if (tree) + { + proto_item_set_len( + packet_item, MAX(WIMAXASNCP_HEADER_LENGTH_END, length)); + + item = proto_tree_add_uint( + wimaxasncp_tree, hf_wimaxasncp_length, + tvb, offset, 2, length); + } + + offset += 2; + + if (length < WIMAXASNCP_HEADER_SIZE) + { + expert_add_info(pinfo, item, &ei_wimaxasncp_length_bad); + + if (tree) + { + proto_item_append_text( + item, " [error: specified length less than header size (20)]"); + } + + if (length <= WIMAXASNCP_HEADER_LENGTH_END) + { + return offset; + } + } + + /* ------------------------------------------------------------------------ + * remaining header fields and TLVs + * ------------------------------------------------------------------------ + */ + + subtree = tvb_new_subset_length_caplen( + tvb, offset, + MIN(length, tvb_captured_length_remaining(tvb, offset)), + length - WIMAXASNCP_HEADER_LENGTH_END); + + offset += dissect_wimaxasncp_backend( + subtree, pinfo, wimaxasncp_tree); + + /* ------------------------------------------------------------------------ + * done, return the amount of data this dissector was able to dissect + * ------------------------------------------------------------------------ + */ + + return offset; +} + +/* ========================================================================= */ +/* Modify the given string to make a suitable display filter */ +static char *alnumerize( + char *name) +{ + char *r = name; /* read pointer */ + char *w = name; /* write pointer */ + char c; + + for ( ; (c = *r); ++r) + { + if (g_ascii_isalnum(c) || c == '_' || c == '.') + { + /* These characters are fine - copy them */ + *(w++) = c; + } + else if (c == ' ' || c == '-' || c == '/') + { + /* Skip these others if haven't written any characters out yet */ + if (w == name) + { + continue; + } + + /* Skip if we would produce multiple adjacent '_'s */ + if (*(w - 1) == '_') + { + continue; + } + + /* OK, replace with underscore */ + *(w++) = '_'; + } + + /* Other undesirable characters are just skipped */ + } + + /* Terminate and return modified string */ + *w = '\0'; + return name; +} + +/* ========================================================================= */ + +static void add_reg_info( + int *hf_ptr, + const char *name, + const char *abbrev, + enum ftenum type, + int display, + const char *blurb) +{ + hf_register_info hf = { + hf_ptr, { name, abbrev, type, display, NULL, 0x0, blurb, HFILL } }; + + wmem_array_append_one(wimaxasncp_build_dict.hf, hf); +} + +/* ========================================================================= */ + +static void add_tlv_reg_info( + wimaxasncp_dict_tlv_t *tlv) +{ + char *name; + char *abbrev; + const char *root_blurb; + char *blurb; + + /* ------------------------------------------------------------------------ + * add root reg info + * ------------------------------------------------------------------------ + */ + + name = wmem_strdup(wmem_epan_scope(), tlv->name); + abbrev = alnumerize(wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s", tlv->name)); + + switch (tlv->decoder) + { + case WIMAXASNCP_TLV_UNKNOWN: + root_blurb = "type=Unknown"; + break; + case WIMAXASNCP_TLV_TBD: + root_blurb = wmem_strdup_printf(wmem_epan_scope(), "type=%u, TBD", tlv->type); + break; + case WIMAXASNCP_TLV_COMPOUND: + root_blurb = wmem_strdup_printf(wmem_epan_scope(), "type=%u, Compound", tlv->type); + break; + case WIMAXASNCP_TLV_FLAG0: + root_blurb = wmem_strdup_printf(wmem_epan_scope(), "type=%u, Value = Null", tlv->type); + break; + default: + root_blurb = wmem_strdup_printf(wmem_epan_scope(), "type=%u", tlv->type); + break; + } + + add_reg_info( + &tlv->hf_root, name, abbrev, FT_BYTES, BASE_NONE, root_blurb); + + /* ------------------------------------------------------------------------ + * add value(s) reg info + * ------------------------------------------------------------------------ + */ + + name = wmem_strdup(wmem_epan_scope(), "Value"); + abbrev = alnumerize(wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value", tlv->name)); + blurb = wmem_strdup_printf(wmem_epan_scope(), "value for type=%u", tlv->type); + + switch (tlv->decoder) + { + case WIMAXASNCP_TLV_UNKNOWN: + wmem_free(wmem_epan_scope(), blurb); + + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, + "value for unknown type"); + break; + + case WIMAXASNCP_TLV_TBD: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + break; + + case WIMAXASNCP_TLV_COMPOUND: + case WIMAXASNCP_TLV_FLAG0: + wmem_free(wmem_epan_scope(), name); + wmem_free(wmem_epan_scope(), abbrev); + wmem_free(wmem_epan_scope(), blurb); + break; + + case WIMAXASNCP_TLV_BYTES: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + break; + + case WIMAXASNCP_TLV_ENUM8: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT8, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_ENUM16: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT16, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_ENUM32: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT32, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_ETHER: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_ETHER, BASE_NONE, blurb); + break; + + case WIMAXASNCP_TLV_ASCII_STRING: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_STRING, BASE_NONE, blurb); + break; + + case WIMAXASNCP_TLV_BITFLAGS8: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT8, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_BITFLAGS16: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT16, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_BITFLAGS32: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT32, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_ID: + wmem_free(wmem_epan_scope(), abbrev); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.ipv4_value", tlv->name)); + + add_reg_info( + &tlv->hf_ipv4, "IPv4 Address", abbrev, FT_IPv4, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.ipv6_value", tlv->name)); + + add_reg_info( + &tlv->hf_ipv6, "IPv6 Address", abbrev, FT_IPv6, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.bsid_value", tlv->name)); + + add_reg_info( + &tlv->hf_bsid, "BS ID", abbrev, FT_ETHER, BASE_NONE, blurb); + + break; + + case WIMAXASNCP_TLV_HEX8: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT8, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_HEX16: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT16, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_HEX32: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT32, BASE_HEX, blurb); + break; + + case WIMAXASNCP_TLV_DEC8: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT8, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_DEC16: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT16, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_DEC32: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_UINT32, BASE_DEC, blurb); + break; + + case WIMAXASNCP_TLV_IP_ADDRESS: + wmem_free(wmem_epan_scope(), abbrev); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.ipv4_value", tlv->name)); + + add_reg_info( + &tlv->hf_ipv4, "IPv4 Address", abbrev, FT_IPv4, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.ipv6_value", tlv->name)); + + add_reg_info( + &tlv->hf_ipv6, "IPv6 Address", abbrev, FT_IPv6, BASE_NONE, blurb); + + break; + + case WIMAXASNCP_TLV_IPV4_ADDRESS: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_IPv4, BASE_NONE, blurb); + break; + + case WIMAXASNCP_TLV_PROTOCOL_LIST: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + + blurb = wmem_strdup_printf(wmem_epan_scope(), "value component for type=%u", tlv->type); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.protocol", tlv->name)); + + add_reg_info( + &tlv->hf_protocol, "Protocol", abbrev, FT_UINT16, BASE_DEC, blurb); + + break; + + case WIMAXASNCP_TLV_PORT_RANGE_LIST: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + + blurb = wmem_strdup_printf(wmem_epan_scope(), "value component for type=%u", tlv->type); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.port_low", tlv->name)); + + add_reg_info( + &tlv->hf_port_low, "Port Low", abbrev, FT_UINT16, BASE_DEC, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.port_high", tlv->name)); + + add_reg_info( + &tlv->hf_port_high, "Port High", abbrev, FT_UINT16, BASE_DEC, blurb); + + break; + + case WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + + blurb = wmem_strdup_printf(wmem_epan_scope(), "value component for type=%u", tlv->type); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.ipv4", tlv->name)); + + add_reg_info( + &tlv->hf_ipv4, "IPv4 Address", abbrev, FT_IPv4, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.ipv4_mask", tlv->name)); + + add_reg_info( + &tlv->hf_ipv4_mask, "IPv4 Mask", abbrev, FT_IPv4, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.ipv6", tlv->name)); + + add_reg_info( + &tlv->hf_ipv6, "IPv6 Address", abbrev, FT_IPv6, BASE_NONE, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.ipv6_mask", tlv->name)); + + add_reg_info( + &tlv->hf_ipv6_mask, "IPv6 Mask", abbrev, FT_IPv6, BASE_NONE, blurb); + + break; + + case WIMAXASNCP_TLV_VENDOR_SPECIFIC: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + + blurb = wmem_strdup_printf(wmem_epan_scope(), "value component for type=%u", tlv->type); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), "wimaxasncp.tlv.%s.value.vendor_id", tlv->name)); + + add_reg_info( + &tlv->hf_vendor_id, "Vendor ID", abbrev, FT_UINT24, BASE_DEC, blurb); + + abbrev = alnumerize( + wmem_strdup_printf(wmem_epan_scope(), + "wimaxasncp.tlv.%s.value.vendor_rest_of_info", tlv->name)); + + add_reg_info( + &tlv->hf_vendor_rest_of_info, "Rest of Info", abbrev, FT_BYTES, BASE_NONE, + blurb); + + break; + + case WIMAXASNCP_TLV_EAP: + blurb = wmem_strdup_printf(wmem_epan_scope(), "EAP payload embedded in %s", name); + + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + break; + + + default: + add_reg_info( + &tlv->hf_value, name, abbrev, FT_BYTES, BASE_NONE, blurb); + + if (debug_enabled) + { + g_print( + "fix-me: unknown decoder: %d\n", tlv->decoder); + } + + break; + } +} + +/* ========================================================================= */ +/* Register the protocol fields and subtrees with Wireshark */ +static void +register_wimaxasncp_fields(const char* unused _U_) +{ + gboolean debug_parser; + gboolean dump_dict; + gchar *dir; + gchar* dict_error; + + /* ------------------------------------------------------------------------ + * List of header fields + * ------------------------------------------------------------------------ + */ + + static hf_register_info hf_base[] = { + { + &hf_wimaxasncp_version, /* ID */ + { + "Version", /* FIELDNAME */ + "wimaxasncp.version", /* PROTOABBREV.FIELDABBRE */ + FT_UINT8, /* FIELDTYPE */ + BASE_DEC, /* FIELDBASE */ + NULL, /* FIELDCONVERT */ + 0x0, /* BITMASK */ + NULL, /* FIELDDESCR */ + HFILL /* HFILL */ + } + }, + { + &hf_wimaxasncp_flags, + { + "Flags", + "wimaxasncp.flags", + FT_UINT8, + BASE_HEX, + NULL, + 0xff, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_function_type, + { + "Function Type", + "wimaxasncp.function_type", + FT_UINT8, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_op_id, + { + "OP ID", + "wimaxasncp.opid", + FT_UINT8, + BASE_HEX, + VALS(wimaxasncp_op_id_vals), + 0xE0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_message_type, + { + "Message Type", + "wimaxasncp.message_type", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#if 0 + { + &hf_wimaxasncp_qos_msg, + { + "Message Type", + "wimaxasncp.qos_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_ho_control_msg, + { + "Message Type", + "wimaxasncp.ho_control_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_data_path_control_msg, + { + "Message Type", + "wimaxasncp.data_path_control_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_context_delivery_msg, + { + "Message Type", + "wimaxasncp.context_delivery_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_r3_mobility_msg, + { + "Message Type", + "wimaxasncp.r3_mobility_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_paging_msg, + { + "Message Type", + "wimaxasncp.paging_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_rrm_msg, + { + "Message Type", + "wimaxasncp.rrm_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_authentication_msg, + { + "Message Type", + "wimaxasncp.authentication_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_ms_state_msg, + { + "Message Type", + "wimaxasncp.ms_state_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_reauthentication_msg, + { + "Message Type", + "wimaxasncp.reauthentication_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_session_msg, + { + "Message Type", + "wimaxasncp.session_msg", + FT_UINT8, + BASE_HEX, + NULL, + 0x1F, + NULL, + HFILL + } + }, +#endif + { + &hf_wimaxasncp_length, + { + "Length", + "wimaxasncp.length", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_msid, + { + "MSID", + "wimaxasncp.msid", + FT_ETHER, + BASE_NONE, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_reserved1, + { + "Reserved", + "wimaxasncp.reserved1", + FT_UINT32, + BASE_HEX, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_transaction_id, + { + "Transaction ID", + "wimaxasncp.transaction_id", + FT_UINT16, + BASE_HEX, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_reserved2, + { + "Reserved", + "wimaxasncp.reserved2", + FT_UINT16, + BASE_HEX, + NULL, + 0x0, + NULL, + HFILL + } + }, +#if 0 + { + &hf_wimaxasncp_tlv, + { + "TLV", + "wimaxasncp.tlv", + FT_BYTES, + BASE_NONE, + NULL, + 0x0, + NULL, + HFILL + } + }, +#endif + { + &hf_wimaxasncp_tlv_type, + { + "Type", + "wimaxasncp.tlv.type", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_tlv_length, + { + "Length", + "wimaxasncp.tlv.length", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_tlv_value_bytes, + { + "Value", + "wimaxasncp.tlv_value_bytes", + FT_BYTES, + BASE_NONE, + NULL, + 0x0, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_tlv_value_bitflags8, + { + "Value", + "wimaxasncp.tlv_value_bitflags8", + FT_UINT8, + BASE_HEX, + NULL, + 0xff, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_tlv_value_bitflags16, + { + "Value", + "wimaxasncp.tlv_value_bitflags16", + FT_UINT16, + BASE_HEX, + NULL, + 0xffff, + NULL, + HFILL + } + }, + { + &hf_wimaxasncp_tlv_value_bitflags32, + { + "Value", + "wimaxasncp.tlv_value_bitflags32", + FT_UINT32, + BASE_HEX, + NULL, + 0xffffffff, + NULL, + HFILL + } + }, +#if 0 + { + &hf_wimaxasncp_tlv_value_protocol, + { + "Value", + "wimaxasncp.tlv_value_protocol", + FT_UINT16, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + }, +#endif +#if 0 + { + &hf_wimaxasncp_tlv_value_vendor_id, + { + "Vendor ID", + "wimaxasncp.tlv_value_vendor_id", + FT_UINT24, + BASE_DEC, + NULL, + 0x0, + NULL, + HFILL + } + } +#endif + }; + + /* ------------------------------------------------------------------------ + * Protocol subtree array + * ------------------------------------------------------------------------ + */ + + static gint *ett_base[] = { + &ett_wimaxasncp, + &ett_wimaxasncp_flags, + &ett_wimaxasncp_tlv, + &ett_wimaxasncp_tlv_value_bitflags8, + &ett_wimaxasncp_tlv_value_bitflags16, + &ett_wimaxasncp_tlv_value_bitflags32, + &ett_wimaxasncp_tlv_protocol_list, + &ett_wimaxasncp_tlv_port_range_list, + &ett_wimaxasncp_tlv_ip_address_mask_list, + &ett_wimaxasncp_tlv_ip_address_mask, + &ett_wimaxasncp_tlv_eap, + &ett_wimaxasncp_tlv_vendor_specific_information_field, + &ett_wimaxasncp_port_range + }; + + static ei_register_info ei[] = { + { &ei_wimaxasncp_tlv_type, { "wimaxasncp.tlv.type.unknown", PI_UNDECODED, PI_WARN, "Unknown tlv", EXPFILL }}, + { &ei_wimaxasncp_function_type, { "wimaxasncp.function_type.unknown", PI_UNDECODED, PI_WARN, "Unknown function type", EXPFILL }}, + { &ei_wimaxasncp_op_id, { "wimaxasncp.opid.unknown", PI_UNDECODED, PI_WARN, "Unknown message op", EXPFILL }}, + { &ei_wimaxasncp_message_type, { "wimaxasncp.message_type.unknown", PI_UNDECODED, PI_WARN, "Unknown message type", EXPFILL }}, + { &ei_wimaxasncp_length_bad, { "wimaxasncp.length.bad", PI_MALFORMED, PI_ERROR, "Bad length", EXPFILL }}, + }; + + expert_module_t* expert_wimaxasncp; + + /* ------------------------------------------------------------------------ + * load the XML dictionary + * ------------------------------------------------------------------------ + */ + + debug_parser = getenv("WIRESHARK_DEBUG_WIMAXASNCP_DICT_PARSER") != NULL; + dump_dict = getenv("WIRESHARK_DUMP_WIMAXASNCP_DICT") != NULL; + + dir = ws_strdup_printf( + "%s" G_DIR_SEPARATOR_S "wimaxasncp", + get_datafile_dir()); + + wimaxasncp_dict = + wimaxasncp_dict_scan(dir, "dictionary.xml", debug_parser, &dict_error); + + g_free(dir); + + if (dict_error) + { + report_failure("wimaxasncp - %s", dict_error); + g_free(dict_error); + } + + if (wimaxasncp_dict && dump_dict) + { + wimaxasncp_dict_print(stdout, wimaxasncp_dict); + } + + /* ------------------------------------------------------------------------ + * build the hf and ett dictionary entries + * ------------------------------------------------------------------------ + */ + + wimaxasncp_build_dict.hf = + wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info)); + + wmem_array_append( + wimaxasncp_build_dict.hf, hf_base, array_length(hf_base)); + + wimaxasncp_build_dict.ett = + wmem_array_new(wmem_epan_scope(), sizeof(gint*)); + + wmem_array_append( + wimaxasncp_build_dict.ett, ett_base, array_length(ett_base)); + + if (wimaxasncp_dict) + { + wimaxasncp_dict_tlv_t *tlv; + + /* For each TLV found in XML file */ + for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next) + { + if (tlv->enums) + { + /* Create array for enums */ + wimaxasncp_dict_enum_t *e; + wmem_array_t* array = wmem_array_new(wmem_epan_scope(), sizeof(value_string)); + + /* Copy each entry into value_string array */ + for (e = tlv->enums; e; e = e->next) + { + value_string item = { e->code, e->name }; + wmem_array_append_one(array, item); + } + + /* Set enums to use with this TLV */ + wmem_array_set_null_terminator(array); + tlv->enum_vs = (value_string*)wmem_array_get_raw(array); + } + + add_tlv_reg_info(tlv); + } + } + + /* add an entry for unknown TLVs */ + add_tlv_reg_info(&wimaxasncp_tlv_not_found); + + /* The following debug will only be printed if the debug_enabled variable + * is set programmatically. Setting the value via preferences will not + * work as it will be set too late to affect this code path. + */ + if (debug_enabled) + { + if (wimaxasncp_dict) + { + wimaxasncp_dict_tlv_t *tlv; + + for (tlv = wimaxasncp_dict->tlvs; tlv; tlv = tlv->next) + { + ws_debug_printf( + "%s\n" + " type = %u\n" + " description = %s\n" + " decoder = %s\n" + " hf_root = %d\n" + " hf_value = %d\n" + " hf_ipv4 = %d\n" + " hf_ipv6 = %d\n" + " hf_bsid = %d\n" + " hf_protocol = %d\n" + " hf_port_low = %d\n" + " hf_port_high = %d\n" + " hf_ipv4_mask = %d\n" + " hf_ipv6_mask = %d\n" + " hf_vendor_id = %d\n" + " hf_vendor_rest_of_info = %d\n", + tlv->name, + tlv->type, + tlv->description, + val_to_str( + tlv->decoder, wimaxasncp_decode_type_vals, "Unknown"), + tlv->hf_root, + tlv->hf_value, + tlv->hf_ipv4, + tlv->hf_ipv6, + tlv->hf_bsid, + tlv->hf_protocol, + tlv->hf_port_low, + tlv->hf_port_high, + tlv->hf_ipv4_mask, + tlv->hf_ipv6_mask, + tlv->hf_vendor_id, + tlv->hf_vendor_rest_of_info); + } + } + } + + /* Required function calls to register the header fields and subtrees + * used */ + proto_register_field_array( + proto_wimaxasncp, + (hf_register_info*)wmem_array_get_raw(wimaxasncp_build_dict.hf), + wmem_array_get_count(wimaxasncp_build_dict.hf)); + + proto_register_subtree_array( + (gint**)wmem_array_get_raw(wimaxasncp_build_dict.ett), + wmem_array_get_count(wimaxasncp_build_dict.ett)); + + expert_wimaxasncp = expert_register_protocol(proto_wimaxasncp); + expert_register_field_array(expert_wimaxasncp, ei, array_length(ei)); + +} + + + + +/* ========================================================================= */ +/* Register the protocol with Wireshark */ + +/* this format is require because a script is used to build the C function + that calls all the protocol registration. +*/ + +void +proto_register_wimaxasncp(void) +{ + module_t *wimaxasncp_module; + + /* ------------------------------------------------------------------------ + * complete registration + * ------------------------------------------------------------------------ + */ + + /* Register the protocol name and description */ + proto_wimaxasncp = proto_register_protocol("WiMAX ASN Control Plane Protocol", "WiMAX ASN CP", "wimaxasncp"); + + /* Register this dissector by name */ + wimaxasncp_handle = register_dissector("wimaxasncp", dissect_wimaxasncp, proto_wimaxasncp); + + wimaxasncp_module = prefs_register_protocol(proto_wimaxasncp, NULL); + + /* Register preferences */ + prefs_register_bool_preference( + wimaxasncp_module, + "show_transaction_id_d_bit", + "Show transaction ID direction bit", + "Show transaction ID direction bit separately from the rest of " + "the transaction ID field.", + &show_transaction_id_d_bit); + + prefs_register_bool_preference( + wimaxasncp_module, + "debug_enabled", + "Enable debug output", + "Print debug output to the console.", + &debug_enabled); + + prefs_register_enum_preference( + wimaxasncp_module, + "nwg_version", + "NWG Version", + "Version of the NWG that the R6 protocol complies with", + &global_wimaxasncp_nwg_ver, + wimaxasncp_nwg_versions, + FALSE); + + proto_register_prefix("wimaxasncp", register_wimaxasncp_fields); +} + +/* ========================================================================= */ +/* If this dissector uses sub-dissector registration add a registration + routine. This exact format is required because a script is used to find + these routines and create the code that calls these routines. + + This function is also called by preferences whenever "Apply" is pressed + (see prefs_register_protocol above) so it should accommodate being called + more than once. +*/ +void +proto_reg_handoff_wimaxasncp(void) +{ + /* Find the EAP dissector */ + eap_handle = find_dissector_add_dependency("eap", proto_wimaxasncp); + + dissector_add_uint_with_preference("udp.port", WIMAXASNCP_DEF_UDP_PORT, wimaxasncp_handle); +} + + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/wimaxasncp/wimaxasncp_dict.h b/plugins/epan/wimaxasncp/wimaxasncp_dict.h new file mode 100644 index 0000000..6f13652 --- /dev/null +++ b/plugins/epan/wimaxasncp/wimaxasncp_dict.h @@ -0,0 +1,114 @@ +/* + ** wimaxasncp_dict.h + ** WIMAXASNCP Dictionary Import Routines + ** + ** (c) 2007, Stephen Croll + ** + ** SPDX-License-Identifier: LGPL-2.0-or-later + */ + +#ifndef _WIMAXASNCP_DICT_H_ +#define _WIMAXASNCP_DICT_H_ + +/* ------------------------------------------------------------------------- + * NWG versions + * ------------------------------------------------------------------------- */ + +#define WIMAXASNCP_NWGVER_R10_V100 0 +#define WIMAXASNCP_NWGVER_R10_V120 1 +#define WIMAXASNCP_NWGVER_R10_V121 2 +#define WIMAXASNCP_NWGVER_NUM 3 + +/* ------------------------------------------------------------------------- + * decode types + * ------------------------------------------------------------------------- */ + +enum +{ + WIMAXASNCP_TLV_UNKNOWN, + WIMAXASNCP_TLV_TBD, + WIMAXASNCP_TLV_COMPOUND, + WIMAXASNCP_TLV_BYTES, + WIMAXASNCP_TLV_ENUM8, + WIMAXASNCP_TLV_ENUM16, + WIMAXASNCP_TLV_ENUM32, + WIMAXASNCP_TLV_ETHER, + WIMAXASNCP_TLV_ASCII_STRING, + WIMAXASNCP_TLV_FLAG0, + WIMAXASNCP_TLV_BITFLAGS8, + WIMAXASNCP_TLV_BITFLAGS16, + WIMAXASNCP_TLV_BITFLAGS32, + WIMAXASNCP_TLV_ID, + WIMAXASNCP_TLV_HEX8, + WIMAXASNCP_TLV_HEX16, + WIMAXASNCP_TLV_HEX32, + WIMAXASNCP_TLV_DEC8, + WIMAXASNCP_TLV_DEC16, + WIMAXASNCP_TLV_DEC32, + WIMAXASNCP_TLV_IP_ADDRESS, /* Note: IPv4 or IPv6, determined by length */ + WIMAXASNCP_TLV_IPV4_ADDRESS, + WIMAXASNCP_TLV_PROTOCOL_LIST, + WIMAXASNCP_TLV_PORT_RANGE_LIST, + WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST, + WIMAXASNCP_TLV_EAP, + WIMAXASNCP_TLV_VENDOR_SPECIFIC +}; + +/* ------------------------------------------------------------------------- + * structures and functions + * ------------------------------------------------------------------------- */ + +struct _wimaxasncp_dict_namecode_t { + gchar *name; + guint code; + struct _wimaxasncp_dict_namecode_t *next; +}; + +typedef struct _wimaxasncp_dict_namecode_t wimaxasncp_dict_enum_t; + +typedef struct _wimaxasncp_dict_tlv_t { + guint16 type; + gchar *name; + gchar *description; + gint decoder; + guint since; + int hf_root; + int hf_value; + int hf_ipv4; + int hf_ipv6; + int hf_bsid; + int hf_protocol; + int hf_port_low; + int hf_port_high; + int hf_ipv4_mask; + int hf_ipv6_mask; + int hf_vendor_id; + int hf_vendor_rest_of_info; + value_string *enum_vs; + wimaxasncp_dict_enum_t *enums; + struct _wimaxasncp_dict_tlv_t *next; +} wimaxasncp_dict_tlv_t; + +typedef struct _wimaxasncp_dict_xmlpi_t { + gchar *name; + gchar *key; + gchar *value; + struct _wimaxasncp_dict_xmlpi_t *next; +} wimaxasncp_dict_xmlpi_t; + +typedef struct _wimaxasncp_dict_t { + wimaxasncp_dict_tlv_t *tlvs; + wimaxasncp_dict_xmlpi_t *xmlpis; +} wimaxasncp_dict_t; + +extern void wimaxasncp_dict_print( + FILE *fh, wimaxasncp_dict_t *d); + +extern wimaxasncp_dict_t *wimaxasncp_dict_scan( + const gchar *system_directory, const gchar *filename, int dbg, + gchar **error); + +extern void wimaxasncp_dict_free( + wimaxasncp_dict_t *d); + +#endif diff --git a/plugins/epan/wimaxasncp/wimaxasncp_dict.l b/plugins/epan/wimaxasncp/wimaxasncp_dict.l new file mode 100644 index 0000000..05fa2e5 --- /dev/null +++ b/plugins/epan/wimaxasncp/wimaxasncp_dict.l @@ -0,0 +1,867 @@ +%top { +/* Include this before everything else, for various large-file definitions */ +#include "config.h" +#include +} + +/* + * We want a reentrant scanner. + */ +%option reentrant + +/* + * We don't use input, so don't generate code for it. + */ +%option noinput + +/* + * We don't use unput, so don't generate code for it. + */ +%option nounput + +/* + * We don't read interactively from the terminal. + */ +%option never-interactive + +/* + * We want to stop processing when we get to the end of the input. + */ +%option noyywrap + +/* + * The type for the state we keep for a scanner. + */ +%option extra-type="WimaxasncpDict_scanner_state_t *" + +/* + * We have to override the memory allocators so that we don't get + * "unused argument" warnings from the yyscanner argument (which + * we don't use, as we have a global memory allocator). + * + * We provide, as macros, our own versions of the routines generated by Flex, + * which just call malloc()/realloc()/free() (as the Flex versions do), + * discarding the extra argument. + */ +%option noyyalloc +%option noyyrealloc +%option noyyfree + +/* + * The language we're scanning is case-insensitive. + */ +%option caseless + +/* + * We use start condition stacks. + */ +%option stack + +/* + * Prefix scanner routines with "WimaxasncpDict_" rather than "yy", so this + * scanner can coexist with other scanners. + */ +%option prefix="WimaxasncpDict_" + +%option outfile="wimaxasncp_dict.c" + +%{ + /* + ** wimaxasncp_dict.h + ** WIMAXASNCP Dictionary Import Routines + ** + ** (c) 2007, Luis E. Garcia Ontanon + ** (c) 2007, Stephen Croll + ** + ** This library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Library General Public + ** License as published by the Free Software Foundation; either + ** version 2 of the License, or (at your option) any later version. + ** + ** This library 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 + ** Library General Public License for more details. + ** + ** You should have received a copy of the GNU Library General Public + ** License along with this library; if not, write to the Free Software + ** Foundation, Inc., 51 Franklin Street, Fifth Floor, + ** Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* array_length */ +#include + +#include "wimaxasncp_dict.h" + +/* + * Disable diagnostics in the code generated by Flex. + */ +DIAG_OFF_FLEX() + +typedef struct entity_t { + gchar *name; + gchar *file; + struct entity_t *next; +} entity_t; + +#define ATTR_UINT(cont) do { D(("attr_uint " #cont "\t" )); yyextra->attr_uint = &(cont); yy_push_state(GET_UINT_ATTR, yyscanner); } while(0) +#define ATTR_UINT16(cont) do { D(("attr_uint16 " #cont "\t" )); yyextra->attr_uint16 = &(cont); yy_push_state(GET_UINT16_ATTR, yyscanner); } while(0) +#define ATTR_STR(cont) do { D(("attr_str " #cont "\t" )); yyextra->attr_str = &(cont); yy_push_state(GET_ATTR, yyscanner); } while(0) +#define ATTR_DECODER(cont) do { D(("attr_decoder " #cont "\t" )); yyextra->attr_uint = &(cont); yy_push_state(GET_DECODER_ATTR, yyscanner); } while(0) +#define WIMAXASNCP_IGNORE() do { D(("ignore: %s\t",yytext)); yy_push_state(IGNORE_ATTR, yyscanner); } while(0) + +#define D(args) wimaxasncp_dict_debug args + +#define MAX_INCLUDE_DEPTH 10 +#define YY_INPUT(buf,result,max_size) { result = yyextra->current_yyinput(buf,max_size,yyscanner); } +#define YY_USER_INIT { \ + WimaxasncpDict_scanner_state_t *scanner_state = WimaxasncpDict_get_extra(yyscanner); \ + BEGIN(scanner_state->start_state); \ +} +#define ECHO +#define APPEND(txt,len) append_to_buffer(txt,(int)len,yyextra) + +typedef struct { + GString *dict_error; + + const gchar *sys_dir; + + gchar *strbuf; + guint size_strbuf; + guint len_strbuf; + + gchar *write_ptr; + gchar *read_ptr; + + wimaxasncp_dict_t *dict; + wimaxasncp_dict_tlv_t *tlv; + wimaxasncp_dict_enum_t *enumitem; + wimaxasncp_dict_xmlpi_t *xmlpi; + + wimaxasncp_dict_tlv_t *last_tlv; + wimaxasncp_dict_enum_t *last_enumitem; + wimaxasncp_dict_xmlpi_t *last_xmlpi; + + entity_t *ents; + + YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; + int include_stack_ptr; + size_t (*current_yyinput)(gchar*,size_t,yyscan_t); + + gchar **attr_str; + guint *attr_uint; + gint16 *attr_uint16; + + int start_state; +} WimaxasncpDict_scanner_state_t; + +static guint wimaxasncp_bits(guint bits, char *n); +static gint wimaxasncp_decode_type(const gchar *name); +static void wimaxasncp_dict_debug(const gchar *fmt, ...) G_GNUC_PRINTF(1, 2); +static void append_to_buffer(const gchar *txt, int len, WimaxasncpDict_scanner_state_t *state); +static FILE *wimaxasncp_dict_open(const gchar*, const gchar*); + +/* + * Sleazy hack to suppress compiler warnings in yy_fatal_error(). + */ +#define YY_EXIT_FAILURE ((void)yyscanner, 2) + +/* + * Macros for the allocators, to discard the extra argument. + */ +#define WimaxasncpDict_alloc(size, yyscanner) (void *)malloc(size) +#define WimaxasncpDict_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) +#define WimaxasncpDict_free(ptr, yyscanner) free((char *)ptr) + +%} + + +xmlpi_start [[:blank:] \r\n]*<\?[[:blank:] \r\n]* +xmlpi_end [[:blank:] \r\n]*\?>[[:blank:] \r\n]* +xmlpi_key_attr [[:blank:] \r\n]*key[[:blank:] \r\n]*=[[:blank:] \r\n]*\042 +xmlpi_value_attr [[:blank:] \r\n]*value[[:blank:] \r\n]*=[[:blank:] \r\n]*\042 + +comment_start [[:blank:] \r\n]*[[:blank:] \r\n]* +open_tag [[:blank:] \r\n]*<[[:blank:] \r\n]* +end_tag [[:blank:] \r\n]*\/>[[:blank:] \r\n]* +close_tag [[:blank:] \r\n]*>[[:blank:] \r\n]* +open_closetag [[:blank:] \r\n]*<\/[[:blank:] \r\n]* +equals [[:blank:] \r\n]*=[[:blank:] \r\n]* +whitespace [[:blank:] \r\n]* +dquoted \042[^\042]*\042 + +doctype [[:blank:] \r\n]*[[:blank:] \r\n]* + +start_entity [[:blank:] \r\n]*<\!ENTITY[[:blank:] \r\n]* +system [[:blank:] \r\n]*SYSTEM[[:blank:] \r\n]*\042 +entityname [a-z0-9-]+ +ndquot [^\042]+ +end_entity \042[[:blank:] \r\n]*>[[:blank:] \r\n]* + +entity \&[a-z0-9-]+; + +any . + + + + +stop > +stop_end \/> +dquot \042 +number [-]?[0-9]*|(0x)?[0-9a-fA-F]* + +dictionary_start +dictionary_end <\/dictionary> + +tlv_start + +type_start {doctype} ; +{doctype_end} ; + +{comment_start} BEGIN LOADING_COMMENT; +. ; +{comment_end} BEGIN LOADING; + +{xmlpi_start} BEGIN LOADING_XMLPI; +{whitespace} ; +{entityname} { + yyextra->xmlpi = g_new(wimaxasncp_dict_xmlpi_t,1); + yyextra->xmlpi->name = g_strdup(yytext); + yyextra->xmlpi->key = NULL; + yyextra->xmlpi->value = NULL; + yyextra->xmlpi->next = NULL; + + if (!yyextra->dict->xmlpis) yyextra->last_xmlpi = yyextra->dict->xmlpis = yyextra->xmlpi; + else yyextra->last_xmlpi = yyextra->last_xmlpi->next = yyextra->xmlpi; + + BEGIN XMLPI_ATTRS; +} + +{xmlpi_key_attr} BEGIN XMLPI_GETKEY; +{ndquot} { yyextra->xmlpi->key = g_strdup(yytext); BEGIN XMLPI_ATTRS; } + +{xmlpi_value_attr} BEGIN XMLPI_GETVAL; +{ndquot} { yyextra->xmlpi->value = g_strdup(yytext); BEGIN XMLPI_ATTRS; } + +. +{xmlpi_end} BEGIN LOADING; + + +{start_entity} BEGIN ENTITY; +{entityname} { + entity_t *e = g_new(entity_t,1); + D(("ENTITY: %s\n",yytext)); + e->name = g_strdup(yytext); + e->next = yyextra->ents; + yyextra->ents = e; + BEGIN GET_SYSTEM; +}; +{system} BEGIN GET_FILE; +{ndquot} { + D(("GET_FILE: %s\n",yytext)); + yyextra->ents->file = g_strdup(yytext); + BEGIN END_ENTITY; +} +{end_entity} BEGIN LOADING; + +{open_tag} APPEND("<",1); + +{close_tag} APPEND(">",1); + +{end_tag} APPEND("/>",2); + +{open_closetag} APPEND("{whitespace} APPEND(" ",1); + +{dquoted} APPEND(yytext,yyleng); + +{equals} APPEND("=",1); + +{any} APPEND(yytext,yyleng); + +{entity} { + gchar *p = ++yytext, *temp_str; + entity_t* e; + + while(*p != ';') p++; + + *p = '\0'; + + D(("looking for entity: %s\n",yytext)); + + if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) { + yyextra->dict_error = g_string_append( + yyextra->dict_error, "included files nested too deeply\n"); + yyterminate(); + } + + yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER; + + + for (e = yyextra->ents; e; e = e->next) { + if (strcmp(e->name,yytext) == 0) { + yyin = wimaxasncp_dict_open(yyextra->sys_dir,e->file); + D(("entity: %s filename: %s yyin: %p\n",e->name,e->file,(void*)yyin)); + if (!yyin) { + yyterminate(); + } else { + WimaxasncpDict__switch_to_buffer(WimaxasncpDict__create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner); + } + break; + } + } + + if (!e) { + temp_str = ws_strdup_printf( + "cannot find entity: '%s'\n", yytext); + yyextra->dict_error = g_string_append(yyextra->dict_error, temp_str); + g_free(temp_str); + yyterminate(); + } + +} + +<> { + if (!yyin) yyterminate(); + + fclose(yyin); + D(("closing: %p %i\n",(void*)yyin,yyextra->include_stack_ptr)); + + if ( --yyextra->include_stack_ptr < 0 ) { + D(("DONE READING\n")); + yyin = NULL; + yyterminate(); + } else { + WimaxasncpDict__delete_buffer(YY_CURRENT_BUFFER, yyscanner); + WimaxasncpDict__switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner); + BEGIN LOADING; + } +} + + +{ndquot} { + *yyextra->attr_str = wmem_strdup(wmem_epan_scope(), yytext); + D(("%s\n",yytext)); + yyextra->attr_str = NULL; + BEGIN END_ATTR; +} + +{number} { + *yyextra->attr_uint = (guint)strtoul(yytext,NULL,0); + D(("%s\n",yytext);); + yyextra->attr_uint = NULL; + BEGIN END_ATTR; +} + +{number} { + *yyextra->attr_uint16 = (gint16) strtol(yytext,NULL,0); + D(("%s\n",yytext);); + yyextra->attr_uint16 = NULL; + BEGIN END_ATTR; +} + +"WIMAXASNCP_BIT32"[ \t]*"(" { BEGIN BIT32; } + +[0-9]+ { + *yyextra->attr_uint = wimaxasncp_bits(32, yytext); + D(("WIMAXASNCP_BIT32(%s)\n",yytext);); + yyextra->attr_uint = NULL; +} + +"WIMAXASNCP_BIT16"[ \t]*"(" { BEGIN BIT16; } + +[0-9]+ { + *yyextra->attr_uint = wimaxasncp_bits(16, yytext); + D(("WIMAXASNCP_BIT16(%s)\n",yytext);); + yyextra->attr_uint = NULL; +} + +"WIMAXASNCP_BIT8"[ \t]*"(" { BEGIN BIT8; } + +[0-9]+ { + *yyextra->attr_uint = wimaxasncp_bits(8, yytext); + D(("WIMAXASNCP_BIT8(%s)\n",yytext);); + yyextra->attr_uint = NULL; +} + +[ \t]*")" { BEGIN END_ATTR; } + +{ndquot} { + *yyextra->attr_uint = wimaxasncp_decode_type(yytext); + D(("%s\n",yytext)); + yyextra->attr_uint = NULL; + BEGIN END_ATTR; +} + +{dquot} { yy_pop_state(yyscanner); } + +. { + /* XXX: should go?*/ + D(("{%s}",yytext)); +} + +{ignored_quoted} { + D(("=>%s<=\n",yytext)); + yy_pop_state(yyscanner); +} + +{dictionary_start} { + D(("dictionary_start\n")); + + BEGIN IN_DICT; +} + +{tlv_start} { + D(("tlv_start\n")); + + yyextra->tlv = wmem_new0(wmem_epan_scope(), wimaxasncp_dict_tlv_t); + yyextra->tlv->hf_root = -1; + yyextra->tlv->hf_value = -1; + yyextra->tlv->hf_ipv4 = -1; + yyextra->tlv->hf_ipv6 = -1; + yyextra->tlv->hf_bsid = -1; + yyextra->tlv->hf_protocol = -1; + yyextra->tlv->hf_port_low = -1; + yyextra->tlv->hf_port_high = -1; + yyextra->tlv->hf_ipv4_mask = -1; + yyextra->tlv->hf_ipv6_mask = -1; + yyextra->tlv->hf_vendor_id = -1; + yyextra->tlv->hf_vendor_rest_of_info = -1; + + if (! yyextra->dict->tlvs ) + yyextra->last_tlv = yyextra->dict->tlvs = yyextra->tlv; + else + yyextra->last_tlv = yyextra->last_tlv->next = yyextra->tlv; + + BEGIN TLV_ATTRS; +} + +{name_attr} { ATTR_STR(yyextra->tlv->name); } +{description_attr} { ATTR_STR(yyextra->tlv->description); } +{type_attr} { ATTR_UINT16(yyextra->tlv->type); } +{decoder_attr} { ATTR_DECODER(yyextra->tlv->decoder); } +{since_attr} { ATTR_UINT(yyextra->tlv->since); } +{stop} { BEGIN IN_TLV; } +{stop_end} { BEGIN IN_DICT; } + + +{enum_start} { + D(("enum_start\n")); + + yyextra->enumitem = wmem_new(wmem_epan_scope(), wimaxasncp_dict_enum_t); + yyextra->enumitem->name = NULL; + yyextra->enumitem->code = 0; + yyextra->enumitem->next = NULL; + + if (!yyextra->tlv->enums) + yyextra->last_enumitem = yyextra->tlv->enums = yyextra->enumitem; + else + yyextra->last_enumitem = yyextra->last_enumitem->next = yyextra->enumitem; + + BEGIN ENUM_ATTRS; +} + + +{name_attr} { ATTR_STR(yyextra->enumitem->name); } +{code_attr} { ATTR_UINT(yyextra->enumitem->code); } + +{stop} { BEGIN IN_TLV; } +{stop_end} { BEGIN IN_TLV; } + +{tlv_end} { D(("tlv_end")); BEGIN IN_DICT; } + +{dictionary_end} { + yyterminate(); +} + +{ignored_attr} WIMAXASNCP_IGNORE(); + +. ; + +%% + +/* + * Turn diagnostics back on, so we check the code that we've written. + */ +DIAG_ON_FLEX() + +static int debugging = 0; + +static void wimaxasncp_dict_debug(const gchar *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + if (debugging) vfprintf(stderr, fmt, ap); + va_end(ap); + + fflush(stderr); +} + +static guint wimaxasncp_bits(guint bits, char *n) +{ + return 1u << ((bits - 1) - (strtoul(n, NULL, 10))); +} + +static const value_string wimaxasncp_decode_type_vals[] = +{ + { WIMAXASNCP_TLV_TBD, "WIMAXASNCP_TLV_TBD"}, + { WIMAXASNCP_TLV_COMPOUND, "WIMAXASNCP_TLV_COMPOUND"}, + { WIMAXASNCP_TLV_BYTES, "WIMAXASNCP_TLV_BYTES"}, + { WIMAXASNCP_TLV_ENUM8, "WIMAXASNCP_TLV_ENUM8"}, + { WIMAXASNCP_TLV_ENUM16, "WIMAXASNCP_TLV_ENUM16"}, + { WIMAXASNCP_TLV_ENUM32, "WIMAXASNCP_TLV_ENUM32"}, + { WIMAXASNCP_TLV_ETHER, "WIMAXASNCP_TLV_ETHER"}, + { WIMAXASNCP_TLV_ASCII_STRING, "WIMAXASNCP_TLV_ASCII_STRING"}, + { WIMAXASNCP_TLV_FLAG0, "WIMAXASNCP_TLV_FLAG0"}, + { WIMAXASNCP_TLV_BITFLAGS8, "WIMAXASNCP_TLV_BITFLAGS8"}, + { WIMAXASNCP_TLV_BITFLAGS16, "WIMAXASNCP_TLV_BITFLAGS16"}, + { WIMAXASNCP_TLV_BITFLAGS32, "WIMAXASNCP_TLV_BITFLAGS32"}, + { WIMAXASNCP_TLV_ID, "WIMAXASNCP_TLV_ID"}, + { WIMAXASNCP_TLV_HEX8, "WIMAXASNCP_TLV_HEX8"}, + { WIMAXASNCP_TLV_HEX16, "WIMAXASNCP_TLV_HEX16"}, + { WIMAXASNCP_TLV_HEX32, "WIMAXASNCP_TLV_HEX32"}, + { WIMAXASNCP_TLV_DEC8, "WIMAXASNCP_TLV_DEC8"}, + { WIMAXASNCP_TLV_DEC16, "WIMAXASNCP_TLV_DEC16"}, + { WIMAXASNCP_TLV_DEC32, "WIMAXASNCP_TLV_DEC32"}, + { WIMAXASNCP_TLV_IP_ADDRESS, "WIMAXASNCP_TLV_IP_ADDRESS"}, + { WIMAXASNCP_TLV_IPV4_ADDRESS, "WIMAXASNCP_TLV_IPV4_ADDRESS"}, + { WIMAXASNCP_TLV_PROTOCOL_LIST, "WIMAXASNCP_TLV_PROTOCOL_LIST"}, + { WIMAXASNCP_TLV_PORT_RANGE_LIST, "WIMAXASNCP_TLV_PORT_RANGE_LIST"}, + { WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST,"WIMAXASNCP_TLV_IP_ADDRESS_MASK_LIST"}, + { WIMAXASNCP_TLV_EAP, "WIMAXASNCP_TLV_EAP"}, + { WIMAXASNCP_TLV_VENDOR_SPECIFIC, "WIMAXASNCP_TLV_VENDOR_SPECIFIC"}, + { 0, NULL} +}; + +static gint wimaxasncp_decode_type(const gchar *name) +{ + gsize i; + for (i = 0; i < array_length(wimaxasncp_decode_type_vals) - 1; ++i) + { + if (strcmp(name, wimaxasncp_decode_type_vals[i].strptr) == 0) + { + return wimaxasncp_decode_type_vals[i].value; + } + } + + /* not found, emit some sort of error here? */ + + return WIMAXASNCP_TLV_TBD; +} + +extern void wimaxasncp_dict_unused(yyscan_t yyscanner); +void wimaxasncp_dict_unused(yyscan_t yyscanner) { + yy_top_state(yyscanner); +} + +static void append_to_buffer(const gchar *txt, int len, WimaxasncpDict_scanner_state_t *state) { + + if (state->strbuf == NULL) { + state->read_ptr = state->write_ptr = state->strbuf = (gchar *)g_malloc(state->size_strbuf); + } + + if (state->len_strbuf + len >= state->size_strbuf) { + state->read_ptr = state->strbuf = (gchar *)g_realloc(state->strbuf,state->size_strbuf *= 2); + } + + state->write_ptr = state->strbuf + state->len_strbuf; + memcpy(state->write_ptr, txt, len + 1); + state->len_strbuf += len; +} + +static size_t file_input(gchar *buf, size_t max, yyscan_t scanner) { + FILE *in = yyget_in(scanner); + size_t read_cnt; + + read_cnt = fread(buf,1,max,in); + + if ( read_cnt == max ) { + return max; + } else if (read_cnt > 0) { + return read_cnt; + } else { + return YY_NULL; + } +} + + +static size_t string_input(gchar *buf, size_t max, yyscan_t scanner) { + WimaxasncpDict_scanner_state_t *statep = yyget_extra(scanner); + + if (statep->read_ptr >= statep->write_ptr ) { + return YY_NULL; + } else if ( statep->read_ptr + max > statep->write_ptr ) { + max = statep->write_ptr - statep->read_ptr; + } + + memcpy(buf,statep->read_ptr,max); + statep->read_ptr += max; + + return max; +} + +static FILE *wimaxasncp_dict_open( + const gchar *system_directory, + const gchar *filename) +{ + FILE *fh; + gchar *fname; + if (system_directory) + { + fname = ws_strdup_printf("%s%s%s", + system_directory, G_DIR_SEPARATOR_S,filename); + } + else + { + fname = g_strdup(filename); + } + + fh = ws_fopen(fname,"r"); + + D(("fname: %s fh: %p\n",fname,(void*)fh)); + + g_free(fname); + + + return fh; +} + +wimaxasncp_dict_t *wimaxasncp_dict_scan( + const gchar *system_directory, const gchar *filename, int dbg, + gchar **error) { + + WimaxasncpDict_scanner_state_t state; + FILE *in; + yyscan_t scanner; + entity_t *e; + + debugging = dbg; + + state.dict_error = g_string_new(""); + + state.sys_dir = system_directory; + + state.dict = g_new(wimaxasncp_dict_t,1); + state.dict->tlvs = NULL; + state.dict->xmlpis = NULL; + + state.strbuf = NULL; + state.size_strbuf = 8192; + state.len_strbuf = 0; + + state.write_ptr = NULL; + state.read_ptr = NULL; + + state.tlv = NULL; + state.enumitem = NULL; + state.xmlpi = NULL; + + state.last_tlv = NULL; + state.last_enumitem = NULL; + state.last_xmlpi = NULL; + + state.ents = NULL; + + /* + * Pass 1. + * + * Reads the file, does some work, and stores a modified version + * of the file contents in memory. + */ + state.current_yyinput = file_input; + state.include_stack_ptr = 0; + + in = wimaxasncp_dict_open(system_directory,filename); + + if (in == NULL) { + /* + * Couldn't open the dictionary. + * + * Treat all failures other then ENOENT as errors? + */ + *error = NULL; + return state.dict; + } + + if (WimaxasncpDict_lex_init(&scanner) != 0) { + D(("Can't initialize scanner: %s\n", strerror(errno))); + fclose(in); + g_free(state.dict); + return NULL; + } + + WimaxasncpDict_set_in(in, scanner); + + /* Associate the state with the scanner */ + WimaxasncpDict_set_extra(&state, scanner); + + state.start_state = LOADING; + WimaxasncpDict_lex(scanner); + + WimaxasncpDict_lex_destroy(scanner); + /* + * XXX - can the lexical analyzer terminate without closing + * all open input files? + */ + + D(("\n---------------\n%s\n------- %d -------\n", + state.strbuf, state.len_strbuf)); + + /* + * Pass 2. + * + * Reads the modified version of the file contents and does the + * rest of the work. + */ + state.current_yyinput = string_input; + + if (WimaxasncpDict_lex_init(&scanner) != 0) { + D(("Can't initialize scanner: %s\n", strerror(errno))); + fclose(in); + g_free(state.dict); + g_free(state.strbuf); + return NULL; + } + + /* Associate the state with the scanner */ + WimaxasncpDict_set_extra(&state, scanner); + + state.start_state = OUTSIDE; + WimaxasncpDict_lex(scanner); + + WimaxasncpDict_lex_destroy(scanner); + g_free(state.strbuf); + + e = state.ents; + while (e) + { + entity_t *next = e->next; + g_free(e->name); + g_free(e->file); + g_free(e); + e = next; + } + + if (state.dict_error->len > 0) + { + *error = g_string_free(state.dict_error, FALSE); + } + else + { + *error = NULL; + g_string_free(state.dict_error, TRUE); + } + return state.dict; +} + +void wimaxasncp_dict_free(wimaxasncp_dict_t *d) { + wimaxasncp_dict_tlv_t *t, *tn; + +#define FREE_NAMEANDOBJ(n) do { g_free(n->name); g_free(n); } while(0) + + for (t = d->tlvs; t; t = tn) { + wimaxasncp_dict_enum_t *e, *en; + tn = t->next; + + for (e = t->enums; e; e = en) { + en = e->next; + FREE_NAMEANDOBJ(e); + } + + g_free(t->description); + FREE_NAMEANDOBJ(t); + } + + g_free(d); +} + +void wimaxasncp_dict_print(FILE *fh, wimaxasncp_dict_t *d) { + wimaxasncp_dict_tlv_t *tlvp; + + fprintf(fh,"\n"); + + for (tlvp = d->tlvs; tlvp; tlvp = tlvp->next) { + wimaxasncp_dict_enum_t *e; + fprintf(fh,"TLV: %s[%u] %s[%d] %s (since %u)\n", + tlvp->name ? tlvp->name : "-", + tlvp->type, + val_to_str(tlvp->decoder, + wimaxasncp_decode_type_vals, + "Unknown"), + tlvp->decoder, + tlvp->description ? tlvp->description : "", + tlvp->since); + + for (e = tlvp->enums; e; e = e->next) { + fprintf(fh,"\tEnum: %s[%u]\n", + e->name ? e->name : "-", + e->code); + } + } +} + +#ifdef TEST_WIMAXASNCP_DICT_STANDALONE +int main(int argc, char **argv) { + wimaxasncp_dict_t *d; + gchar *dname = NULL; + gchar *fname; + int i = 1; + + switch (argc) { + case 3: + dname = argv[i++]; + case 2: + fname = argv[i]; + break; + default: + fprintf(stderr,"%s: usage [dictionary_dir] dictionary_filename\n",argv[0]); + return 1; + } + + d = wimaxasncp_dict_scan(dname,fname,1,&dict_error); + + if (dict_error) + { + printf("wimaxasncp - %s", dict_error); + g_free(dict_error); + } + + wimaxasncp_dict_print(stdout, d); + + return 0; +} +#endif -- cgit v1.2.3