[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;
     }