diff options
author | Michael Mann <mmann78@netscape.net> | 2013-05-02 01:59:34 +0000 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2013-05-02 01:59:34 +0000 |
commit | 5b416c847974dcaec090420a427114e2cdb4f526 (patch) | |
tree | a2b70097521bcaca391f4f9d1181fa6444311af9 /epan/dissectors/packet-ieee80211.c | |
parent | f1d06a226bd524983b6a8de8136ede809e66bdec (diff) |
IEEE802.11 improvements:
1. ANQP Venue Name is a UTF-8 string
2. Dissect Hotspot 2.0 indication and ANQP elements
3. Dissect TFS Request/Response
4. Dissect WNM-Notification Request frames
svn path=/trunk/; revision=49131
Diffstat (limited to 'epan/dissectors/packet-ieee80211.c')
-rw-r--r-- | epan/dissectors/packet-ieee80211.c | 734 |
1 files changed, 724 insertions, 10 deletions
diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c index 798119d293..e0a50ba048 100644 --- a/epan/dissectors/packet-ieee80211.c +++ b/epan/dissectors/packet-ieee80211.c @@ -527,6 +527,7 @@ enum fixed_field { FIELD_SELFPROT_ACTION, FIELD_WNM_ACTION_CODE, FIELD_KEY_DATA_LENGTH, + FIELD_WNM_NOTIFICATION_TYPE, /* add any new fixed field value above this line */ MAX_FIELD_NUM }; @@ -804,6 +805,15 @@ static value_string_ext tag_num_vals_ext = VALUE_STRING_EXT_INIT(tag_num_vals); /* WFA vendor specific subtypes */ #define WFA_SUBTYPE_P2P 9 +#define WFA_SUBTYPE_HS20_INDICATION 16 +#define WFA_SUBTYPE_HS20_ANQP 17 + +static const value_string wfa_subtype_vals[] = { + { WFA_SUBTYPE_P2P, "P2P" }, + { WFA_SUBTYPE_HS20_INDICATION, "Hotspot 2.0 Indication" }, + { WFA_SUBTYPE_HS20_ANQP, "Hotspot 2.0 ANQP" }, + { 0, NULL } +}; /* ************************************************************************* */ /* Supported Rates (7.3.2.2) */ @@ -1368,6 +1378,17 @@ static const value_string wnm_action_codes[] = { }; static value_string_ext wnm_action_codes_ext = VALUE_STRING_EXT_INIT(wnm_action_codes); + +static const value_string wnm_notification_types[] = { + { 0, "Firmware Update Notification" }, + { 1, "Reserved for use by WFA" }, + { 221, "Vendor Specific" }, + { 0, NULL } +}; + +static value_string_ext wnm_notification_types_ext = + VALUE_STRING_EXT_INIT(wnm_notification_types); + /*** End: Action Fixed Parameter ***/ static const value_string ieee80211_tag_measure_request_type_flags[] = { @@ -2760,6 +2781,7 @@ static int hf_ieee80211_ff_regulatory_class = -1; static int hf_ieee80211_ff_wnm_action_code = -1; static int hf_ieee80211_ff_key_data_length = -1; static int hf_ieee80211_ff_key_data = -1; +static int hf_ieee80211_ff_wnm_notification_type = -1; static int hf_ieee80211_ff_request_mode_pref_cand = -1; static int hf_ieee80211_ff_request_mode_abridged = -1; static int hf_ieee80211_ff_request_mode_disassoc_imminent = -1; @@ -3644,6 +3666,21 @@ static int hf_ieee80211_tag_time_adv_time_update_counter = -1; static int hf_ieee80211_tag_bss_max_idle_period = -1; static int hf_ieee80211_tag_bss_max_idle_options_protected = -1; +/* IEEE Std 802.11-2012 8.4.2.82 */ +static int hf_ieee80211_tag_tfs_request_id = -1; +static int hf_ieee80211_tag_tfs_request_ac_delete_after_match = -1; +static int hf_ieee80211_tag_tfs_request_ac_notify = -1; +static int hf_ieee80211_tag_tfs_request_subelem_id = -1; +static int hf_ieee80211_tag_tfs_request_subelem_len = -1; +static int hf_ieee80211_tag_tfs_request_subelem = -1; + +/* IEEE Std 802.11-2012 8.4.2.83 */ +static int hf_ieee80211_tag_tfs_response_subelem_id = -1; +static int hf_ieee80211_tag_tfs_response_subelem_len = -1; +static int hf_ieee80211_tag_tfs_response_subelem = -1; +static int hf_ieee80211_tag_tfs_response_status = -1; +static int hf_ieee80211_tag_tfs_response_id = -1; + /* IEEE Std 802.11-2012 8.4.2.84 */ static int hf_ieee80211_tag_wnm_sleep_mode_action_type = -1; static int hf_ieee80211_tag_wnm_sleep_mode_response_status = -1; @@ -3984,6 +4021,37 @@ static int hf_ieee80211_tag_timeout_int_value = -1; /* Ethertype 89-0d */ static int hf_ieee80211_data_encap_payload_type = -1; +static int hf_ieee80211_anqp_wfa_subtype = -1; + +/* Hotspot 2.0 */ +static int hf_hs20_indication_dgaf_disabled = -1; + +static int hf_hs20_anqp_subtype = -1; +static int hf_hs20_anqp_reserved = -1; +static int hf_hs20_anqp_payload = -1; +static int hf_hs20_anqp_hs_query_list = -1; +static int hf_hs20_anqp_hs_capability_list = -1; +static int hf_hs20_anqp_ofn_length = -1; +static int hf_hs20_anqp_ofn_language = -1; +static int hf_hs20_anqp_ofn_name = -1; +static int hf_hs20_anqp_wan_metrics_link_status = -1; +static int hf_hs20_anqp_wan_metrics_symmetric_link = -1; +static int hf_hs20_anqp_wan_metrics_at_capacity = -1; +static int hf_hs20_anqp_wan_metrics_reserved = -1; +static int hf_hs20_anqp_wan_metrics_downlink_speed = -1; +static int hf_hs20_anqp_wan_metrics_uplink_speed = -1; +static int hf_hs20_anqp_wan_metrics_downlink_load = -1; +static int hf_hs20_anqp_wan_metrics_uplink_load = -1; +static int hf_hs20_anqp_wan_metrics_lmd = -1; +static int hf_hs20_anqp_cc_proto_ip_proto = -1; +static int hf_hs20_anqp_cc_proto_port_num = -1; +static int hf_hs20_anqp_cc_proto_status = -1; +static int hf_hs20_anqp_nai_hrq_count = -1; +static int hf_hs20_anqp_nai_hrq_encoding_type = -1; +static int hf_hs20_anqp_nai_hrq_length = -1; +static int hf_hs20_anqp_nai_hrq_realm_name = -1; +static int hf_hs20_anqp_oper_class_indic = -1; + /* ************************************************************************* */ /* Protocol trees */ /* ************************************************************************* */ @@ -4126,6 +4194,8 @@ static gint ett_nai_realm_eap = -1; static gint ett_tag_ric_data_desc_ie = -1; static gint ett_anqp_vendor_capab = -1; +static gint ett_hs20_cc_proto_port_tuple = -1; + static const fragment_items frag_items = { &ett_fragment, &ett_fragments, @@ -4930,6 +5000,17 @@ dissect_anqp_query_list(proto_tree *tree, tvbuff_t *tvb, int offset, int end) } } +static void dissect_hs20_anqp_hs_capability_list(proto_tree *tree, + tvbuff_t *tvb, + int offset, int end) +{ + while (offset < end) { + proto_tree_add_item(tree, hf_hs20_anqp_hs_capability_list, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + } +} + static void dissect_anqp_capab_list(proto_tree *tree, tvbuff_t *tvb, int offset, int end) { @@ -4937,6 +5018,7 @@ dissect_anqp_capab_list(proto_tree *tree, tvbuff_t *tvb, int offset, int end) proto_item *item; proto_tree *vtree; guint32 oui; + guint8 subtype; while (offset + 2 <= end) { id = tvb_get_letohs(tvb, offset); @@ -4960,6 +5042,27 @@ dissect_anqp_capab_list(proto_tree *tree, tvbuff_t *tvb, int offset, int end) len -= 3; switch (oui) { + case OUI_WFA: + if (len == 0) + break; + subtype = tvb_get_guint8(tvb, offset); + proto_item_append_text(vtree, " - WFA - %s", + val_to_str(subtype, wfa_subtype_vals, + "Unknown (%u)")); + proto_tree_add_item(vtree, hf_ieee80211_anqp_wfa_subtype, + tvb, offset, 1, ENC_NA); + offset++; + len--; + switch (subtype) { + case WFA_SUBTYPE_HS20_ANQP: + dissect_hs20_anqp_hs_capability_list(vtree, tvb, offset, end); + break; + default: + proto_tree_add_item(vtree, hf_ieee80211_ff_anqp_capability_vendor, + tvb, offset, len, ENC_BIG_ENDIAN); + break; + } + break; default: proto_tree_add_item(vtree, hf_ieee80211_ff_anqp_capability_vendor, tvb, offset, len, ENC_NA); @@ -5021,7 +5124,7 @@ dissect_venue_name_info(proto_tree *tree, tvbuff_t *tvb, int offset, int end) proto_tree_add_item(tree, hf_ieee80211_ff_anqp_venue_language, tvb, offset, 3, ENC_ASCII|ENC_NA); proto_tree_add_item(tree, hf_ieee80211_ff_anqp_venue_name, - tvb, offset + 3, vlen - 3, ENC_ASCII|ENC_NA); + tvb, offset + 3, vlen - 3, ENC_UTF_8|ENC_NA); offset += vlen; } } @@ -5312,13 +5415,241 @@ dissect_domain_name_list(proto_tree *tree, tvbuff_t *tvb, int offset, int end) } } +#define HS20_ANQP_HS_QUERY_LIST 1 +#define HS20_ANQP_HS_CAPABILITY_LIST 2 +#define HS20_ANQP_OPERATOR_FRIENDLY_NAME 3 +#define HS20_ANQP_WAN_METRICS 4 +#define HS20_ANQP_CONNECTION_CAPABILITY 5 +#define HS20_ANQP_NAI_HOME_REALM_QUERY 6 +#define HS20_ANQP_OPERATING_CLASS_INDICATION 7 + +static const value_string hs20_anqp_subtype_vals[] = { + { HS20_ANQP_HS_QUERY_LIST, "HS Query list" }, + { HS20_ANQP_HS_CAPABILITY_LIST, "HS Capability List" }, + { HS20_ANQP_OPERATOR_FRIENDLY_NAME, "Operator Friendly Name" }, + { HS20_ANQP_WAN_METRICS, "WAN Metrics" }, + { HS20_ANQP_CONNECTION_CAPABILITY, "Connection Capability" }, + { HS20_ANQP_NAI_HOME_REALM_QUERY, "NAI Home Realm Query" }, + { HS20_ANQP_OPERATING_CLASS_INDICATION, "Operating Class Indication" }, + { 0, NULL } +}; + +static void dissect_hs20_anqp_hs_query_list(proto_tree *tree, tvbuff_t *tvb, + int offset, int end) +{ + while (offset < end) { + proto_tree_add_item(tree, hf_hs20_anqp_hs_query_list, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + } +} + +static void dissect_hs20_anqp_operator_friendly_name(proto_tree *tree, + tvbuff_t *tvb, + int offset, int end) +{ + while (offset + 4 <= end) { + guint8 vlen = tvb_get_guint8(tvb, offset); + proto_item *item = proto_tree_add_item(tree, hf_hs20_anqp_ofn_length, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + if (vlen > end - offset || vlen < 3) { + expert_add_info_format(g_pinfo, item, PI_MALFORMED, PI_ERROR, + "Invalid Operator Friendly Name Duple length"); + break; + } + proto_tree_add_item(tree, hf_hs20_anqp_ofn_language, + tvb, offset, 3, ENC_ASCII|ENC_NA); + proto_tree_add_item(tree, hf_hs20_anqp_ofn_name, + tvb, offset + 3, vlen - 3, ENC_UTF_8|ENC_NA); + offset += vlen; + } +} + +static const value_string hs20_wm_link_status_vals[] = { + { 0, "Reserved" }, + { 1, "Link up" }, + { 2, "Link down" }, + { 3, "Link in test state" }, + { 0, NULL } +}; + +static void dissect_hs20_anqp_wan_metrics(proto_tree *tree, tvbuff_t *tvb, + int offset, gboolean request) +{ + if (request) + return; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_link_status, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_symmetric_link, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_at_capacity, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_reserved, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_downlink_speed, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_uplink_speed, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_downlink_load, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_uplink_load, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + proto_tree_add_item(tree, hf_hs20_anqp_wan_metrics_lmd, + tvb, offset, 2, ENC_LITTLE_ENDIAN); +} + +static const value_string hs20_cc_status_vals[] = { + { 0, "Closed" }, + { 1, "Open" }, + { 2, "Unknown" }, + { 0, NULL } +}; + +static void +dissect_hs20_anqp_connection_capability(proto_tree *tree, tvbuff_t *tvb, + int offset, int end) +{ + proto_item *item; + proto_tree *tuple; + while (offset + 4 <= end) { + guint8 ip_proto, status; + guint16 port_num; + + ip_proto = tvb_get_guint8(tvb, offset); + port_num = tvb_get_letohs(tvb, offset + 1); + status = tvb_get_guint8(tvb, offset + 3); + + item = proto_tree_add_text(tree, tvb, offset, 4, "ProtoPort Tuple - " + "ip_proto=%u port_num=%u status=%s", + ip_proto, port_num, + val_to_str(status, hs20_cc_status_vals, + "Unknown (%u)")); + tuple = proto_item_add_subtree(item, ett_hs20_cc_proto_port_tuple); + proto_tree_add_item(tuple, hf_hs20_anqp_cc_proto_ip_proto, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + proto_tree_add_item(tuple, hf_hs20_anqp_cc_proto_port_num, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(tuple, hf_hs20_anqp_cc_proto_status, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + } +} + +static void +dissect_hs20_anqp_nai_home_realm_query(proto_tree *tree, tvbuff_t *tvb, + int offset, int end) +{ + guint8 len; + proto_item *item; + + proto_tree_add_item(tree, hf_hs20_anqp_nai_hrq_count, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + + while (offset + 2 <= end) { + proto_tree_add_item(tree, hf_hs20_anqp_nai_hrq_encoding_type, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + len = tvb_get_guint8(tvb, offset); + item = proto_tree_add_item(tree, hf_hs20_anqp_nai_hrq_length, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + if (offset + len > end) { + expert_add_info_format(g_pinfo, item, PI_MALFORMED, PI_ERROR, + "Invalid NAI Home Realm Query length"); + break; + } + proto_tree_add_item(tree, hf_hs20_anqp_nai_hrq_realm_name, + tvb, offset, len, ENC_ASCII|ENC_NA); + offset += len; + } +} + +static void dissect_hs20_anqp_oper_class_indic(proto_tree *tree, tvbuff_t *tvb, + int offset, int end) +{ + while (offset < end) { + proto_tree_add_item(tree, hf_hs20_anqp_oper_class_indic, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + } +} + +static void dissect_hs20_anqp(proto_tree *tree, tvbuff_t *tvb, int offset, + int end, gboolean request, int idx) +{ + guint8 subtype; + + subtype = tvb_get_guint8(tvb, offset); + proto_item_append_text(tree, " - HS 2.0 %s", + val_to_str(subtype, hs20_anqp_subtype_vals, + "Unknown (%u)")); + if (idx == 0) { + col_append_fstr(g_pinfo->cinfo, COL_INFO, " HS 2.0 %s", + val_to_str(subtype, hs20_anqp_subtype_vals, + "Unknown (%u)")); + } else if (idx == 1) { + col_append_fstr(g_pinfo->cinfo, COL_INFO, ", .."); + } + proto_tree_add_item(tree, hf_hs20_anqp_subtype, tvb, offset, 1, + ENC_LITTLE_ENDIAN); + offset++; + + proto_tree_add_item(tree, hf_hs20_anqp_reserved, tvb, offset, 1, + ENC_LITTLE_ENDIAN); + offset++; + + switch (subtype) { + case HS20_ANQP_HS_QUERY_LIST: + dissect_hs20_anqp_hs_query_list(tree, tvb, offset, end); + break; + case HS20_ANQP_HS_CAPABILITY_LIST: + dissect_hs20_anqp_hs_capability_list(tree, tvb, offset, end); + break; + case HS20_ANQP_OPERATOR_FRIENDLY_NAME: + dissect_hs20_anqp_operator_friendly_name(tree, tvb, offset, end); + break; + case HS20_ANQP_WAN_METRICS: + dissect_hs20_anqp_wan_metrics(tree, tvb, offset, request); + break; + case HS20_ANQP_CONNECTION_CAPABILITY: + dissect_hs20_anqp_connection_capability(tree, tvb, offset, end); + break; + case HS20_ANQP_NAI_HOME_REALM_QUERY: + dissect_hs20_anqp_nai_home_realm_query(tree, tvb, offset, end); + break; + case HS20_ANQP_OPERATING_CLASS_INDICATION: + dissect_hs20_anqp_oper_class_indic(tree, tvb, offset, end); + break; + default: + if (offset == end) + break; + proto_tree_add_item(tree, hf_hs20_anqp_payload, tvb, offset, + end - offset, ENC_LITTLE_ENDIAN); + break; + } +} + static int dissect_anqp_info(proto_tree *tree, tvbuff_t *tvb, int offset, gboolean request, int idx) { guint16 id, len; guint32 oui; - guint8 subtype; proto_item *item; item = proto_tree_add_item(tree, hf_ieee80211_ff_anqp_info_id, @@ -5382,13 +5713,16 @@ dissect_anqp_info(proto_tree *tree, tvbuff_t *tvb, int offset, switch (oui) { case OUI_WFA: - subtype = tvb_get_guint8(tvb, offset); - if (subtype == WFA_SUBTYPE_P2P) { - proto_tree_add_text(tree, tvb, offset, 1, "Subtype %u: P2P ANQP", - subtype); + proto_tree_add_item(tree, hf_ieee80211_anqp_wfa_subtype, tvb, offset, 1, + ENC_NA); + switch (tvb_get_guint8(tvb, offset)) { + case WFA_SUBTYPE_P2P: dissect_wifi_p2p_anqp(g_pinfo, tree, tvb, offset + 1, request); - } else { - proto_tree_add_text(tree, tvb, offset, 1, "Subtype %u", subtype); + break; + case WFA_SUBTYPE_HS20_ANQP: + dissect_hs20_anqp(tree, tvb, offset + 1, offset + len - 3, request, + idx); + break; } break; default: @@ -6607,6 +6941,31 @@ wnm_sleep_mode_resp(proto_tree *tree, tvbuff_t *tvb, int offset) } static guint +wnm_tfs_req(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + int start = offset; + offset += add_fixed_field(tree, tvb, offset, FIELD_DIALOG_TOKEN); + return offset - start; +} + +static guint +wnm_tfs_resp(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + int start = offset; + offset += add_fixed_field(tree, tvb, offset, FIELD_DIALOG_TOKEN); + return offset - start; +} + +static guint +wnm_notification_req(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + int start = offset; + offset += add_fixed_field(tree, tvb, offset, FIELD_DIALOG_TOKEN); + offset += add_fixed_field(tree, tvb, offset, FIELD_WNM_NOTIFICATION_TYPE); + return offset - start; +} + +static guint add_ff_action_wnm(proto_tree *tree, tvbuff_t *tvb, int offset) { guint8 code; @@ -6619,12 +6978,21 @@ add_ff_action_wnm(proto_tree *tree, tvbuff_t *tvb, int offset) case WNM_BSS_TRANS_MGMT_REQ: offset += wnm_bss_trans_mgmt_req(tree, tvb, offset); break; + case WNM_TFS_REQ: + offset += wnm_tfs_req(tree, tvb, offset); + break; + case WNM_TFS_RESP: + offset += wnm_tfs_resp(tree, tvb, offset); + break; case WNM_SLEEP_MODE_REQ: offset += wnm_sleep_mode_req(tree, tvb, offset); break; case WNM_SLEEP_MODE_RESP: offset += wnm_sleep_mode_resp(tree, tvb, offset); break; + case WNM_NOTIFICATION_REQ: + offset += wnm_notification_req(tree, tvb, offset); + break; } return offset - start; /* Size of fixed fields */ @@ -6955,6 +7323,14 @@ struct ieee80211_fixed_field_dissector { guint (*dissector)(proto_tree *tree, tvbuff_t *tvb, int offset); }; +static guint +add_ff_wnm_notification_type(proto_tree *tree, tvbuff_t *tvb, int offset) +{ + proto_tree_add_item(tree, hf_ieee80211_ff_wnm_notification_type, + tvb, offset, 1, ENC_NA); + return 1; +} + #define FF_FIELD(f, func) { FIELD_ ## f, add_ff_ ## func } static const struct ieee80211_fixed_field_dissector ff_dissectors[] = { @@ -7021,6 +7397,7 @@ static const struct ieee80211_fixed_field_dissector ff_dissectors[] = { FF_FIELD(REGULATORY_CLASS , regulatory_class), FF_FIELD(WNM_ACTION_CODE , wnm_action_code), FF_FIELD(KEY_DATA_LENGTH , key_data_length), + FF_FIELD(WNM_NOTIFICATION_TYPE , wnm_notification_type), { (enum fixed_field)-1 , NULL } }; @@ -7615,6 +7992,13 @@ dissect_vendor_ie_wpawme(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 ta return offset; } +static void dissect_hs20_indication(proto_tree *tree, tvbuff_t *tvb, + int offset) +{ + proto_tree_add_item(tree, hf_hs20_indication_dgaf_disabled, tvb, offset, 1, + ENC_LITTLE_ENDIAN); +} + static void dissect_vendor_ie_wfa(packet_info *pinfo, proto_item *item, tvbuff_t *tag_tvb) { @@ -7628,6 +8012,10 @@ dissect_vendor_ie_wfa(packet_info *pinfo, proto_item *item, tvbuff_t *tag_tvb) dissect_wifi_p2p_ie(pinfo, item, tag_tvb, 4, tag_len - 4); proto_item_append_text(item, ": P2P"); break; + case WFA_SUBTYPE_HS20_INDICATION: + dissect_hs20_indication(item, tag_tvb, 4); + proto_item_append_text(item, ": Hotspot 2.0 Indication"); + break; } } @@ -9068,6 +9456,154 @@ static int dissect_bss_max_idle_period(proto_tree *tree, tvbuff_t *tvb, return offset; } +static int add_tagged_field(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, + int offset, int ftype); + +enum tfs_request_subelem_id { + TFS_REQ_SUBELEM_TFS = 1, + TFS_REQ_SUBELEM_VENDOR_SPECIFIC = 221 +}; + +static const value_string tfs_request_subelem_ids[] = { + { TFS_REQ_SUBELEM_TFS, "TFS subelement" }, + { TFS_REQ_SUBELEM_VENDOR_SPECIFIC, "Vendor Specific subelement" }, + { 0, NULL } +}; + +static int dissect_tfs_request(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, guint32 tag_len, + int ftype) +{ + int end = offset + tag_len; + + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_id, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_ac_delete_after_match, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_ac_notify, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + if (offset + 1 >= end) { + expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_WARN, + "No TFS Request subelements in TFS Request"); + return end; + } + + while (offset + 1 < end) { + guint8 id, len; + int s_offset, s_end; + + id = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_subelem_id, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + len = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_subelem_len, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + if (offset + len > end) { + expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, + "Not enough data for TFS Request subelement"); + return end; + } + switch (id) { + case TFS_REQ_SUBELEM_TFS: + s_offset = offset; + s_end = offset + len; + while (s_offset < s_end) { + int tlen = add_tagged_field(pinfo, tree, tvb, s_offset, ftype); + s_offset += tlen; + } + break; + default: + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_request_subelem, + tvb, offset, len, ENC_NA); + break; + } + offset += len; + } + + if (offset < end) { + proto_tree_add_text(tree, tvb, offset, end - offset, + "Unexpected extra data"); + expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_WARN, + "Extra data after TFS Subelements"); + } + + return end; +} + +enum tfs_response_subelem_id { + TFS_RESP_SUBELEM_TFS_STATUS = 1, + TFS_RESP_SUBELEM_TFS = 2, + TFS_RESP_SUBELEM_VENDOR_SPECIFIC = 221 +}; + +static const value_string tfs_response_subelem_ids[] = { + { TFS_RESP_SUBELEM_TFS_STATUS, "TFS Status subelement" }, + { TFS_RESP_SUBELEM_TFS, "TFS subelement" }, + { TFS_RESP_SUBELEM_VENDOR_SPECIFIC, "Vendor Specific subelement" }, + { 0, NULL } +}; + +static int dissect_tfs_response(packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, int offset, guint32 tag_len, + int ftype) +{ + int end = offset + tag_len; + + while (offset + 3 <= end) { + guint8 id, len; + int s_offset, s_end; + + id = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_response_subelem_id, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + len = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_response_subelem_len, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset++; + if (offset + len > end) { + expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR, + "Not enough data for TFS Request subelement"); + return end; + } + switch (id) { + case TFS_RESP_SUBELEM_TFS_STATUS: + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_response_status, + tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_response_id, + tvb, offset + 1, 1, ENC_LITTLE_ENDIAN); + break; + case TFS_RESP_SUBELEM_TFS: + s_offset = offset; + s_end = offset + len; + while (s_offset < s_end) { + int tlen = add_tagged_field(pinfo, tree, tvb, s_offset, ftype); + s_offset += tlen; + } + break; + default: + proto_tree_add_item(tree, hf_ieee80211_tag_tfs_response_subelem, + tvb, offset, len, ENC_NA); + break; + } + + offset += len; + } + + if (offset < end) { + proto_tree_add_text(tree, tvb, offset, end - offset, + "Unexpected extra data"); + expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_WARN, + "Extra data after TFS Status subelements"); + } + + return end; +} + static const value_string wnm_sleep_mode_action_types[] = { { 0, "Enter WNM-Sleep Mode" }, { 1, "Exit WNM-Sleep Mode" }, @@ -10016,7 +10552,6 @@ dissect_roaming_consortium(packet_info *pinfo, proto_tree *tree, /* Dissect and add tagged (optional) fields to proto tree */ /* ************************************************************************* */ - static int beacon_padding = 0; /* beacon padding bug */ static int @@ -11656,6 +12191,14 @@ add_tagged_field(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset dissect_bss_max_idle_period(tree, tvb, offset + 2); break; + case TAG_TFS_REQUEST: + dissect_tfs_request(pinfo, tree, tvb, offset + 2, tag_len, ftype); + break; + + case TAG_TFS_RESPONSE: + dissect_tfs_response(pinfo, tree, tvb, offset + 2, tag_len, ftype); + break; + case TAG_WNM_SLEEP_MODE: dissect_wnm_sleep_mode(tree, tvb, offset + 2); break; @@ -14580,6 +15123,11 @@ proto_register_ieee80211 (void) {"Key Data Length", "wlan_mgt.fixed.key_data_length", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_ff_wnm_notification_type, + {"WNM-Notification type", "wlan_mgt.fixed.wnm_notification_type", + FT_UINT8, BASE_DEC|BASE_EXT_STRING, &wnm_notification_types_ext, 0, + NULL, HFILL }}, + {&hf_ieee80211_ff_request_mode_pref_cand, {"Preferred Candidate List Included","wlan_mgt.fixed.request_mode.pref_cand", FT_UINT8, BASE_DEC, NULL, 0x01, @@ -15853,6 +16401,126 @@ proto_register_ieee80211 (void) FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_anqp_wfa_subtype, + {"ANQP WFA Subtype", "wlan_mgt.anqp.wfa.subtype", + FT_UINT8, BASE_DEC, VALS(wfa_subtype_vals), 0, NULL, HFILL }}, + + {&hf_hs20_indication_dgaf_disabled, + {"DGAF Disabled", "wlan_mgt.hs20.indication.dgaf_disabled", + FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }}, + + {&hf_hs20_anqp_subtype, + {"Subtype", "wlan_mgt.hs20.anqp.subtype", + FT_UINT8, BASE_DEC, VALS(hs20_anqp_subtype_vals), 0, + "Hotspot 2.0 ANQP Subtype", HFILL }}, + + {&hf_hs20_anqp_reserved, + {"Reserved", "wlan_mgt.hs20.anqp.reserved", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_payload, + {"Payload", "wlan_mgt.hs20.anqp.payload", + FT_BYTES, BASE_NONE, NULL, 0, + "Hotspot 2.0 ANQP Payload", HFILL }}, + + {&hf_hs20_anqp_hs_query_list, + {"Queried Subtype", "wlan_mgt.hs20.anqp.hs_query_list", + FT_UINT8, BASE_DEC, VALS(hs20_anqp_subtype_vals), 0, + "Queried HS 2.0 Element Subtype", HFILL }}, + + {&hf_hs20_anqp_hs_capability_list, + {"Capability", "wlan_mgt.hs20.anqp.hs_capability_list", + FT_UINT8, BASE_DEC, VALS(hs20_anqp_subtype_vals), 0, + "Hotspot 2.0 ANQP Subtype Capability", HFILL }}, + + {&hf_hs20_anqp_ofn_length, + {"Length", "wlan_mgt.hs20.anqp.ofn.length", + FT_UINT8, BASE_DEC, NULL, 0, + "Operator Friendly Name Length", HFILL }}, + + {&hf_hs20_anqp_ofn_language, + {"Language Code", "wlan_mgt.hs20.anqp.ofn.language", + FT_STRING, BASE_NONE, NULL, 0, + "Operator Friendly Name Language Code", HFILL }}, + + {&hf_hs20_anqp_ofn_name, + {"Operator Friendly Name", "wlan_mgt.hs20.anqp.ofn.name", + FT_STRING, BASE_NONE, NULL, 0, + NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_link_status, + {"Link Status", "wlan_mgt.hs20.anqp.wan_metrics.link_status", + FT_UINT8, BASE_DEC, VALS(hs20_wm_link_status_vals), 0x03, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_symmetric_link, + {"Symmetric Link", "wlan_mgt.hs20.anqp.wan_metrics.symmetric_link", + FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_at_capacity, + {"At Capacity", "wlan_mgt.hs20.anqp.wan_metrics.at_capacity", + FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_reserved, + {"Reserved", "wlan_mgt.hs20.anqp.wan_metrics.reserved", + FT_UINT8, BASE_DEC, NULL, 0xf0, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_downlink_speed, + {"Downlink Speed", "wlan_mgt.hs20.anqp.wan_metrics.downlink_speed", + FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_uplink_speed, + {"Uplink Speed", "wlan_mgt.hs20.anqp.wan_metrics.uplink_speed", + FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_downlink_load, + {"Downlink Load", "wlan_mgt.hs20.anqp.wan_metrics.downlink_load", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_uplink_load, + {"Uplink Load", "wlan_mgt.hs20.anqp.wan_metrics.uplink_load", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_wan_metrics_lmd, + {"LMD", "wlan_mgt.hs20.anqp.wan_metrics.lmd", + FT_UINT16, BASE_DEC, NULL, 0, "Load Measurement Duration", HFILL }}, + + {&hf_hs20_anqp_cc_proto_ip_proto, + {"IP Protocol", "wlan_mgt.hs20.anqp.cc.ip_proto", + FT_UINT8, BASE_DEC, NULL, 0, + "ProtoPort Tuple - IP Protocol", HFILL }}, + + {&hf_hs20_anqp_cc_proto_port_num, + {"Port Number", "wlan_mgt.hs20.anqp.cc.port_num", + FT_UINT16, BASE_DEC, NULL, 0, + "ProtoPort Tuple - Port Number", HFILL }}, + + {&hf_hs20_anqp_cc_proto_status, + {"Status", "wlan_mgt.hs20.anqp.cc.status", + FT_UINT8, BASE_DEC, VALS(hs20_cc_status_vals), 0, + "ProtoPort Tuple - Status", HFILL }}, + + {&hf_hs20_anqp_nai_hrq_count, + {"NAI Home Realm Count", "wlan_mgt.hs20.anqp.nai_hrq.count", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_nai_hrq_encoding_type, + {"NAI Home Realm Encoding Type", + "wlan_mgt.hs20.anqp.nai_hrq.encoding_type", + FT_UINT8, BASE_DEC, VALS(nai_realm_encoding_vals), + 0x01, NULL, HFILL }}, + + {&hf_hs20_anqp_nai_hrq_length, + {"NAI Home Realm Name Length", "wlan_mgt.hs20.anqp.nai_hrq.length", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_nai_hrq_realm_name, + {"NAI Home Realm Name", "wlan_mgt.hs20.anqp.nai_hrq.name", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }}, + + {&hf_hs20_anqp_oper_class_indic, + {"Operating Class", "wlan_mgt.hs20.anqp.oper_class_indic.oper_class", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_tag, {"Tag", "wlan_mgt.tag", FT_NONE, BASE_NONE, 0x0, 0, @@ -19493,6 +20161,51 @@ proto_register_ieee80211 (void) "wlan_mgt.bss_max_idle.options.protected", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }}, + /* TFS Request */ + {&hf_ieee80211_tag_tfs_request_id, + {"TFS ID", "wlan_mgt.tfs_request.id", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_tag_tfs_request_ac_delete_after_match, + {"TFS Action Code - Delete after match", + "wlan_mgt.tfs_request.action_code.delete_after_match", + FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }}, + {&hf_ieee80211_tag_tfs_request_ac_notify, + {"TFS Action Code - Notify", + "wlan_mgt.tfs_request.action_code.notify", + FT_UINT8, BASE_DEC, NULL, 0x02, NULL, HFILL }}, + {&hf_ieee80211_tag_tfs_request_subelem_id, + {"Subelement ID", "wlan_mgt.tfs_request.subelem.id", + FT_UINT8, BASE_DEC, VALS(tfs_request_subelem_ids), 0, + "TFS Request Subelement ID", HFILL }}, + {&hf_ieee80211_tag_tfs_request_subelem_len, + {"Length", "wlan_mgt.tfs_request.subelem.len", + FT_UINT8, BASE_DEC, NULL, 0, + "TFS Request Subelement Length", HFILL }}, + {&hf_ieee80211_tag_tfs_request_subelem, + {"Subelement Data", "wlan_mgt.tfs_request.subelem", + FT_BYTES, BASE_NONE, NULL, 0, + "TFS Request Subelement Data", HFILL }}, + + /* TFS Response */ + {&hf_ieee80211_tag_tfs_response_subelem_id, + {"Subelement ID", "wlan_mgt.tfs_response.subelem.id", + FT_UINT8, BASE_DEC, VALS(tfs_response_subelem_ids), 0, + "TFS Response Subelement ID", HFILL }}, + {&hf_ieee80211_tag_tfs_response_subelem_len, + {"Length", "wlan_mgt.tfs_response.subelem.len", + FT_UINT8, BASE_DEC, NULL, 0, + "TFS Response Subelement Length", HFILL }}, + {&hf_ieee80211_tag_tfs_response_subelem, + {"Subelement Data", "wlan_mgt.tfs_response.subelem", + FT_BYTES, BASE_NONE, NULL, 0, + "TFS Response Subelement Data", HFILL }}, + {&hf_ieee80211_tag_tfs_response_status, + {"TFS Response Status", "wlan_mgt.tfs_response.status", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + {&hf_ieee80211_tag_tfs_response_id, + {"TFS ID", "wlan_mgt.tfs_response.tfs_id", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + /* WNM-Sleep Mode */ {&hf_ieee80211_tag_wnm_sleep_mode_action_type, {"Action Type", "wlan_mgt.wnm_sleep_mode.action_type", @@ -19893,7 +20606,8 @@ proto_register_ieee80211 (void) &ett_nai_realm, &ett_nai_realm_eap, &ett_tag_ric_data_desc_ie, - &ett_anqp_vendor_capab + &ett_anqp_vendor_capab, + &ett_hs20_cc_proto_port_tuple }; module_t *wlan_module; |