mpdu: Validate IE order for most frame subtypes

Check the IE order for each frame type where we'd just do the body
minimum length check until now (and not always correctly).  We do not
try to validate the contents of any IEs (may be doable for some) or the
minimum mandatory IEs presence.  This is because which IEs are required
depend on the contents of other fields in the frame, on the
authentication state and STA config and even contents of a request frame
which we're validating the response to.  Frame handlers have to do this
work anyway.
This commit is contained in:
Andrew Zaborowski 2017-09-22 05:06:29 +02:00 committed by Denis Kenzior
parent 58a7032ed9
commit 736f611974
1 changed files with 516 additions and 20 deletions

View File

@ -49,11 +49,515 @@ static bool validate_mgmt_header(const struct mmpdu_header *mpdu,
return true;
}
static bool validate_on_ies_start_position_mmpdu(
const struct mmpdu_header *mpdu,
int len, int *offset, int position)
/* 802.11-2016 13.11.2 */
static bool skip_resource_req_resp(struct ie_tlv_iter *iter, bool response)
{
return *offset + position < len;
struct ie_tlv_iter tmp;
/*
* This is called when we've seen an RDE so we only need to validate
* and skip IEs representing one or more Resource Descriptors up to
* the end of this Resource Request or Resource Response.
*
* Since the Resource Descriptor specification is complex and,
* especially in the case of a Vendor Specific descriptor and
* in the case of a Resource Response to a failed request (with
* the optional information), there seems to be no strict definition
* of where one request/response ends and the next begins, allow
* any combination of any of the IEs listed in 13.11.2 until an
* IE that doesn't seem to be part of this RDE.
*/
memcpy(&tmp, iter, sizeof(tmp));
while (ie_tlv_iter_next(&tmp)) {
switch (ie_tlv_iter_get_tag(&tmp)) {
case IE_TYPE_TSPEC:
case IE_TYPE_TCLAS:
case IE_TYPE_TCLAS_PROCESSING:
case IE_TYPE_EXPEDITED_BANDWIDTH_REQUEST:
case IE_TYPE_SCHEDULE:
case IE_TYPE_TS_DELAY:
case IE_TYPE_RIC_DESCRIPTOR:
case IE_TYPE_VENDOR_SPECIFIC:
memcpy(iter, &tmp, sizeof(tmp));
continue;
default:
break;
}
break;
}
return true;
}
static bool validate_mgmt_ies(const uint8_t *ies, size_t ies_len,
const enum ie_type tag_order[], int tag_count,
bool response)
{
struct ie_tlv_iter iter;
int last_idx = -1;
enum ie_type tag;
ie_tlv_iter_init(&iter, ies, ies_len);
while (ie_tlv_iter_next(&iter)) {
int new_idx, i;
tag = ie_tlv_iter_get_tag(&iter);
/*
* Only some element IDs including the final Vendor Specific
* element are allowed to repeat.
*/
if (last_idx == -1 || (tag != IE_TYPE_VENDOR_SPECIFIC &&
tag != IE_TYPE_RIC_DATA &&
tag != IE_TYPE_TRANSMIT_POWER_ENVELOPE &&
tag != IE_TYPE_MCCAOP_ADVERTISEMENT &&
tag != IE_TYPE_EMERGENCY_ALERT_IDENTIFIER &&
tag != IE_TYPE_MULTIPLE_BSSID &&
tag != IE_TYPE_NEIGHBOR_REPORT &&
tag != IE_TYPE_QUIET_CHANNEL))
last_idx++;
if (tag == IE_TYPE_RIC_DATA &&
!skip_resource_req_resp(&iter, response))
return false;
new_idx = last_idx;
while (tag != tag_order[new_idx] && new_idx < tag_count)
new_idx++;
if (new_idx < tag_count) {
last_idx = new_idx;
continue;
}
/*
* Tag not found in the remaining part of the array, check
* if it is anywhere else in the array and only then report
* error since we have to ignore unknown tags. 802.11-2016
* section 9.3.3.2:
* "All fields and elements are mandatory unless stated
* otherwise and appear in the specified, relative order.
* STAs that encounter an element ID they do not recognize
* in the frame body of a received Management frame ignore
* that element and continue to parse the remainder of the
* management frame body (if any) for additional elements
* with recognizable element IDs."
*/
for (i = 0; i < last_idx; i++)
if (tag == tag_order[i])
goto check_request_response;
}
return true;
check_request_response:
/*
* If this is a response to a frame that could have contained a
* Request or an Extended Request element, then, after all of the
* "Elements that would have been included even in the absence of
* the Request element or Extended Request element" (802.11-2016
* section 11.1.4.3.5) basically any Element ID may appear with the
* only requirement being an ascending order of the numerical values
* of the IDs.
*/
if (!response)
return false;
tag = ie_tlv_iter_get_tag(&iter);
while (ie_tlv_iter_next(&iter)) {
enum ie_type next_tag = ie_tlv_iter_get_tag(&iter);
if (next_tag < tag)
return false;
tag = next_tag;
}
return true;
}
/* 802.11-2016 section 9.3.3.6 */
static bool validate_association_request_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_association_request *body =
(const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SSID,
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_POWER_CAPABILITY,
IE_TYPE_SUPPORTED_CHANNELS,
IE_TYPE_RSN,
IE_TYPE_QOS_CAPABILITY,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_SUPPORTED_OPERATING_CLASSES,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_QOS_TRAFFIC_CAPABILITY,
IE_TYPE_TIM_BROADCAST_REQUEST,
IE_TYPE_INTERWORKING,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_association_request))
return false;
*offset += sizeof(struct mmpdu_association_request);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), false);
}
/* 802.11-2016 section 9.3.3.7 */
static bool validate_association_response_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_association_response *body =
(const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_EDCA_PARAMETER_SET,
IE_TYPE_RCPI,
IE_TYPE_RSNI,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_FAST_BSS_TRANSITION,
IE_TYPE_DSE_REGISTERED_LOCATION,
IE_TYPE_TIMEOUT_INTERVAL,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_HT_OPERATION,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_OVERLAPPING_BSS_SCAN_PARAMETERS,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_BSS_MAX_IDLE_PERIOD,
IE_TYPE_TIM_BROADCAST_RESPONSE,
IE_TYPE_QOS_MAP_SET,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_association_response))
return false;
*offset += sizeof(struct mmpdu_association_response);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), true);
}
/* 802.11-2016 section 9.3.3.8 */
static bool validate_reassociation_request_mmpdu(
const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_reassociation_request *body =
(const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SSID,
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_POWER_CAPABILITY,
IE_TYPE_SUPPORTED_CHANNELS,
IE_TYPE_RSN,
IE_TYPE_QOS_CAPABILITY,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_FAST_BSS_TRANSITION,
IE_TYPE_RIC_DATA,
IE_TYPE_SUPPORTED_OPERATING_CLASSES,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_QOS_TRAFFIC_CAPABILITY,
IE_TYPE_TIM_BROADCAST_REQUEST,
IE_TYPE_FMS_REQUEST,
IE_TYPE_DMS_REQUEST,
IE_TYPE_INTERWORKING,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_reassociation_request))
return false;
*offset += sizeof(struct mmpdu_reassociation_request);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), false);
}
/* 802.11-2016 section 9.3.3.9 */
static bool validate_reassociation_response_mmpdu(
const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_reassociation_response *body =
(const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_EDCA_PARAMETER_SET,
IE_TYPE_RCPI,
IE_TYPE_RSNI,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_RSN,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_FAST_BSS_TRANSITION,
IE_TYPE_RIC_DATA,
IE_TYPE_DSE_REGISTERED_LOCATION,
IE_TYPE_TIMEOUT_INTERVAL,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_HT_OPERATION,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_OVERLAPPING_BSS_SCAN_PARAMETERS,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_BSS_MAX_IDLE_PERIOD,
IE_TYPE_TIM_BROADCAST_RESPONSE,
IE_TYPE_FMS_RESPONSE,
IE_TYPE_DMS_RESPONSE,
IE_TYPE_QOS_MAP_SET,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_reassociation_response))
return false;
*offset += sizeof(struct mmpdu_reassociation_response);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), true);
}
/* 802.11-2016 section 9.3.3.10 */
static bool validate_probe_request_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_probe_request *body = (const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SSID,
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_REQUEST,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_DSSS_PARAMETER_SET,
IE_TYPE_SUPPORTED_OPERATING_CLASSES,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_SSID_LIST,
IE_TYPE_CHANNEL_USAGE,
IE_TYPE_INTERWORKING,
IE_TYPE_MESH_ID,
IE_TYPE_MULTIBAND,
IE_TYPE_DMG_CAPABILITIES,
IE_TYPE_MULTIPLE_MAC_SUBLAYERS,
IE_TYPE_VHT_CAPABILITIES,
IE_TYPE_ESTIMATED_SERVICE_PARAMETERS,
IE_TYPE_EXTENDED_REQUEST,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_probe_request))
return false;
*offset += sizeof(struct mmpdu_probe_request);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), false);
}
/* 802.11-2016 section 9.3.3.11 */
static bool validate_probe_response_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_probe_response *body = (const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SSID,
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_DSSS_PARAMETER_SET,
IE_TYPE_CF_PARAMETER_SET,
IE_TYPE_IBSS_PARAMETER_SET,
IE_TYPE_COUNTRY,
IE_TYPE_POWER_CONSTRAINT,
IE_TYPE_CHANNEL_SWITCH_ANNOUNCEMENT,
IE_TYPE_QUIET,
IE_TYPE_IBSS_DFS,
IE_TYPE_TPC_REPORT,
IE_TYPE_ERP,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_RSN,
IE_TYPE_BSS_LOAD,
IE_TYPE_EDCA_PARAMETER_SET,
IE_TYPE_MEASUREMENT_PILOT_TRANSMISSION,
IE_TYPE_MULTIPLE_BSSID,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_AP_CHANNEL_REPORT,
IE_TYPE_BSS_AVERAGE_ACCESS_DELAY,
IE_TYPE_ANTENNA,
IE_TYPE_BSS_AVAILABLE_ADMISSION_CAPACITY,
IE_TYPE_BSS_AC_ACCESS_DELAY,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_DSE_REGISTERED_LOCATION,
IE_TYPE_EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT,
IE_TYPE_SUPPORTED_OPERATING_CLASSES,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_HT_OPERATION,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_OVERLAPPING_BSS_SCAN_PARAMETERS,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_QOS_TRAFFIC_CAPABILITY,
IE_TYPE_CHANNEL_USAGE,
IE_TYPE_TIME_ADVERTISEMENT,
IE_TYPE_TIME_ZONE,
IE_TYPE_INTERWORKING,
IE_TYPE_ADVERTISEMENT_PROTOCOL,
IE_TYPE_ROAMING_CONSORTIUM,
IE_TYPE_EMERGENCY_ALERT_IDENTIFIER,
IE_TYPE_MESH_ID,
IE_TYPE_MESH_CONFIGURATION,
IE_TYPE_MESH_AWAKE_WINDOW,
IE_TYPE_BEACON_TIMING,
IE_TYPE_MCCAOP_ADVERTISEMENT_OVERVIEW,
IE_TYPE_MCCAOP_ADVERTISEMENT,
IE_TYPE_MESH_CHANNEL_SWITCH_PARAMETERS,
IE_TYPE_QMF_POLICY,
IE_TYPE_QLOAD_REPORT,
IE_TYPE_MULTIBAND,
IE_TYPE_DMG_CAPABILITIES,
IE_TYPE_DMG_OPERATION,
IE_TYPE_MULTIPLE_MAC_SUBLAYERS,
IE_TYPE_ANTENNA_SECTOR_ID_PATTERN,
IE_TYPE_VHT_CAPABILITIES,
IE_TYPE_VHT_OPERATION,
IE_TYPE_TRANSMIT_POWER_ENVELOPE,
IE_TYPE_CHANNEL_SWITCH_WRAPPER,
IE_TYPE_EXTENDED_BSS_LOAD,
IE_TYPE_QUIET_CHANNEL,
IE_TYPE_OPERATING_MODE_NOTIFICATION,
IE_TYPE_REDUCED_NEIGHBOR_REPORT,
IE_TYPE_TVHT_OPERATION,
IE_TYPE_ESTIMATED_SERVICE_PARAMETERS,
IE_TYPE_RELAY_CAPABILITIES,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_probe_response))
return false;
*offset += sizeof(struct mmpdu_probe_response);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), true);
}
/* 802.11-2016 section 9.3.3.16 */
static bool validate_timing_advertisement_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_timing_advertisement *body =
(const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_COUNTRY,
IE_TYPE_POWER_CONSTRAINT,
IE_TYPE_TIME_ADVERTISEMENT,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_timing_advertisement))
return false;
*offset += sizeof(struct mmpdu_timing_advertisement);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), false);
}
/* 802.11-2016 section 9.3.3.3 */
static bool validate_beacon_mmpdu(const struct mmpdu_header *mpdu,
int len, int *offset)
{
const struct mmpdu_beacon *body = (const void *) mpdu + *offset;
static const enum ie_type ie_order[] = {
IE_TYPE_SSID,
IE_TYPE_SUPPORTED_RATES,
IE_TYPE_DSSS_PARAMETER_SET,
IE_TYPE_CF_PARAMETER_SET,
IE_TYPE_IBSS_PARAMETER_SET,
IE_TYPE_TIM,
IE_TYPE_COUNTRY,
IE_TYPE_POWER_CONSTRAINT,
IE_TYPE_CHANNEL_SWITCH_ANNOUNCEMENT,
IE_TYPE_QUIET,
IE_TYPE_IBSS_DFS,
IE_TYPE_TPC_REPORT,
IE_TYPE_ERP,
IE_TYPE_EXTENDED_SUPPORTED_RATES,
IE_TYPE_RSN,
IE_TYPE_BSS_LOAD,
IE_TYPE_EDCA_PARAMETER_SET,
IE_TYPE_QOS_CAPABILITY,
IE_TYPE_AP_CHANNEL_REPORT,
IE_TYPE_BSS_AVERAGE_ACCESS_DELAY,
IE_TYPE_ANTENNA,
IE_TYPE_BSS_AVAILABLE_ADMISSION_CAPACITY,
IE_TYPE_BSS_AC_ACCESS_DELAY,
IE_TYPE_MEASUREMENT_PILOT_TRANSMISSION,
IE_TYPE_MULTIPLE_BSSID,
IE_TYPE_RM_ENABLED_CAPABILITIES,
IE_TYPE_MOBILITY_DOMAIN,
IE_TYPE_DSE_REGISTERED_LOCATION,
IE_TYPE_EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT,
IE_TYPE_SUPPORTED_OPERATING_CLASSES,
IE_TYPE_HT_CAPABILITIES,
IE_TYPE_HT_OPERATION,
IE_TYPE_BSS_COEXISTENCE,
IE_TYPE_OVERLAPPING_BSS_SCAN_PARAMETERS,
IE_TYPE_EXTENDED_CAPABILITIES,
IE_TYPE_FMS_DESCRIPTOR,
IE_TYPE_QOS_TRAFFIC_CAPABILITY,
IE_TYPE_TIME_ADVERTISEMENT,
IE_TYPE_INTERWORKING,
IE_TYPE_ADVERTISEMENT_PROTOCOL,
IE_TYPE_ROAMING_CONSORTIUM,
IE_TYPE_EMERGENCY_ALERT_IDENTIFIER,
IE_TYPE_MESH_ID,
IE_TYPE_MESH_CONFIGURATION,
IE_TYPE_MESH_AWAKE_WINDOW,
IE_TYPE_BEACON_TIMING,
IE_TYPE_MCCAOP_ADVERTISEMENT_OVERVIEW,
IE_TYPE_MCCAOP_ADVERTISEMENT,
IE_TYPE_MESH_CHANNEL_SWITCH_PARAMETERS,
IE_TYPE_QMF_POLICY,
IE_TYPE_QLOAD_REPORT,
IE_TYPE_HCCA_TXOP_UPDATE_COUNT,
IE_TYPE_MULTIBAND,
IE_TYPE_VHT_CAPABILITIES,
IE_TYPE_VHT_OPERATION,
IE_TYPE_TRANSMIT_POWER_ENVELOPE,
IE_TYPE_CHANNEL_SWITCH_WRAPPER,
IE_TYPE_EXTENDED_BSS_LOAD,
IE_TYPE_QUIET_CHANNEL,
IE_TYPE_OPERATING_MODE_NOTIFICATION,
IE_TYPE_REDUCED_NEIGHBOR_REPORT,
IE_TYPE_TVHT_OPERATION,
IE_TYPE_ESTIMATED_SERVICE_PARAMETERS,
IE_TYPE_FUTURE_CHANNEL_GUIDANCE,
IE_TYPE_VENDOR_SPECIFIC,
};
if (len < *offset + (int) sizeof(struct mmpdu_beacon))
return false;
*offset += sizeof(struct mmpdu_beacon);
return validate_mgmt_ies(body->ies, len - *offset, ie_order,
L_ARRAY_SIZE(ie_order), false);
}
static bool validate_atim_mmpdu(const struct mmpdu_header *mpdu,
@ -122,29 +626,21 @@ static bool validate_mgmt_mpdu(const struct mmpdu_header *mpdu, int len,
switch (mpdu->fc.subtype) {
case MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 9);
return validate_association_request_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_RESPONSE:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 9);
return validate_association_response_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_REQUEST:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 15);
return validate_reassociation_request_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_RESPONSE:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 9);
return validate_reassociation_response_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_PROBE_REQUEST:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 0);
return validate_probe_request_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_PROBE_RESPONSE:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 5);
return validate_probe_response_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_TIMING_ADVERTISEMENT:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 3);
return validate_timing_advertisement_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_BEACON:
return validate_on_ies_start_position_mmpdu(mpdu, len,
offset, 5);
return validate_beacon_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_ATIM:
return validate_atim_mmpdu(mpdu, len, offset);
case MPDU_MANAGEMENT_SUBTYPE_DISASSOCIATION: