[wlan][mlme] Validate all non-action mgmt frames
NET-1785
TEST=Manually checked that connecting to a network passes the
validation, and writing an incorrect frame fails.
Change-Id: Iac7c750622269c5a3c4c35eeeee13e0f2173b174
diff --git a/lib/wlan/common/include/wlan/common/mac_frame.h b/lib/wlan/common/include/wlan/common/mac_frame.h
index 47f878c..d4cebdc 100644
--- a/lib/wlan/common/include/wlan/common/mac_frame.h
+++ b/lib/wlan/common/include/wlan/common/mac_frame.h
@@ -522,10 +522,10 @@
enum AuthAlgorithm : uint16_t {
kOpenSystem = 0,
kSharedKey = 1,
- kFastBssTransition = 2,
+ kFastBssTransitionAuth = 2,
kSae = 3,
// 4-65534 Reserved
- kVendorSpecific = 65535,
+ kVendorSpecificAuth = 65535,
};
// IEEE Std 802.11-2016, 9.3.3.12
@@ -592,6 +592,26 @@
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
+// IEEE Std 802.11-2016, 9.3.3.8
+struct ReassociationRequest {
+ CapabilityInfo cap;
+ uint16_t listen_interval;
+ common::MacAddr current_ap_addr;
+} __PACKED;
+
+// IEEE Std 802.11-2016, 9.3.3.9
+struct ReassociationResponse {
+ CapabilityInfo cap;
+ uint16_t status_code;
+ uint16_t aid;
+} __PACKED;
+
+// IEEE Std 802.11-2016, 9.3.3.16
+struct TimingAdvertisement {
+ uint64_t timestamp;
+ CapabilityInfo cap;
+} __PACKED;
+
// IEEE Std 802.11-2016, 9.3.3.5
struct Disassociation {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kDisassociation; }
diff --git a/lib/wlan/mlme/beacon.cpp b/lib/wlan/mlme/beacon.cpp
index 133dade..43b2876 100644
--- a/lib/wlan/mlme/beacon.cpp
+++ b/lib/wlan/mlme/beacon.cpp
@@ -97,8 +97,8 @@
WriteRsne(w, config);
WriteHtCapabilities(w, config);
WriteHtOperation(w, config);
- WriteMeshConfiguration(w, config);
WriteMeshId(w, config);
+ WriteMeshConfiguration(w, config);
}
template <typename T> static void SetBssType(T* bcn, BssType bss_type) {
diff --git a/lib/wlan/mlme/validate_frame.cpp b/lib/wlan/mlme/validate_frame.cpp
index 4ce879b..07c521e 100644
--- a/lib/wlan/mlme/validate_frame.cpp
+++ b/lib/wlan/mlme/validate_frame.cpp
@@ -52,6 +52,7 @@
return AllowedElement(id, true);
}
+// IEEE Std 802.11-2016, 9.3.3.3
static constexpr AllowedElement kBeaconElements[] = {
Required(kSsid),
Required(kSuppRates),
@@ -95,8 +96,8 @@
kAdvertisementProtocol,
kRoamingConsortium,
kEmergencyAlertId,
- kMeshConfiguration,
kMeshId,
+ kMeshConfiguration,
kMeshAwakeWindow,
kBeaconTiming,
kMccaopAdvertisementOverview,
@@ -115,8 +116,254 @@
kOperatingModeNotification,
kReducedNeighborReport,
kTvhtOperation,
+ // TODO: Estimated Service Parameters (2-byte ID)
+ // TODO: Future Channel Guidance (2-byte ID)
};
+// IEEE Std 802.11-2016, 9.3.3.5
+static constexpr AllowedElement kDisassocElements[] = {
+ kManagementMic
+};
+
+// IEEE Std 802.11-2016, 9.3.3.6
+static constexpr AllowedElement kAssocReqElements[] = {
+ Required(kSsid),
+ Required(kSuppRates),
+ kExtSuppRates,
+ kPowerCapability,
+ kSupportedChannels,
+ kRsn,
+ kQosCapability,
+ kRmEnabledCapabilities,
+ kMobilityDomain,
+ kSuppOperatingClasses,
+ kHtCapabilities,
+ k2040BssCoex,
+ kExtCapabilities,
+ kQosTrafficCapability,
+ kTimBroadcastRequest,
+ kInterworking,
+ kMultiband,
+ kDmgCapabilities,
+ kMultipleMacSublayers,
+ kVhtCapabilities,
+ kOperatingModeNotification,
+};
+
+// IEEE Std 802.11-2016, 9.3.3.7
+static constexpr AllowedElement kAssocRespElements[] = {
+ Required(kSuppRates),
+ kExtSuppRates,
+ kEdcaParamSet,
+ kRcpi,
+ kRsni,
+ kRmEnabledCapabilities,
+ kMobilityDomain,
+ kFastBssTransition,
+ kDseRegisteredLocation,
+ kTimeoutInterval,
+ kHtCapabilities,
+ kHtOperation,
+ k2040BssCoex,
+ kOverlappingBssScanParams,
+ kExtCapabilities,
+ kBssMaxIdlePeriod,
+ kTimBroadcastResponse,
+ kQosMap,
+ kQmfPolicy,
+ kMultiband,
+ kDmgCapabilities,
+ kDmgOperation,
+ kMultipleMacSublayers,
+ kNeighborReport,
+ kVhtCapabilities,
+ kVhtOperation,
+ kOperatingModeNotification,
+ // TODO: Future Channel Guidance (2-byte ID)
+};
+
+// IEEE Std 802.11-2016, 9.3.3.8
+static constexpr AllowedElement kReassocReqElements[] = {
+ Required(kSsid),
+ Required(kSuppRates),
+ kExtSuppRates,
+ kPowerCapability,
+ kSupportedChannels,
+ kRsn,
+ kQosCapability,
+ kRmEnabledCapabilities,
+ kMobilityDomain,
+ kFastBssTransition,
+ // TODO: RIC container? (can be several elements)
+ kSuppOperatingClasses,
+ kHtCapabilities,
+ k2040BssCoex,
+ kExtCapabilities,
+ kQosTrafficCapability,
+ kTimBroadcastRequest,
+ kFmsRequest,
+ kDmsRequest,
+ kInterworking,
+ kMultiband,
+ kDmgCapabilities,
+ kMultipleMacSublayers,
+ kVhtCapabilities,
+ kOperatingModeNotification
+};
+
+// IEEE Std 802.11-2016, 9.3.3.9
+static constexpr AllowedElement kReassocRespElements[] = {
+ Required(kSuppRates),
+ kExtSuppRates,
+ kEdcaParamSet,
+ kRcpi,
+ kRsni,
+ kRmEnabledCapabilities,
+ kRsn,
+ kMobilityDomain,
+ kFastBssTransition,
+ // TODO: RIC container? (can be several elements)
+ kDseRegisteredLocation,
+ kTimeoutInterval,
+ kHtCapabilities,
+ kHtOperation,
+ k2040BssCoex,
+ kOverlappingBssScanParams,
+ kExtCapabilities,
+ kBssMaxIdlePeriod,
+ kTimBroadcastResponse,
+ kFmsResponse,
+ kDmsResponse,
+ kQosMap,
+ kQmfPolicy,
+ kMultiband,
+ kDmgCapabilities,
+ kDmgOperation,
+ kMultipleMacSublayers,
+ kNeighborReport,
+ kVhtCapabilities,
+ kVhtOperation,
+ kOperatingModeNotification
+ // TODO: Future Channel Guidance (2-byte ID)
+};
+
+// IEEE Std 802.11-2016, 9.3.3.10
+static constexpr AllowedElement kProbeReqElements[] = {
+ Required(kSsid),
+ Required(kSuppRates),
+ kRequest,
+ kExtSuppRates,
+ kDsssParamSet,
+ kSuppOperatingClasses,
+ kHtCapabilities,
+ k2040BssCoex,
+ kExtCapabilities,
+ kSsidList,
+ kChannelUsage,
+ kInterworking,
+ kMeshId,
+ kMultiband,
+ kDmgCapabilities,
+ kMultipleMacSublayers,
+ kVhtCapabilities,
+ // TODO: Estimated Service Parameters (2-byte ID)
+ // TODO: Extended Request (2-byte ID)
+};
+
+// IEEE Std 802.11-2016, 9.3.3.11
+static constexpr AllowedElement kProbeRespElements[] = {
+ Required(kSsid),
+ Required(kSuppRates),
+ kDsssParamSet,
+ kCfParamSet,
+ kIbssParamSet,
+ kCountry,
+ kPowerConstraint,
+ kChannelSwitchAnn,
+ kQuiet,
+ kIbssDfs,
+ kTpcReport,
+ kErp,
+ kExtSuppRates,
+ kRsn,
+ kBssLoad,
+ kEdcaParamSet,
+ kMeasurementPilotTrans,
+ kMultipleBssid,
+ kRmEnabledCapabilities,
+ kApChannelReport,
+ kBssAvgAccessDelay,
+ kAntenna,
+ kBssAvailAdmissionCapacity,
+ kBssAcAccessDelay,
+ kMobilityDomain,
+ kDseRegisteredLocation,
+ kExtChannelSwitchAnn,
+ kSuppOperatingClasses,
+ kHtCapabilities,
+ kHtOperation,
+ k2040BssCoex,
+ kOverlappingBssScanParams,
+ kExtCapabilities,
+ kQosTrafficCapability,
+ kChannelUsage,
+ kTimeAdvertisement,
+ kTimeZone,
+ kInterworking,
+ kAdvertisementProtocol,
+ kRoamingConsortium,
+ kEmergencyAlertId,
+ kMeshId,
+ kMeshConfiguration,
+ kMeshAwakeWindow,
+ kBeaconTiming,
+ kMccaopAdvertisementOverview,
+ kMccaopAdvertisement,
+ kMeshChannelSwitchParams,
+ kQmfPolicy,
+ kQloadReport,
+ kMultiband,
+ kDmgCapabilities,
+ kDmgOperation,
+ kMultipleMacSublayers,
+ kAntennaSectorIdPattern,
+ kVhtCapabilities,
+ kVhtOperation,
+ kTransmitPowerEnvelope,
+ kChannelSwitchWrapper,
+ kExtBssLoad,
+ kQuietChannel,
+ kOperatingModeNotification,
+ kReducedNeighborReport,
+ kTvhtOperation,
+ // TODO: Estimated Service Parameters (2-byte ID)
+ kRelayCapabilities
+};
+
+// IEEE Std 802.11-2016, 9.3.3.12
+static constexpr AllowedElement kAuthElements[] = {
+ kChallengeText,
+ kRsn,
+ kMobilityDomain,
+ kFastBssTransition,
+ kTimeoutInterval
+ // TODO: RIC (can be several elements)
+};
+
+// IEEE Std 802.11-2016, 9.3.3.13
+static constexpr AllowedElement kDeauthElements[] = {
+ kManagementMic
+};
+
+// IEEE Std 802.11-2016, 9.3.3.16
+static constexpr AllowedElement kTimingAdElements[] = {
+ kCountry,
+ kPowerConstraint,
+ kTimeAdvertisement,
+ kExtCapabilities
+};
+
+
static void ValidateFixedSizeElement(size_t offset, Span<const uint8_t> body, size_t expected_size,
const char* element_name, ErrorAccumulator* errors) {
if (body.size() != expected_size) {
@@ -303,32 +550,58 @@
switch (mgmt_header->fc.subtype()) {
case kAssociationRequest:
+ ValidateFrameWithElements(r, sizeof(AssociationRequest), "Association Request",
+ kAssocReqElements, errors);
break;
case kAssociationResponse:
+ ValidateFrameWithElements(r, sizeof(AssociationResponse), "Association Response",
+ kAssocRespElements, errors);
break;
case kReassociationRequest:
+ ValidateFrameWithElements(r, sizeof(ReassociationRequest), "Reassociation Request",
+ kReassocReqElements, errors);
break;
case kReassociationResponse:
+ ValidateFrameWithElements(r, sizeof(ReassociationResponse), "Reassociation Response",
+ kReassocRespElements, errors);
break;
case kProbeRequest:
+ ValidateFrameWithElements(r, sizeof(ProbeRequest), "Probe Request",
+ kProbeReqElements, errors);
break;
case kProbeResponse:
+ ValidateFrameWithElements(r, sizeof(ProbeResponse), "Probe Response",
+ kProbeRespElements, errors);
break;
case kTimingAdvertisement:
+ ValidateFrameWithElements(r, sizeof(TimingAdvertisement), "Timing Advertisement",
+ kTimingAdElements, errors);
break;
case kBeacon:
ValidateFrameWithElements(r, sizeof(Beacon), "Beacon", kBeaconElements, errors);
break;
case kAtim:
+ if (r->RemainingBytes() > 0) {
+ errors->Add(r->ReadBytes(), "ATIM frame has a non-null body");
+ }
break;
case kDisassociation:
+ ValidateFrameWithElements(r, sizeof(Disassociation), "Disassociation",
+ kDisassocElements, errors);
break;
case kAuthentication:
+ // This will report a false positive if we attempt to write an auth frame
+ // with trailing non-element fields, e.g. "Finite Cyclic Group".
+ // If we get there one day, we can delete this check (or write a proper validator,
+ // which is probably not worth the effort, given how complicated the encoding is).
+ ValidateFrameWithElements(r, sizeof(Authentication), "Authentication",
+ kAuthElements, errors);
break;
case kDeauthentication:
+ ValidateFrameWithElements(r, sizeof(Deauthentication), "Deauthentication",
+ kDeauthElements, errors);
break;
case kAction:
- break;
case kActionNoAck:
break;
}