nl80211: Dissect further attributes
Add code to dissect: - Top level nested attributes - Top level nested array attributes - Top level attributes with enum fields - nl80211_band_attr sub attribute - nl80211_bss sub attribute - nl80211_sta_info sub attribute - Attributes containing 802.11 information elements Also update tools/generate-nl80211-fields.py to generate further code blocks. NOTE: This commit will not build alone as it does not contain the generated definitions needed. Depends-On: Ibd8c296c4a3d2f880f359f075271b89625367898 Change-Id: I23b87f41c6230d3fc1eb0f6b050b0d5209a9dd5c Reviewed-on: https://code.wireshark.org/review/29317 Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
b62822055f
commit
5442b51267
|
@ -2,6 +2,7 @@
|
|||
* Dissector for nl80211 (over Netlink).
|
||||
*
|
||||
* Copyright (c) 2017, Peter Wu <peter@lekensteyn.nl>
|
||||
* Copyright (c) 2018, Mikael Kanstrup <mikael.kanstrup@sony.com>
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
|
@ -15,12 +16,15 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <epan/packet.h>
|
||||
#include "packet-ieee80211.h"
|
||||
#include "packet-netlink.h"
|
||||
|
||||
void proto_register_netlink_nl80211(void);
|
||||
void proto_reg_handoff_netlink_nl80211(void);
|
||||
|
||||
/* Extracted using tools/make-nl80211-fields.py */
|
||||
#define NETLINK_NL80211_HFI_INIT HFI_INIT(proto_netlink_generic)
|
||||
|
||||
/* Extracted using tools/generate-nl80211-fields.py */
|
||||
/* Definitions from linux/nl80211.h {{{ */
|
||||
enum ws_nl80211_commands {
|
||||
WS_NL80211_CMD_UNSPEC,
|
||||
|
@ -781,6 +785,17 @@ static const value_string ws_nl80211_attrs_vals[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
static value_string_ext ws_nl80211_attrs_vals_ext = VALUE_STRING_EXT_INIT(ws_nl80211_attrs_vals);
|
||||
|
||||
static header_field_info hfi_nl80211_commands NETLINK_NL80211_HFI_INIT =
|
||||
{ "Command", "nl80211.cmd", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
|
||||
VALS(&ws_nl80211_commands_vals_ext), 0x00, "Generic Netlink Command", HFILL };
|
||||
|
||||
static header_field_info hfi_nl80211_attrs NETLINK_NL80211_HFI_INIT =
|
||||
{ "Attribute Type", "nl80211.attr_type", FT_UINT16, BASE_DEC | BASE_EXT_STRING,
|
||||
VALS(&ws_nl80211_attrs_vals_ext), 0x00, NULL, HFILL };
|
||||
|
||||
static gint ett_nl80211_commands = -1;
|
||||
static gint ett_nl80211_attrs = -1;
|
||||
/* }}} */
|
||||
|
||||
|
||||
|
@ -790,14 +805,7 @@ static dissector_handle_t netlink_nl80211_handle;
|
|||
|
||||
static header_field_info *hfi_netlink_nl80211 = NULL;
|
||||
|
||||
#define NETLINK_NL80211_HFI_INIT HFI_INIT(proto_netlink_generic)
|
||||
|
||||
static gint ett_nl80211 = -1;
|
||||
static gint ett_nl80211_attr = -1;
|
||||
|
||||
static header_field_info hfi_nl80211_attr_type NETLINK_NL80211_HFI_INIT =
|
||||
{ "Attribute Type", "nl80211.attr_type", FT_UINT16, BASE_DEC | BASE_EXT_STRING,
|
||||
VALS(&ws_nl80211_attrs_vals_ext), 0x00, NULL, HFILL };
|
||||
|
||||
static header_field_info hfi_nl80211_attr_value NETLINK_NL80211_HFI_INIT =
|
||||
{ "Attribute Value", "nl80211.attr_value", FT_BYTES, BASE_NONE,
|
||||
|
@ -812,39 +820,330 @@ static header_field_info hfi_nl80211_attr_value32 NETLINK_NL80211_HFI_INIT =
|
|||
NULL, 0x00, NULL, HFILL };
|
||||
|
||||
static int
|
||||
dissect_nl80211_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
dissect_nl80211_generic(tvbuff_t *tvb, void *data, proto_tree *tree, _U_ int nla_type, int offset, int len)
|
||||
{
|
||||
enum ws_nl80211_commands type = (enum ws_nl80211_commands) nla_type;
|
||||
genl_info_t *genl_info = (genl_info_t *)data;
|
||||
|
||||
switch (type) {
|
||||
/* TODO add more fields here? */
|
||||
default:
|
||||
/*
|
||||
* No specific dissection available, apply arbitrary heuristics to
|
||||
* determine whether we have an u16 or u32 field and treat others as
|
||||
* opaque bytes.
|
||||
*/
|
||||
if (len) {
|
||||
if (len == 2) {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value16, tvb, offset, len, genl_info->encoding);
|
||||
} else if (len == 4) {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value32, tvb, offset, len, genl_info->encoding);
|
||||
} else {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value, tvb, offset, len, genl_info->encoding);
|
||||
}
|
||||
offset += len;
|
||||
/*
|
||||
* No specific dissection available, apply arbitrary heuristics to
|
||||
* determine whether we have an u16 or u32 field and treat others as
|
||||
* opaque bytes.
|
||||
*/
|
||||
if (len) {
|
||||
if (len == 2) {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value16, tvb, offset, len, genl_info->encoding);
|
||||
} else if (len == 4) {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value32, tvb, offset, len, genl_info->encoding);
|
||||
} else {
|
||||
proto_tree_add_item(tree, &hfi_nl80211_attr_value, tvb, offset, len, genl_info->encoding);
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
struct attr_lookup {
|
||||
unsigned int attr_type;
|
||||
header_field_info* hfi;
|
||||
gint* ett;
|
||||
int (*func)(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len);
|
||||
};
|
||||
|
||||
static int
|
||||
dissect_nested_attr(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len, const struct attr_lookup *nested)
|
||||
{
|
||||
genl_info_t *genl_info = (genl_info_t *)data;
|
||||
for (int i = 0; nested[i].hfi; i++) {
|
||||
if (nested[i].attr_type != (nla_type & NLA_TYPE_MASK)) {
|
||||
continue;
|
||||
}
|
||||
offset = dissect_netlink_attributes(tvb, nested[i].hfi, *nested[i].ett, genl_info,
|
||||
genl_info->data, tree, offset, len,
|
||||
nested[i].func ? nested[i].func : dissect_nl80211_generic);
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nested_attr_array(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len, const struct attr_lookup *nested_arr)
|
||||
{
|
||||
genl_info_t *genl_info = (genl_info_t *)data;
|
||||
for (int i = 0; nested_arr[i].hfi; i++) {
|
||||
if (nested_arr[i].attr_type != (nla_type & NLA_TYPE_MASK)) {
|
||||
continue;
|
||||
}
|
||||
offset = dissect_netlink_attributes_array(tvb, nested_arr[i].hfi, *nested_arr[i].ett,
|
||||
*nested_arr[i].ett, genl_info,
|
||||
genl_info->data, tree, offset, len,
|
||||
nested_arr[i].func ?
|
||||
nested_arr[i].func : dissect_nl80211_generic);
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_value(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len, const struct attr_lookup *values)
|
||||
{
|
||||
genl_info_t *genl_info = (genl_info_t *)data;
|
||||
for (int i = 0; values[i].hfi; i++) {
|
||||
if (values[i].attr_type != (nla_type & NLA_TYPE_MASK)) {
|
||||
continue;
|
||||
}
|
||||
proto_tree_add_item(tree, values[i].hfi, tvb, offset, len, genl_info->encoding);
|
||||
return offset + len;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static packet_info *m_pinfo = NULL; /* TODO find a better way to pass pinfo to functions */
|
||||
|
||||
static int
|
||||
dissect_information_elements(tvbuff_t *tvb, proto_tree *tree, int offset, int len)
|
||||
{
|
||||
int offset_end = offset + len;
|
||||
while (offset < offset_end) {
|
||||
int tlen = add_tagged_field(m_pinfo, tree, tvb, offset, 0, NULL, 0, NULL);
|
||||
if (tlen == 0) {
|
||||
break;
|
||||
}
|
||||
offset += tlen;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nl80211_frequency_attr(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup nested[] = {
|
||||
{ WS_NL80211_FREQUENCY_ATTR_DFS_STATE, &hfi_nl80211_dfs_state, &ett_nl80211_dfs_state, NULL},
|
||||
{ WS_NL80211_FREQUENCY_ATTR_WMM, &hfi_nl80211_wmm_rule, &ett_nl80211_wmm_rule, NULL},
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
enum ws_nl80211_frequency_attr type = (enum ws_nl80211_frequency_attr) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr(tvb, data, tree, nla_type, offset, len, nested);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nl80211_band_attr(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup nested_arr[] = {
|
||||
{ WS_NL80211_BAND_ATTR_FREQS, &hfi_nl80211_frequency_attr, &ett_nl80211_frequency_attr, dissect_nl80211_frequency_attr },
|
||||
{ WS_NL80211_BAND_ATTR_RATES, &hfi_nl80211_bitrate_attr, &ett_nl80211_bitrate_attr, NULL },
|
||||
{ WS_NL80211_BAND_ATTR_IFTYPE_DATA, &hfi_nl80211_band_iftype_attr, &ett_nl80211_band_iftype_attr, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
enum ws_nl80211_band_attr type = (enum ws_nl80211_band_attr) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr_array(tvb, data, tree, nla_type, offset, len, nested_arr);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
/* TODO add more fields here? */
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nl80211_bss(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup values[] = {
|
||||
{ WS_NL80211_BSS_STATUS, &hfi_nl80211_bss_status, NULL, NULL },
|
||||
{ WS_NL80211_BSS_CHAN_WIDTH, &hfi_nl80211_bss_scan_width, NULL, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
enum ws_nl80211_bss type = (enum ws_nl80211_bss) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_value(tvb, data, tree, nla_type, offset, len, values);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
case WS_NL80211_BSS_INFORMATION_ELEMENTS:
|
||||
case WS_NL80211_BSS_BEACON_IES:
|
||||
offset = dissect_information_elements(tvb, tree, offset, len);
|
||||
break;
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nl80211_tid_stats(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup nested[] = {
|
||||
{ WS_NL80211_TID_STATS_TXQ_STATS, &hfi_nl80211_txq_stats, &ett_nl80211_txq_stats, NULL},
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
enum ws_nl80211_tid_stats type = (enum ws_nl80211_tid_stats) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr(tvb, data, tree, nla_type, offset, len, nested);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_nl80211_sta_info(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup nested[] = {
|
||||
{ WS_NL80211_STA_INFO_TX_BITRATE, &hfi_nl80211_rate_info, &ett_nl80211_rate_info, NULL},
|
||||
{ WS_NL80211_STA_INFO_RX_BITRATE, &hfi_nl80211_rate_info, &ett_nl80211_rate_info, NULL},
|
||||
{ WS_NL80211_STA_INFO_BSS_PARAM, &hfi_nl80211_sta_bss_param, &ett_nl80211_sta_bss_param, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
static const struct attr_lookup nested_arr[] = {
|
||||
{ WS_NL80211_STA_INFO_TID_STATS, &hfi_nl80211_tid_stats, &ett_nl80211_tid_stats, dissect_nl80211_tid_stats},
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
enum ws_nl80211_sta_info type = (enum ws_nl80211_sta_info) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr(tvb, data, tree, nla_type, offset, len, nested);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr_array(tvb, data, tree, nla_type, offset, len, nested_arr);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static header_field_info hfi_nl80211_cmd NETLINK_NL80211_HFI_INIT =
|
||||
{ "Command", "nl80211.cmd", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
|
||||
&ws_nl80211_commands_vals_ext, 0x00, "Generic Netlink command", HFILL };
|
||||
static int
|
||||
dissect_nl80211_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
|
||||
{
|
||||
static const struct attr_lookup nested[] = {
|
||||
{ WS_NL80211_ATTR_SUPPORTED_IFTYPES, &hfi_nl80211_iftype, &ett_nl80211_iftype, NULL },
|
||||
{ WS_NL80211_ATTR_STA_FLAGS, &hfi_nl80211_sta_flags, &ett_nl80211_sta_flags, NULL },
|
||||
{ WS_NL80211_ATTR_STA_INFO, &hfi_nl80211_sta_info, &ett_nl80211_sta_info, dissect_nl80211_sta_info },
|
||||
{ WS_NL80211_ATTR_MPATH_INFO, &hfi_nl80211_mpath_info, &ett_nl80211_mpath_info, NULL },
|
||||
{ WS_NL80211_ATTR_MNTR_FLAGS, &hfi_nl80211_mntr_flags, &ett_nl80211_mntr_flags, NULL },
|
||||
{ WS_NL80211_ATTR_BSS, &hfi_nl80211_bss, &ett_nl80211_bss, dissect_nl80211_bss },
|
||||
{ WS_NL80211_ATTR_KEY, &hfi_nl80211_key_attributes, &ett_nl80211_key_attributes, NULL },
|
||||
{ WS_NL80211_ATTR_SURVEY_INFO, &hfi_nl80211_survey_info, &ett_nl80211_survey_info, NULL },
|
||||
{ WS_NL80211_ATTR_FREQ_BEFORE, &hfi_nl80211_frequency_attr, &ett_nl80211_frequency_attr, NULL },
|
||||
{ WS_NL80211_ATTR_FREQ_AFTER, &hfi_nl80211_frequency_attr, &ett_nl80211_frequency_attr, NULL },
|
||||
{ WS_NL80211_ATTR_TX_RATES, &hfi_nl80211_tx_rate_attributes, &ett_nl80211_tx_rate_attributes, NULL },
|
||||
{ WS_NL80211_ATTR_CQM, &hfi_nl80211_attr_cqm, &ett_nl80211_attr_cqm, NULL },
|
||||
{ WS_NL80211_ATTR_KEY_DEFAULT_TYPES, &hfi_nl80211_key_default_types, &ett_nl80211_key_default_types, NULL },
|
||||
{ WS_NL80211_ATTR_MESH_SETUP, &hfi_nl80211_mesh_setup_params, &ett_nl80211_mesh_setup_params, NULL },
|
||||
{ WS_NL80211_ATTR_MESH_CONFIG, &hfi_nl80211_meshconf_params, &ett_nl80211_meshconf_params, NULL },
|
||||
{ WS_NL80211_ATTR_SCHED_SCAN_MATCH, &hfi_nl80211_sched_scan_match_attr, &ett_nl80211_sched_scan_match_attr, NULL },
|
||||
{ WS_NL80211_ATTR_INTERFACE_COMBINATIONS, &hfi_nl80211_if_combination_attrs, &ett_nl80211_if_combination_attrs, NULL },
|
||||
{ WS_NL80211_ATTR_REKEY_DATA, &hfi_nl80211_rekey_data, &ett_nl80211_rekey_data, NULL },
|
||||
{ WS_NL80211_ATTR_STA_WME, &hfi_nl80211_sta_wme_attr, &ett_nl80211_sta_wme_attr, NULL },
|
||||
{ WS_NL80211_ATTR_PMKSA_CANDIDATE, &hfi_nl80211_pmksa_candidate_attr, &ett_nl80211_pmksa_candidate_attr, NULL },
|
||||
{ WS_NL80211_ATTR_SCHED_SCAN_PLANS, &hfi_nl80211_sched_scan_plan, &ett_nl80211_sched_scan_plan, NULL },
|
||||
{ WS_NL80211_ATTR_BSS_SELECT, &hfi_nl80211_bss_select_attr, &ett_nl80211_bss_select_attr, NULL },
|
||||
{ WS_NL80211_ATTR_IFTYPE_EXT_CAPA, &hfi_nl80211_attrs, &ett_nl80211_attrs, dissect_nl80211_attrs },
|
||||
{ WS_NL80211_ATTR_NAN_FUNC, &hfi_nl80211_nan_func_attributes, &ett_nl80211_nan_func_attributes, NULL },
|
||||
{ WS_NL80211_ATTR_NAN_MATCH, &hfi_nl80211_nan_match_attributes, &ett_nl80211_nan_match_attributes, NULL },
|
||||
{ WS_NL80211_ATTR_TXQ_STATS, &hfi_nl80211_txq_stats, &ett_nl80211_txq_stats, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
static const struct attr_lookup nested_arr[] = {
|
||||
{ WS_NL80211_ATTR_WIPHY_TXQ_PARAMS, &hfi_nl80211_txq_attr, &ett_nl80211_txq_attr, NULL },
|
||||
{ WS_NL80211_ATTR_WIPHY_BANDS, &hfi_nl80211_band_attr, &ett_nl80211_band_attr, dissect_nl80211_band_attr },
|
||||
{ WS_NL80211_ATTR_REG_RULES, &hfi_nl80211_reg_rule_attr, &ett_nl80211_reg_rule_attr, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
static const struct attr_lookup values[] = {
|
||||
{ WS_NL80211_ATTR_CHANNEL_WIDTH, &hfi_nl80211_chan_width, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_WIPHY_CHANNEL_TYPE, &hfi_nl80211_channel_type, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_IFTYPE, &hfi_nl80211_iftype, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_STA_PLINK_ACTION, &hfi_plink_actions, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_MPATH_INFO, &hfi_nl80211_mpath_info, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_REG_INITIATOR, &hfi_nl80211_reg_initiator, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_REG_TYPE, &hfi_nl80211_reg_type, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_AUTH_TYPE, &hfi_nl80211_auth_type, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_KEY_TYPE, &hfi_nl80211_key_type, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_USE_MFP, &hfi_nl80211_mfp, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_PS_STATE, &hfi_nl80211_ps_state, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_WIPHY_TX_POWER_SETTING, &hfi_nl80211_tx_power_setting, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_STA_PLINK_STATE, &hfi_nl80211_plink_state, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_TDLS_OPERATION, &hfi_nl80211_tdls_operation, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_DFS_REGION, &hfi_nl80211_dfs_regions, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_USER_REG_HINT_TYPE, &hfi_nl80211_user_reg_hint_type, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_CONN_FAILED_REASON, &hfi_nl80211_connect_failed_reason, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_LOCAL_MESH_POWER_MODE, &hfi_nl80211_mesh_power_mode, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_ACL_POLICY, &hfi_nl80211_acl_policy, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_RADAR_EVENT, &hfi_nl80211_radar_event, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_CRIT_PROT_ID, &hfi_nl80211_crit_proto_id, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_SMPS_MODE, &hfi_nl80211_smps_mode, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_STA_SUPPORT_P2P_PS, &hfi_nl80211_sta_p2p_ps_status, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_TIMEOUT_REASON, &hfi_nl80211_timeout_reason, NULL, NULL },
|
||||
{ WS_NL80211_ATTR_EXTERNAL_AUTH_ACTION, &hfi_nl80211_external_auth_action, NULL, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
enum ws_nl80211_attrs type = (enum ws_nl80211_attrs) nla_type & NLA_TYPE_MASK;
|
||||
int offset_end = offset + len;
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr(tvb, data, tree, nla_type, offset, len, nested);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_nested_attr_array(tvb, data, tree, nla_type, offset, len, nested_arr);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
offset = dissect_value(tvb, data, tree, nla_type, offset, len, values);
|
||||
}
|
||||
if (offset < offset_end) {
|
||||
switch (type) {
|
||||
case WS_NL80211_ATTR_HT_CAPABILITY:
|
||||
case WS_NL80211_ATTR_IE:
|
||||
case WS_NL80211_ATTR_REQ_IE:
|
||||
case WS_NL80211_ATTR_RESP_IE:
|
||||
case WS_NL80211_ATTR_IE_PROBE_RESP:
|
||||
case WS_NL80211_ATTR_IE_ASSOC_RESP:
|
||||
case WS_NL80211_ATTR_VHT_CAPABILITY:
|
||||
case WS_NL80211_ATTR_CSA_IES:
|
||||
case WS_NL80211_ATTR_HE_CAPABILITY:
|
||||
offset = dissect_information_elements(tvb, tree, offset, len);
|
||||
break;
|
||||
/* TODO add more fields here? */
|
||||
default:
|
||||
offset = dissect_nl80211_generic(tvb, data, tree, nla_type, offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_netlink_nl80211(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
|
@ -858,13 +1157,14 @@ dissect_netlink_nl80211(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
|
|||
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "nl80211");
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
m_pinfo = pinfo;
|
||||
|
||||
offset = dissect_genl_header(tvb, genl_info, &hfi_nl80211_cmd);
|
||||
offset = dissect_genl_header(tvb, genl_info, &hfi_nl80211_commands);
|
||||
|
||||
pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_nl80211), tvb, offset, -1, ENC_NA);
|
||||
nlmsg_tree = proto_item_add_subtree(pi, ett_nl80211);
|
||||
|
||||
offset = dissect_netlink_attributes(tvb, &hfi_nl80211_attr_type, ett_nl80211_attr, genl_info, genl_info->data, nlmsg_tree, offset, -1, dissect_nl80211_attrs);
|
||||
offset = dissect_netlink_attributes(tvb, &hfi_nl80211_attrs, ett_nl80211_attrs, genl_info, genl_info->data, nlmsg_tree, offset, -1, dissect_nl80211_attrs);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
@ -874,17 +1174,24 @@ proto_register_netlink_nl80211(void)
|
|||
{
|
||||
#ifndef HAVE_HFI_SECTION_INIT
|
||||
static header_field_info *hfi[] = {
|
||||
&hfi_nl80211_cmd,
|
||||
&hfi_nl80211_attr_type,
|
||||
&hfi_nl80211_attr_value,
|
||||
&hfi_nl80211_attr_value16,
|
||||
&hfi_nl80211_attr_value32,
|
||||
/* Extracted using tools/generate-nl80211-fields.py */
|
||||
/* Definitions from linux/nl80211.h {{{ */
|
||||
&hfi_nl80211_commands,
|
||||
&hfi_nl80211_attrs,
|
||||
/* }}} */
|
||||
};
|
||||
#endif
|
||||
|
||||
static gint *ett[] = {
|
||||
&ett_nl80211,
|
||||
&ett_nl80211_attr,
|
||||
/* Extracted using tools/generate-nl80211-fields.py */
|
||||
/* Definitions from linux/nl80211.h {{{ */
|
||||
&ett_nl80211_commands,
|
||||
&ett_nl80211_attrs,
|
||||
/* }}} */
|
||||
};
|
||||
|
||||
proto_netlink_nl80211 = proto_register_protocol("Linux 802.11 Netlink", "nl80211", "nl80211");
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# (value_string) for packet-netlink-nl80211.c
|
||||
#
|
||||
# Copyright (c) 2017, Peter Wu <peter@lekensteyn.nl>
|
||||
# Copyright (c) 2018, Mikael Kanstrup <mikael.kanstrup@sony.com>
|
||||
#
|
||||
# Wireshark - Network traffic analyzer
|
||||
# By Gerald Combs <gerald@wireshark.org>
|
||||
|
@ -25,20 +26,90 @@ import sys
|
|||
HEADER = "/* Definitions from linux/nl80211.h {{{ */\n"
|
||||
FOOTER = "/* }}} */\n"
|
||||
# Enums to extract from the header file
|
||||
EXPORT_ENUMS = ("nl80211_commands", "nl80211_attrs")
|
||||
EXPORT_ENUMS = {
|
||||
# 'enum_name': ('field_name', field_type', 'field_blurb')
|
||||
'nl80211_commands': ('Command', 'FT_UINT8', '"Generic Netlink Command"'),
|
||||
'nl80211_attrs': (None, None, None),
|
||||
'nl80211_iftype': (None, None, None),
|
||||
'nl80211_sta_flags': (None, None, None),
|
||||
'nl80211_rate_info': (None, None, None),
|
||||
'nl80211_sta_bss_param': (None, None, None),
|
||||
'nl80211_sta_info': (None, None, None),
|
||||
'nl80211_tid_stats': (None, None, None),
|
||||
'nl80211_mpath_info': (None, None, None),
|
||||
'nl80211_mntr_flags': (None, None, None),
|
||||
'nl80211_bss': (None, None, None),
|
||||
'nl80211_key_attributes': (None, None, None),
|
||||
'nl80211_survey_info': (None, None, None),
|
||||
'nl80211_frequency_attr': (None, None, None),
|
||||
'nl80211_tx_rate_attributes': (None, None, None),
|
||||
'nl80211_attr_cqm': (None, None, None),
|
||||
'nl80211_key_default_types': (None, None, None),
|
||||
'nl80211_mesh_setup_params': (None, None, None),
|
||||
'nl80211_meshconf_params': (None, None, None),
|
||||
'nl80211_if_combination_attrs': (None, None, None),
|
||||
'nl80211_rekey_data': (None, None, None),
|
||||
'nl80211_sta_wme_attr': (None, None, None),
|
||||
'nl80211_pmksa_candidate_attr': (None, None, None),
|
||||
'nl80211_sched_scan_plan': (None, None, None),
|
||||
'nl80211_bss_select_attr': (None, None, None),
|
||||
'nl80211_nan_func_attributes': (None, None, None),
|
||||
'nl80211_nan_match_attributes': (None, None, None),
|
||||
'nl80211_txq_stats': (None, None, None),
|
||||
'nl80211_band_attr': (None, None, None),
|
||||
'nl80211_bitrate_attr': (None, None, None),
|
||||
'nl80211_reg_rule_attr': (None, None, None),
|
||||
'nl80211_txq_attr': (None, None, None),
|
||||
'nl80211_band_iftype_attr': (None, None, None),
|
||||
'nl80211_dfs_state': (None, None, None),
|
||||
'nl80211_wmm_rule': (None, None, None),
|
||||
'nl80211_txq_stats': (None, None, None),
|
||||
'nl80211_sched_scan_match_attr': (None, None, None),
|
||||
'nl80211_chan_width': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_channel_type': ('Attribute Value', 'FT_UINT32', None),
|
||||
'plink_actions': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_reg_initiator': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_reg_type': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_auth_type': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_key_type': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_bss_status': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_bss_scan_width': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_mfp': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_ps_state': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_tx_power_setting': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_plink_state': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_tdls_operation': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_user_reg_hint_type': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_connect_failed_reason': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_mesh_power_mode': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_acl_policy': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_radar_event': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_crit_proto_id': ('Attribute Value', 'FT_UINT16', None),
|
||||
'nl80211_smps_mode': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_sta_p2p_ps_status': ('Attribute Value', 'FT_UINT8', None),
|
||||
'nl80211_timeout_reason': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_external_auth_action': ('Attribute Value', 'FT_UINT32', None),
|
||||
'nl80211_dfs_regions': ('Attribute Value', 'FT_UINT8', None),
|
||||
}
|
||||
# File to be patched
|
||||
SOURCE_FILE = "epan/dissectors/packet-netlink-nl80211.c"
|
||||
# URL where the latest version can be found
|
||||
URL = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/nl80211.h"
|
||||
|
||||
def make_enum(name, values, indent):
|
||||
def make_enum(name, values, expressions, indent):
|
||||
code = 'enum ws_%s {\n' % name
|
||||
for value in values:
|
||||
code += '%sWS_%s,\n' % (indent, value)
|
||||
for value, expression in zip(values, expressions):
|
||||
if expression and 'NL80211' in expression:
|
||||
expression = 'WS_%s' % expression
|
||||
if expression:
|
||||
code += '%sWS_%s = %s,\n' % (indent, value, expression)
|
||||
else:
|
||||
code += '%sWS_%s,\n' % (indent, value)
|
||||
|
||||
code += '};\n'
|
||||
return code
|
||||
|
||||
def make_value_string(name, values, indent):
|
||||
def make_value_string(name, values, indent,):
|
||||
code = 'static const value_string ws_%s_vals[] = {\n' % name
|
||||
align = 40
|
||||
for value in values:
|
||||
|
@ -50,56 +121,94 @@ def make_value_string(name, values, indent):
|
|||
code += ' VALUE_STRING_EXT_INIT(ws_%s_vals);\n' % name
|
||||
return code
|
||||
|
||||
def make_hfi(name, indent):
|
||||
(field_name, field_type, field_blurb) = EXPORT_ENUMS.get(name)
|
||||
field_abbrev = name
|
||||
|
||||
# Fill in default values
|
||||
if not field_name:
|
||||
field_name = 'Attribute Type'
|
||||
if not field_type:
|
||||
field_type = 'FT_UINT16'
|
||||
if not field_blurb:
|
||||
field_blurb = 'NULL'
|
||||
|
||||
# Special treatment of already existing field names
|
||||
rename_fields = {
|
||||
'nl80211_attrs': 'nl80211_attr_type',
|
||||
'nl80211_commands': 'nl80211_cmd'
|
||||
}
|
||||
if rename_fields.get(name):
|
||||
field_abbrev = rename_fields[name]
|
||||
field_abbrev = field_abbrev.lstrip('nl80211_')
|
||||
|
||||
code = 'static header_field_info hfi_%s NETLINK_NL80211_HFI_INIT =\n' % name
|
||||
code += indent + '{ "%s", "nl80211.%s", %s, BASE_DEC | BASE_EXT_STRING,\n' % \
|
||||
(field_name, field_abbrev, field_type)
|
||||
code += indent + ' VALS(&ws_%s_vals_ext), 0x00, %s, HFILL };\n' % (name, field_blurb)
|
||||
return code
|
||||
|
||||
def make_ett_defs(name, indent):
|
||||
code = 'static gint ett_%s = -1;' % name
|
||||
return code
|
||||
|
||||
def make_hfi_init(name, indent):
|
||||
code = indent + indent + '&hfi_%s,' % name
|
||||
return code
|
||||
|
||||
def make_ett(name, indent):
|
||||
code = indent + indent + '&ett_%s,' % name
|
||||
return code
|
||||
|
||||
class EnumStore(object):
|
||||
def __init__(self, name):
|
||||
__RE_ENUM_VALUE = re.compile(
|
||||
r'\s+?(?P<value>\w+)(?:\ /\*.*?\*\/)?(?:\s*=\s*(?P<expression>.*?))?(?:\s*,|$)',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
|
||||
def __init__(self, name, values):
|
||||
self.name = name
|
||||
self.values = []
|
||||
self.expressions = []
|
||||
self.active = True
|
||||
self.parse_values(values)
|
||||
|
||||
def update(self, line):
|
||||
if not self.active:
|
||||
return
|
||||
|
||||
# Skip comments and remove trailing comma
|
||||
line = re.sub(r'\s*/\*.*?\*/\s*', '', line).rstrip(",")
|
||||
if not line:
|
||||
return
|
||||
|
||||
# Try to match a name. Allow aliases only for the previous item.
|
||||
m = re.match(r'^(?P<name>\w+)(?: *= *(?P<alias_of>\w+))?$', line)
|
||||
assert m, "Failed to find match in %r" % line
|
||||
name, alias_of = m.groups()
|
||||
if alias_of:
|
||||
# Alias must match previous item, skip it otherwise.
|
||||
assert alias_of == self.values[-1]
|
||||
elif name.startswith("__"):
|
||||
# Skip after hitting "__NL80211_CMD_AFTER_LAST"
|
||||
self.active = False
|
||||
else:
|
||||
self.values.append(name)
|
||||
def parse_values(self, values):
|
||||
for m in self.__RE_ENUM_VALUE.finditer(values):
|
||||
value, expression = m.groups()
|
||||
if value.startswith('NUM_'):
|
||||
break
|
||||
if value.endswith('_AFTER_LAST'):
|
||||
break
|
||||
if value.endswith('_LAST'):
|
||||
break
|
||||
if value.startswith('__') and value.endswith('_NUM'):
|
||||
break
|
||||
if expression and expression in self.values:
|
||||
# Skip aliases
|
||||
continue
|
||||
self.values.append(value)
|
||||
self.expressions.append(expression)
|
||||
|
||||
def finish(self):
|
||||
assert not self.active
|
||||
assert self.values
|
||||
return self.name, self.values
|
||||
return self.name, self.values, self.expressions
|
||||
|
||||
RE_ENUM = re.compile(
|
||||
r'enum\s+?(?P<enum>\w+)\s+?\{(?P<values>.*?)\}\;',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
RE_COMMENT = re.compile(r'/\*.*?\*/', re.MULTILINE | re.DOTALL)
|
||||
|
||||
def parse_header(content):
|
||||
# Strip comments
|
||||
content = re.sub(RE_COMMENT, '', content)
|
||||
|
||||
def parse_header(f):
|
||||
enum_store = None
|
||||
enums = []
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("enum "):
|
||||
assert not enum_store
|
||||
enum_keyword, enum_name, trailer = line.split()
|
||||
assert trailer == "{"
|
||||
if enum_name in EXPORT_ENUMS:
|
||||
enum_store = EnumStore(enum_name)
|
||||
elif enum_store:
|
||||
if line == "};":
|
||||
enums.append(enum_store.finish())
|
||||
enum_store = None
|
||||
elif line:
|
||||
enum_store.update(line)
|
||||
for m in RE_ENUM.finditer(content):
|
||||
enum = m.group('enum')
|
||||
values = m.group('values')
|
||||
if enum in EXPORT_ENUMS:
|
||||
enums.append(EnumStore(enum, values).finish())
|
||||
|
||||
return enums
|
||||
|
||||
def parse_source():
|
||||
|
@ -108,6 +217,7 @@ def parse_source():
|
|||
after the block.
|
||||
"""
|
||||
begin, block, end = '', '', ''
|
||||
parts = []
|
||||
# Stages: 1 (before block), 2 (in block, skip), 3 (after block)
|
||||
stage = 1
|
||||
with open(SOURCE_FILE) as f:
|
||||
|
@ -116,15 +226,21 @@ def parse_source():
|
|||
stage = 3 # End of block
|
||||
if stage == 1:
|
||||
begin += line
|
||||
if line == HEADER:
|
||||
stage = 2 # Begin of block
|
||||
elif stage == 2:
|
||||
block += line
|
||||
elif stage == 3:
|
||||
end += line
|
||||
if stage != 3:
|
||||
raise RuntimeError("Could not parse file (in stage %d)" % stage)
|
||||
return begin, block, end
|
||||
if line == HEADER and stage == 1:
|
||||
stage = 2 # Begin of block
|
||||
if line == HEADER and stage == 3:
|
||||
stage = 2 # Begin of next code block
|
||||
parts.append((begin, block, end))
|
||||
begin, block, end = '', '', ''
|
||||
|
||||
parts.append((begin, block, end))
|
||||
if stage != 3 or len(parts) != 3:
|
||||
raise RuntimeError("Could not parse file (in stage %d) (parts %d)" % (stage, len(parts)))
|
||||
return parts
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--update", action="store_true",
|
||||
|
@ -143,37 +259,53 @@ def main():
|
|||
if any(args.header_file.startswith(proto) for proto in ('http:', 'https')):
|
||||
r = requests.get(args.header_file)
|
||||
r.raise_for_status()
|
||||
enums = parse_header(r.text.splitlines())
|
||||
enums = parse_header(r.text)
|
||||
elif args.header_file == "-":
|
||||
enums = parse_header(sys.stdin)
|
||||
enums = parse_header(sys.stdin.read())
|
||||
else:
|
||||
with open(args.header_file) as f:
|
||||
enums = parse_header(f)
|
||||
enums = parse_header(f.read())
|
||||
|
||||
assert len(enums) == len(EXPORT_ENUMS), \
|
||||
"Could not parse data, found %d/%d results" % \
|
||||
(len(enums), len(EXPORT_ENUMS))
|
||||
|
||||
code_enums, code_vals = '', ''
|
||||
for enum_name, enum_values in enums:
|
||||
code_enums += make_enum(enum_name, enum_values, indent) + '\n'
|
||||
code_enums, code_vals, code_hfi, code_ett_defs, code_hfi_init, code_ett = '', '', '', '', '', ''
|
||||
for enum_name, enum_values, expressions in enums:
|
||||
code_enums += make_enum(enum_name, enum_values, expressions, indent) + '\n'
|
||||
code_vals += make_value_string(enum_name, enum_values, indent) + '\n'
|
||||
code_hfi += make_hfi(enum_name, indent) + '\n'
|
||||
code_ett_defs += make_ett_defs(enum_name, indent) + '\n'
|
||||
code_hfi_init += make_hfi_init(enum_name, indent) + '\n'
|
||||
code_ett += make_ett(enum_name, indent) + '\n'
|
||||
|
||||
code = code_enums + code_vals
|
||||
code = code.rstrip("\n") + "\n"
|
||||
code_top = code_enums + code_vals + code_hfi + code_ett_defs
|
||||
code_top = code_top.rstrip("\n") + "\n"
|
||||
|
||||
code = [code_top, code_hfi_init, code_ett]
|
||||
|
||||
update = False
|
||||
if args.update:
|
||||
begin, block, end = parse_source()
|
||||
if block == code:
|
||||
parts = parse_source()
|
||||
|
||||
# Check if file needs update
|
||||
for (begin, old_code, end), new_code in zip(parts, code):
|
||||
if old_code != new_code:
|
||||
update = True
|
||||
break
|
||||
if not update:
|
||||
print("File is up-to-date")
|
||||
else:
|
||||
with open(SOURCE_FILE, "w") as f:
|
||||
return
|
||||
# Update file
|
||||
with open(SOURCE_FILE, "w") as f:
|
||||
for (begin, old_code, end), new_code in zip(parts, code):
|
||||
f.write(begin)
|
||||
f.write(code)
|
||||
f.write(new_code)
|
||||
f.write(end)
|
||||
print("Updated %s" % SOURCE_FILE)
|
||||
print("Updated %s" % SOURCE_FILE)
|
||||
else:
|
||||
print(code)
|
||||
for new_code in code:
|
||||
print(new_code)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
Loading…
Reference in New Issue