1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <general_test/basic_wifi_test.h>
18 
19 #include <algorithm>
20 #include <cinttypes>
21 #include <cmath>
22 
23 #include <shared/macros.h>
24 #include <shared/send_message.h>
25 #include <shared/time_util.h>
26 
27 #include "chre/util/nanoapp/log.h"
28 #include "chre/util/time.h"
29 #include "chre/util/unique_ptr.h"
30 #include "chre_api/chre.h"
31 
32 using nanoapp_testing::sendFatalFailureToHost;
33 using nanoapp_testing::sendFatalFailureToHostUint8;
34 using nanoapp_testing::sendSuccessToHost;
35 
36 #define LOG_TAG "[BasicWifiTest]"
37 
38 /*
39  * Test to check expected functionality of the CHRE WiFi APIs.
40  *
41  * 1. If scan monitor is not supported, skips to 3;
42  *    otherwise enables scan monitor.
43  * 2. Checks async result of enabling scan monitor.
44  * 3. If on demand WiFi scan is not supported, skips to 5;
45  *    otherwise sends default scan request.
46  * 4. Checks the result of on demand WiFi scan.
47  * 5. If scan monitor is supported then disables scan monitor;
48  *    otherwise go to step 7.
49  * 6. Checks async result of disabling scan monitor.
50  * 7. If a scan has ever happened runs the ranging test; otherwise
51  *    go to the end.
52  * 8. Checks the ranging test result.
53  * 9. end
54  */
55 namespace general_test {
56 
57 namespace {
58 
59 //! A fake/unused cookie to pass into the enable configure scan monitoring async
60 //! request.
61 constexpr uint32_t kEnableScanMonitoringCookie = 0x1337;
62 
63 //! A fake/unused cookie to pass into the disable configure scan monitoring
64 //! async request.
65 constexpr uint32_t kDisableScanMonitoringCookie = 0x1338;
66 
67 //! A fake/unused cookie to pass into request ranging async.
68 constexpr uint32_t kRequestRangingCookie = 0xefac;
69 
70 //! A fake/unused cookie to pass into request scan async.
71 constexpr uint32_t kOnDemandScanCookie = 0xcafe;
72 
73 //! Starting frequency of band 2.4 GHz
74 constexpr uint32_t kWifiBandStartFreq_2_4_GHz = 2407;
75 
76 //! Starting frequency of band 5 GHz
77 constexpr uint32_t kWifiBandStartFreq_5_GHz = 5000;
78 
79 //! Frequency of channel 14
80 constexpr uint32_t kWifiBandFreqOfChannel_14 = 2484;
81 
82 //! The amount of time to allow between an operation timing out and the event
83 //! being deliverd to the test.
84 constexpr uint32_t kTimeoutWiggleRoomNs = 2 * chre::kOneSecondInNanoseconds;
85 
86 // Number of seconds waited before retrying when an on demand wifi scan fails.
87 constexpr uint64_t kOnDemandScanTimeoutNs = 7 * chre::kOneSecondInNanoseconds;
88 
89 /**
90  * Calls API testConfigureScanMonitorAsync. Sends fatal failure to host
91  * if API call fails.
92  *
93  * @param enable Set to true to enable monitoring scan results,
94  *        false to disable.
95  * @param cookie An opaque value that will be included in the chreAsyncResult
96  *        sent in relation to this request.
97  */
testConfigureScanMonitorAsync(bool enable,const void * cookie)98 void testConfigureScanMonitorAsync(bool enable, const void *cookie) {
99   LOGI("Starts scan monitor configure test: %s", enable ? "enable" : "disable");
100   if (!chreWifiConfigureScanMonitorAsync(enable, cookie)) {
101     if (enable) {
102       sendFatalFailureToHost("Failed to request to enable scan monitor.");
103     } else {
104       sendFatalFailureToHost("Failed to request to disable scan monitor.");
105     }
106   }
107 }
108 
109 /**
110  * Calls API chreWifiRequestScanAsyncDefault. Sends fatal failure to host
111  * if API call fails.
112  */
testRequestScanAsync()113 void testRequestScanAsync() {
114   LOGI("Starts on demand scan test");
115   // Request a fresh scan to ensure the correct scan type is performed.
116   constexpr struct chreWifiScanParams kParams = {
117       /*.scanType=*/CHRE_WIFI_SCAN_TYPE_ACTIVE,
118       /*.maxScanAgeMs=*/0,  // 0 seconds
119       /*.frequencyListLen=*/0,
120       /*.frequencyList=*/NULL,
121       /*.ssidListLen=*/0,
122       /*.ssidList=*/NULL,
123       /*.radioChainPref=*/CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT,
124       /*.channelSet=*/CHRE_WIFI_CHANNEL_SET_NON_DFS};
125   if (!chreWifiRequestScanAsync(&kParams, &kOnDemandScanCookie)) {
126     sendFatalFailureToHost("Failed to request for on-demand WiFi scan.");
127   }
128 }
129 
130 /**
131  * Calls API chreWifiRequestRangingAsync. Sends fatal failure to host if the
132  * API call fails.
133  */
testRequestRangingAsync(const struct chreWifiScanResult * aps,uint8_t length)134 void testRequestRangingAsync(const struct chreWifiScanResult *aps,
135                              uint8_t length) {
136   LOGI("Starts ranging test");
137   // Sending an array larger than CHRE_WIFI_RANGING_LIST_MAX_LEN will cause
138   // an immediate failure.
139   uint8_t targetLength =
140       std::min(length, static_cast<uint8_t>(CHRE_WIFI_RANGING_LIST_MAX_LEN));
141 
142   auto targetList =
143       chre::MakeUniqueArray<struct chreWifiRangingTarget[]>(targetLength);
144   ASSERT_NE(targetList, nullptr,
145             "Failed to allocate array for issuing a ranging request");
146 
147   // Save the last spot for any available RTT APs in case they didn't make it
148   // in the array earlier. This first loop allows non-RTT compatible APs as a
149   // way to test that the driver implementation will return failure for only
150   // those APs and success for valid RTT APs.
151   for (uint8_t i = 0; i < targetLength - 1; i++) {
152     chreWifiRangingTargetFromScanResult(&aps[i], &targetList[i]);
153   }
154 
155   for (uint8_t i = targetLength - 1; i < length; i++) {
156     if ((aps[i].flags & CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER) ==
157             CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER ||
158         i == (length - 1)) {
159       chreWifiRangingTargetFromScanResult(&aps[i],
160                                           &targetList[targetLength - 1]);
161       break;
162     }
163   }
164 
165   struct chreWifiRangingParams params = {.targetListLen = targetLength,
166                                          .targetList = targetList.get()};
167   if (!chreWifiRequestRangingAsync(&params, &kRequestRangingCookie)) {
168     sendFatalFailureToHost(
169         "Failed to request ranging for a list of WiFi scans.");
170   }
171 }
172 
173 /**
174  * Validates primaryChannel and sends fatal failure to host if failing.
175  * 1. (primaryChannel - start frequecny) is a multiple of 5.
176  * 2. primaryChannelNumber is multiple of 5 and between [1, maxChannelNumber].
177  *
178  * @param primaryChannel primary channel of a WiFi scan result.
179  * @param startFrequency start frequency of band 2.4/5 GHz.
180  * @param maxChannelNumber max channel number of band 2.4/5 GHz.
181  */
validatePrimaryChannel(uint32_t primaryChannel,uint32_t startFrequency,uint8_t maxChannelNumber)182 void validatePrimaryChannel(uint32_t primaryChannel, uint32_t startFrequency,
183                             uint8_t maxChannelNumber) {
184   if ((primaryChannel - startFrequency) % 5 != 0) {
185     LOGE("primaryChannel - %" PRIu32
186          " must be a multiple of 5,"
187          "got primaryChannel: %" PRIu32,
188          startFrequency, primaryChannel);
189   }
190 
191   uint32_t primaryChannelNumber = (primaryChannel - startFrequency) / 5;
192   if (primaryChannelNumber < 1 || primaryChannelNumber > maxChannelNumber) {
193     LOGE("primaryChannelNumber must be between 1 and %" PRIu8
194          ","
195          "got primaryChannel: %" PRIu32,
196          maxChannelNumber, primaryChannel);
197   }
198 }
199 
200 /**
201  * Validates primaryChannel for band 2.4/5 GHz.
202  *
203  * primaryChannelNumber of band 2.4 GHz is between 1 and 13,
204  * plus a special case for channel 14 (primaryChannel == 2484);
205  * primaryChannelNumber of band 5 GHz is between 1 and 200,
206  * ref: IEEE Std 802.11-2016, 19.3.15.2.
207  * Also, (primaryChannel - start frequecny) is a multiple of 5,
208  * except channel 14 of 2.4 GHz.
209  *
210  * @param result WiFi scan result.
211  */
validatePrimaryChannel(const chreWifiScanResult & result)212 void validatePrimaryChannel(const chreWifiScanResult &result) {
213   // channel 14 (primaryChannel = 2484) is not applicable for this test.
214   if (result.band == CHRE_WIFI_BAND_2_4_GHZ &&
215       result.primaryChannel != kWifiBandFreqOfChannel_14) {
216     validatePrimaryChannel(result.primaryChannel, kWifiBandStartFreq_2_4_GHz,
217                            13);
218   } else if (result.band == CHRE_WIFI_BAND_5_GHZ) {
219     validatePrimaryChannel(result.primaryChannel, kWifiBandStartFreq_5_GHz,
220                            200);
221   }
222 }
223 
224 /**
225  * Validates centerFreqPrimary and centerFreqSecondary
226  * TODO (jacksun) add test when channelWidth is 20, 40, 80, or 160 MHz
227  */
validateCenterFreq(const chreWifiScanResult & result)228 void validateCenterFreq(const chreWifiScanResult &result) {
229   if (result.channelWidth != CHRE_WIFI_CHANNEL_WIDTH_80_PLUS_80_MHZ &&
230       result.centerFreqSecondary != 0) {
231     // TODO (jacksun) Format the centerFreqSecondary into the message
232     // after redesigning of sendFatalFailureToHost()
233     sendFatalFailureToHost(
234         "centerFreqSecondary must be 0 if channelWidth is not 80+80MHZ");
235   }
236 }
237 
238 /**
239  * Validates that RSSI is within sane limits.
240  */
validateRssi(int8_t rssi)241 void validateRssi(int8_t rssi) {
242   // It's possible for WiFi RSSI to be positive if the phone is placed
243   // right next to a high-power AP (e.g. transmitting at 20 dBm),
244   // in which case RSSI will be < 20 dBm. Place a high threshold to check
245   // against values likely to be erroneous (36 dBm/4W).
246   ASSERT_LT(rssi, 36, "RSSI is greater than 36");
247 }
248 
249 /**
250  * Validates that the amount of access points ranging was requested for matches
251  * the number of ranging results returned. Also, verifies that the BSSID of
252  * the each access point is present in the ranging results.
253  */
validateRangingEventArray(const struct chreWifiScanResult * results,size_t resultsSize,const struct chreWifiRangingEvent * event)254 void validateRangingEventArray(const struct chreWifiScanResult *results,
255                                size_t resultsSize,
256                                const struct chreWifiRangingEvent *event) {
257   size_t expectedArraySize = std::min(
258       resultsSize, static_cast<size_t>(CHRE_WIFI_RANGING_LIST_MAX_LEN));
259   ASSERT_EQ(event->resultCount, expectedArraySize,
260             "RTT ranging result count was not the same as the requested target "
261             "list size");
262 
263   uint8_t matchesFound = 0;
264 
265   for (size_t i = 0; i < resultsSize; i++) {
266     for (size_t j = 0; j < expectedArraySize; j++) {
267       if (memcmp(results[i].bssid, event->results[j].macAddress,
268                  CHRE_WIFI_BSSID_LEN) == 0) {
269         matchesFound++;
270         break;
271       }
272     }
273   }
274 
275   ASSERT_EQ(
276       matchesFound, expectedArraySize,
277       "BSSID(s) from the ranging request were not found in the ranging result");
278 }
279 
280 /**
281  * Validates the location configuration information returned by a ranging result
282  * is compliant with the formatting specified at @see chreWifiLci.
283  */
validateLci(const struct chreWifiRangingResult::chreWifiLci * lci)284 void validateLci(const struct chreWifiRangingResult::chreWifiLci *lci) {
285   // Per RFC 6225 2.3, there are 25 fractional bits and up to 9 integer bits
286   // used for lat / lng so verify that no bits outside those are used.
287   constexpr int64_t kMaxLat = INT64_C(90) << 25;
288   constexpr int64_t kMaxLng = INT64_C(180) << 25;
289   ASSERT_IN_RANGE(lci->latitude, -1 * kMaxLat, kMaxLat,
290                   "LCI's latitude is outside the range of -90 to 90");
291   ASSERT_IN_RANGE(lci->longitude, -1 * kMaxLng, kMaxLng,
292                   "LCI's longitude is outside the range of -180 to 180");
293 
294   // According to RFC 6225, values greater than 34 are reserved
295   constexpr uint8_t kMaxLatLngUncertainty = 34;
296   ASSERT_LE(lci->latitudeUncertainty, kMaxLatLngUncertainty,
297             "LCI's latitude uncertainty is greater than 34");
298   ASSERT_LE(lci->longitudeUncertainty, kMaxLatLngUncertainty,
299             "LCI's longitude uncertainty is greater than 34");
300 
301   if (lci->altitudeType == CHRE_WIFI_LCI_ALTITUDE_TYPE_METERS) {
302     // Highest largely populated city in the world, El Alto, Bolivia, is 4300
303     // meters and the tallest building in the world is 828 meters so the upper
304     // bound for this range should be 5500 meters (contains some padding).
305     constexpr int32_t kMaxAltitudeMeters = 5500 << 8;
306 
307     // Lowest largely populated city in the world, Baku, Azerbaijan, is 28
308     // meters below sea level so -100 meters should be a good lower bound.
309     constexpr int32_t kMinAltitudeMeters = (100 << 8) * -1;
310     ASSERT_IN_RANGE(
311         lci->altitude, kMinAltitudeMeters, kMaxAltitudeMeters,
312         "LCI's altitude is outside of the range of -25 to 500 meters");
313 
314     // According to RFC 6225, values greater than 30 are reserved
315     constexpr uint8_t kMaxAltitudeUncertainty = 30;
316     ASSERT_LE(lci->altitudeUncertainty, kMaxAltitudeUncertainty,
317               "LCI's altitude certainty is greater than 30");
318   } else if (lci->altitudeType == CHRE_WIFI_LCI_ALTITUDE_TYPE_FLOORS) {
319     // Tallest building has 163 floors. Assume -5 to 100 floors is a sane range.
320     constexpr int32_t kMaxAltitudeFloors = 100 << 8;
321     constexpr int32_t kMinAltitudeFloors = (5 << 8) * -1;
322     ASSERT_IN_RANGE(
323         lci->altitude, kMinAltitudeFloors, kMaxAltitudeFloors,
324         "LCI's altitude is outside of the range of -5 to 100 floors");
325   } else if (lci->altitudeType != CHRE_WIFI_LCI_ALTITUDE_TYPE_UNKNOWN) {
326     sendFatalFailureToHost(
327         "LCI's altitude type was not unknown, floors, or meters");
328   }
329 }
330 
331 }  // anonymous namespace
332 
BasicWifiTest()333 BasicWifiTest::BasicWifiTest() : Test(CHRE_API_VERSION_1_1) {}
334 
setUp(uint32_t messageSize,const void *)335 void BasicWifiTest::setUp(uint32_t messageSize, const void * /* message */) {
336   if (messageSize != 0) {
337     sendFatalFailureToHost("Expected 0 byte message, got more bytes:",
338                            &messageSize);
339   } else {
340     mWifiCapabilities = chreWifiGetCapabilities();
341     startScanMonitorTestStage();
342   }
343 }
344 
handleEvent(uint32_t,uint16_t eventType,const void * eventData)345 void BasicWifiTest::handleEvent(uint32_t /* senderInstanceId */,
346                                 uint16_t eventType, const void *eventData) {
347   ASSERT_NE(eventData, nullptr, "Received null eventData");
348   LOGI("Received event type %" PRIu16, eventType);
349   switch (eventType) {
350     case CHRE_EVENT_WIFI_ASYNC_RESULT:
351       handleChreWifiAsyncEvent(static_cast<const chreAsyncResult *>(eventData));
352       break;
353     case CHRE_EVENT_WIFI_SCAN_RESULT: {
354       if (!scanEventExpected()) {
355         sendFatalFailureToHost("WiFi scan event received when not requested");
356       }
357       const auto *result = static_cast<const chreWifiScanEvent *>(eventData);
358       LOGI("Received wifi scan result, result count: %" PRIu8,
359            result->resultCount);
360 
361       if (!isActiveWifiScanType(result)) {
362         LOGW("Received unexpected scan type %" PRIu8, result->scanType);
363       }
364 
365       // The first chreWifiScanResult is expected to come immediately,
366       // but a long delay is possible if it's implemented incorrectly,
367       // e.g. the async result comes right away (before the scan is actually
368       // completed), then there's a long delay to the scan result.
369       constexpr uint64_t maxDelayNs = 100 * chre::kOneMillisecondInNanoseconds;
370       bool delayExceeded = (mStartTimestampNs != 0) &&
371                            (chreGetTime() - mStartTimestampNs > maxDelayNs);
372       if (delayExceeded) {
373         sendFatalFailureToHost(
374             "Did not receive chreWifiScanResult within 100 milliseconds.");
375       }
376       // Do not reset mStartTimestampNs here, because it is used for the
377       // subsequent RTT ranging timestamp validation.
378       validateWifiScanEvent(result);
379       break;
380     }
381     case CHRE_EVENT_WIFI_RANGING_RESULT: {
382       if (!rangingEventExpected()) {
383         sendFatalFailureToHost(
384             "WiFi ranging event received when not requested");
385       }
386       const auto *result = static_cast<const chreWifiRangingEvent *>(eventData);
387       // Allow some wiggle room between the expected timeout and when the event
388       // would actually be delivered to the test.
389       if (mStartTimestampNs != 0 &&
390           chreGetTime() - mStartTimestampNs >
391               CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS + kTimeoutWiggleRoomNs) {
392         sendFatalFailureToHost(
393             "Did not receive chreWifiRangingEvent within the ranging timeout");
394       }
395       validateRangingEvent(result);
396       // Ensure timestamp is reset after everything is validated as it's used to
397       // validate the ranging event
398       mStartTimestampNs = 0;
399       mTestSuccessMarker.markStageAndSuccessOnFinish(
400           BASIC_WIFI_TEST_STAGE_SCAN_RTT);
401       break;
402     }
403     case CHRE_EVENT_TIMER: {
404       const uint32_t *timerHandle = static_cast<const uint32_t *>(eventData);
405       if (mScanTimeoutTimerHandle != CHRE_TIMER_INVALID &&
406           timerHandle == &mScanTimeoutTimerHandle) {
407         mScanTimeoutTimerHandle = CHRE_TIMER_INVALID;
408         startScanAsyncTestStage();
409       }
410       break;
411     }
412     default:
413       unexpectedEvent(eventType);
414       break;
415   }
416 }
417 
handleChreWifiAsyncEvent(const chreAsyncResult * result)418 void BasicWifiTest::handleChreWifiAsyncEvent(const chreAsyncResult *result) {
419   if (!mCurrentWifiRequest.has_value()) {
420     nanoapp_testing::sendFailureToHost("Unexpected async result");
421   }
422   LOGI("Received a wifi async event. request type: %" PRIu8
423        " error code: %" PRIu8,
424        result->requestType, result->errorCode);
425   if (result->requestType == CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN &&
426       !result->success && mNumScanRetriesRemaining > 0) {
427     LOGI("Wait for %" PRIu64 " seconds and try again",
428          kOnDemandScanTimeoutNs / chre::kOneSecondInNanoseconds);
429     mNumScanRetriesRemaining--;
430     mScanTimeoutTimerHandle = chreTimerSet(
431         /* duration= */ kOnDemandScanTimeoutNs, &mScanTimeoutTimerHandle,
432         /* oneShot= */ true);
433     return;
434   }
435   validateChreAsyncResult(result, mCurrentWifiRequest.value());
436   processChreWifiAsyncResult(result);
437 }
438 
processChreWifiAsyncResult(const chreAsyncResult * result)439 void BasicWifiTest::processChreWifiAsyncResult(const chreAsyncResult *result) {
440   switch (result->requestType) {
441     case CHRE_WIFI_REQUEST_TYPE_RANGING:
442       // Reuse same start timestamp as the scan request since ranging fields
443       // may be retrieved automatically as part of that scan.
444       break;
445     case CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN:
446       LOGI("Wifi scan result validated");
447       if (mScanTimeoutTimerHandle != CHRE_TIMER_INVALID) {
448         chreTimerCancel(mScanTimeoutTimerHandle);
449         mScanTimeoutTimerHandle = CHRE_TIMER_INVALID;
450       }
451       break;
452     case CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR:
453       if (mCurrentWifiRequest->cookie == &kDisableScanMonitoringCookie) {
454         mTestSuccessMarker.markStageAndSuccessOnFinish(
455             BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
456         mStartTimestampNs = chreGetTime();
457         startRangingAsyncTestStage();
458       } else {
459         startScanAsyncTestStage();
460       }
461       break;
462     default:
463       sendFatalFailureToHostUint8("Received unexpected requestType %d",
464                                   result->requestType);
465       break;
466   }
467 }
468 
isActiveWifiScanType(const chreWifiScanEvent * eventData)469 bool BasicWifiTest::isActiveWifiScanType(const chreWifiScanEvent *eventData) {
470   return (eventData->scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE);
471 }
472 
startScanMonitorTestStage()473 void BasicWifiTest::startScanMonitorTestStage() {
474   LOGI("startScanMonitorTestStage - Wifi capabilities: %" PRIu32,
475        mWifiCapabilities);
476   if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
477     testConfigureScanMonitorAsync(true /* enable */,
478                                   &kEnableScanMonitoringCookie);
479     resetCurrentWifiRequest(&kEnableScanMonitoringCookie,
480                             CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
481                             CHRE_ASYNC_RESULT_TIMEOUT_NS);
482   } else {
483     mTestSuccessMarker.markStageAndSuccessOnFinish(
484         BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
485     startScanAsyncTestStage();
486   }
487 }
488 
startScanAsyncTestStage()489 void BasicWifiTest::startScanAsyncTestStage() {
490   if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
491     testRequestScanAsync();
492     resetCurrentWifiRequest(&kOnDemandScanCookie,
493                             CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN,
494                             CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
495   } else if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
496     mTestSuccessMarker.markStageAndSuccessOnFinish(
497         BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
498     testConfigureScanMonitorAsync(false /* enable */,
499                                   &kDisableScanMonitoringCookie);
500     resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
501                             CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
502                             CHRE_ASYNC_RESULT_TIMEOUT_NS);
503   } else {
504     mTestSuccessMarker.markStageAndSuccessOnFinish(
505         BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
506     mStartTimestampNs = chreGetTime();
507     startRangingAsyncTestStage();
508   }
509 }
510 
startRangingAsyncTestStage()511 void BasicWifiTest::startRangingAsyncTestStage() {
512   // If no scans were received, the test has nothing to range with so simply
513   // mark it as a success.
514   if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_RTT_RANGING &&
515       mLatestWifiScanResults.size() != 0) {
516     testRequestRangingAsync(mLatestWifiScanResults.data(),
517                             mLatestWifiScanResults.size());
518     resetCurrentWifiRequest(&kRequestRangingCookie,
519                             CHRE_WIFI_REQUEST_TYPE_RANGING,
520                             CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
521   } else {
522     mTestSuccessMarker.markStageAndSuccessOnFinish(
523         BASIC_WIFI_TEST_STAGE_SCAN_RTT);
524   }
525 }
526 
resetCurrentWifiRequest(const void * cookie,uint8_t requestType,uint64_t timeoutNs)527 void BasicWifiTest::resetCurrentWifiRequest(const void *cookie,
528                                             uint8_t requestType,
529                                             uint64_t timeoutNs) {
530   chreAsyncRequest request = {.cookie = cookie,
531                               .requestType = requestType,
532                               .requestTimeNs = chreGetTime(),
533                               .timeoutNs = timeoutNs};
534   mCurrentWifiRequest = request;
535 }
536 
validateWifiScanEvent(const chreWifiScanEvent * eventData)537 void BasicWifiTest::validateWifiScanEvent(const chreWifiScanEvent *eventData) {
538   if (eventData->version != CHRE_WIFI_SCAN_EVENT_VERSION) {
539     sendFatalFailureToHostUint8("Got unexpected scan event version %d",
540                                 eventData->version);
541   }
542 
543   if (mNextExpectedIndex != eventData->eventIndex) {
544     LOGE("Expected index: %" PRIu32 ", received index: %" PRIu8,
545          mNextExpectedIndex, eventData->eventIndex);
546     sendFatalFailureToHost("Received out-of-order events");
547   }
548   mNextExpectedIndex++;
549 
550   if (eventData->eventIndex == 0) {
551     mWiFiScanResultRemaining = eventData->resultTotal;
552   }
553   if (mWiFiScanResultRemaining < eventData->resultCount) {
554     LOGE("Remaining scan results %" PRIu32 ", received %" PRIu8,
555          mWiFiScanResultRemaining, eventData->resultCount);
556     sendFatalFailureToHost("Received too many WiFi scan results");
557   }
558   mWiFiScanResultRemaining -= eventData->resultCount;
559 
560   validateWifiScanResult(eventData->resultCount, eventData->results);
561 
562   // Save the latest results for future tests retaining old data if the new
563   // scan is empty (so the test has something to use).
564   if (eventData->resultCount > 0) {
565     mLatestWifiScanResults.copy_array(eventData->results,
566                                       eventData->resultCount);
567   }
568 
569   LOGI("Remaining scan result is %" PRIu32, mWiFiScanResultRemaining);
570 
571   if (mWiFiScanResultRemaining == 0) {
572     mNextExpectedIndex = 0;
573     mTestSuccessMarker.markStageAndSuccessOnFinish(
574         BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
575     if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
576       testConfigureScanMonitorAsync(false /* enable */,
577                                     &kDisableScanMonitoringCookie);
578       resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
579                               CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
580                               CHRE_ASYNC_RESULT_TIMEOUT_NS);
581     } else {
582       mStartTimestampNs = chreGetTime();
583       startRangingAsyncTestStage();
584     }
585   }
586 }
587 
validateWifiScanResult(uint8_t count,const chreWifiScanResult * results)588 void BasicWifiTest::validateWifiScanResult(uint8_t count,
589                                            const chreWifiScanResult *results) {
590   for (uint8_t i = 0; i < count; ++i) {
591     if (results[i].ssidLen > CHRE_WIFI_SSID_MAX_LEN) {
592       sendFatalFailureToHostUint8("Got unexpected ssidLen %d",
593                                   results[i].ssidLen);
594     }
595 
596     // TODO: Enable fatal failures on band, RSSI, and primary channel
597     //       validations when proper error waiver is implemented in CHQTS.
598     if (results[i].band != CHRE_WIFI_BAND_2_4_GHZ &&
599         results[i].band != CHRE_WIFI_BAND_5_GHZ) {
600       LOGE("Got unexpected band %d", results[i].band);
601     }
602 
603     validateRssi(results[i].rssi);
604 
605     validatePrimaryChannel(results[i]);
606     validateCenterFreq(results[i]);
607   }
608 }
609 
validateRangingEvent(const chreWifiRangingEvent * eventData)610 void BasicWifiTest::validateRangingEvent(
611     const chreWifiRangingEvent *eventData) {
612   if (eventData->version != CHRE_WIFI_RANGING_EVENT_VERSION) {
613     sendFatalFailureToHostUint8("Got unexpected ranging event version %d",
614                                 eventData->version);
615   }
616 
617   validateRangingEventArray(mLatestWifiScanResults.data(),
618                             mLatestWifiScanResults.size(), eventData);
619 
620   for (uint8_t i = 0; i < eventData->resultCount; i++) {
621     auto &result = eventData->results[i];
622     auto currentTime = chreGetTime();
623     if (result.timestamp < mStartTimestampNs ||
624         result.timestamp > currentTime) {
625       LOGE("Invalid Ranging result timestamp = %" PRIu64 " (%" PRIu64
626            ", %" PRIu64 "). Status = %" PRIu8,
627            result.timestamp, mStartTimestampNs, currentTime, result.status);
628       sendFatalFailureToHost("Invalid ranging result timestamp");
629     }
630 
631     if (result.status != CHRE_WIFI_RANGING_STATUS_SUCCESS) {
632       if (result.rssi != 0 || result.distance != 0 ||
633           result.distanceStdDev != 0) {
634         sendFatalFailureToHost(
635             "Ranging result with failure status had non-zero state");
636       }
637     } else {
638       validateRssi(result.rssi);
639 
640       // TODO(b/289432591): Use sendFatalFailureToHost to check ranging distance
641       // results.
642       constexpr uint32_t kMaxDistanceMillimeters = 100 * 1000;
643       if (result.distance > kMaxDistanceMillimeters) {
644         LOGE("Ranging result was more than 100 meters away %" PRIu32,
645              result.distance);
646       }
647 
648       constexpr uint32_t kMaxStdDevMillimeters = 10 * 1000;
649       if (result.distanceStdDev > kMaxStdDevMillimeters) {
650         LOGE("Ranging result distance stddev was more than 10 meters %" PRIu32,
651              result.distanceStdDev);
652       }
653 
654       if (result.flags & CHRE_WIFI_RTT_RESULT_HAS_LCI) {
655         validateLci(&result.lci);
656       }
657     }
658   }
659 }
660 
rangingEventExpected()661 bool BasicWifiTest::rangingEventExpected() {
662   return mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_ASYNC) &&
663          !mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_RTT);
664 }
665 
scanEventExpected()666 bool BasicWifiTest::scanEventExpected() {
667   bool scanMonitoringFinished =
668       mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
669   bool onDemandScanFinished =
670       mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
671   if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
672     return !scanMonitoringFinished && !onDemandScanFinished;
673   } else {
674     return scanMonitoringFinished && !onDemandScanFinished;
675   }
676 }
677 
678 }  // namespace general_test
679