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(¶ms, &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 (mScanMonitorEnabled && !mNextScanResultWasRequested) {
355 LOGI(
356 "Ignoring scan monitor scan result while waiting on requested scan"
357 " result");
358 break;
359 }
360
361 if (!scanEventExpected()) {
362 sendFatalFailureToHost("WiFi scan event received when not requested");
363 }
364 const auto *result = static_cast<const chreWifiScanEvent *>(eventData);
365 LOGI("Received wifi scan result, result count: %" PRIu8,
366 result->resultCount);
367
368 if (!isActiveWifiScanType(result)) {
369 LOGW("Received unexpected scan type %" PRIu8, result->scanType);
370 }
371
372 // The first chreWifiScanResult is expected to come immediately,
373 // but a long delay is possible if it's implemented incorrectly,
374 // e.g. the async result comes right away (before the scan is actually
375 // completed), then there's a long delay to the scan result.
376 constexpr uint64_t maxDelayNs = 100 * chre::kOneMillisecondInNanoseconds;
377 bool delayExceeded = (mStartTimestampNs != 0) &&
378 (chreGetTime() - mStartTimestampNs > maxDelayNs);
379 if (delayExceeded) {
380 sendFatalFailureToHost(
381 "Did not receive chreWifiScanResult within 100 milliseconds.");
382 }
383 // Do not reset mStartTimestampNs here, because it is used for the
384 // subsequent RTT ranging timestamp validation.
385 validateWifiScanEvent(result);
386 break;
387 }
388 case CHRE_EVENT_WIFI_RANGING_RESULT: {
389 if (!rangingEventExpected()) {
390 sendFatalFailureToHost(
391 "WiFi ranging event received when not requested");
392 }
393 const auto *result = static_cast<const chreWifiRangingEvent *>(eventData);
394 // Allow some wiggle room between the expected timeout and when the event
395 // would actually be delivered to the test.
396 if (mStartTimestampNs != 0 &&
397 chreGetTime() - mStartTimestampNs >
398 CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS + kTimeoutWiggleRoomNs) {
399 sendFatalFailureToHost(
400 "Did not receive chreWifiRangingEvent within the ranging timeout");
401 }
402 validateRangingEvent(result);
403 // Ensure timestamp is reset after everything is validated as it's used to
404 // validate the ranging event
405 mStartTimestampNs = 0;
406 mTestSuccessMarker.markStageAndSuccessOnFinish(
407 BASIC_WIFI_TEST_STAGE_SCAN_RTT);
408 break;
409 }
410 case CHRE_EVENT_TIMER: {
411 const uint32_t *timerHandle = static_cast<const uint32_t *>(eventData);
412 if (mScanTimeoutTimerHandle != CHRE_TIMER_INVALID &&
413 timerHandle == &mScanTimeoutTimerHandle) {
414 mScanTimeoutTimerHandle = CHRE_TIMER_INVALID;
415 startScanAsyncTestStage();
416 }
417 break;
418 }
419 default:
420 unexpectedEvent(eventType);
421 break;
422 }
423 }
424
handleChreWifiAsyncEvent(const chreAsyncResult * result)425 void BasicWifiTest::handleChreWifiAsyncEvent(const chreAsyncResult *result) {
426 if (!mCurrentWifiRequest.has_value()) {
427 nanoapp_testing::sendFailureToHost("Unexpected async result");
428 }
429 LOGI("Received a wifi async event. request type: %" PRIu8
430 " error code: %" PRIu8,
431 result->requestType, result->errorCode);
432 if (result->requestType == CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN) {
433 if (result->success) {
434 mNextScanResultWasRequested = true;
435 } else if (mNumScanRetriesRemaining > 0) {
436 LOGI("Wait for %" PRIu64 " seconds and try again",
437 kOnDemandScanTimeoutNs / chre::kOneSecondInNanoseconds);
438 mNumScanRetriesRemaining--;
439 mScanTimeoutTimerHandle = chreTimerSet(
440 /* duration= */ kOnDemandScanTimeoutNs, &mScanTimeoutTimerHandle,
441 /* oneShot= */ true);
442 return;
443 }
444 }
445 validateChreAsyncResult(result, mCurrentWifiRequest.value());
446 processChreWifiAsyncResult(result);
447 }
448
processChreWifiAsyncResult(const chreAsyncResult * result)449 void BasicWifiTest::processChreWifiAsyncResult(const chreAsyncResult *result) {
450 switch (result->requestType) {
451 case CHRE_WIFI_REQUEST_TYPE_RANGING:
452 // Reuse same start timestamp as the scan request since ranging fields
453 // may be retrieved automatically as part of that scan.
454 break;
455 case CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN:
456 LOGI("Wifi scan result validated");
457 if (mScanTimeoutTimerHandle != CHRE_TIMER_INVALID) {
458 chreTimerCancel(mScanTimeoutTimerHandle);
459 mScanTimeoutTimerHandle = CHRE_TIMER_INVALID;
460 }
461 break;
462 case CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR:
463 if (mCurrentWifiRequest->cookie == &kDisableScanMonitoringCookie) {
464 if (result->success) {
465 mScanMonitorEnabled = false;
466 }
467 mTestSuccessMarker.markStageAndSuccessOnFinish(
468 BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
469 mStartTimestampNs = chreGetTime();
470 startRangingAsyncTestStage();
471 } else {
472 if (result->success) {
473 mScanMonitorEnabled = true;
474 }
475 startScanAsyncTestStage();
476 }
477 break;
478 default:
479 sendFatalFailureToHostUint8("Received unexpected requestType %d",
480 result->requestType);
481 break;
482 }
483 }
484
isActiveWifiScanType(const chreWifiScanEvent * eventData)485 bool BasicWifiTest::isActiveWifiScanType(const chreWifiScanEvent *eventData) {
486 return (eventData->scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE);
487 }
488
startScanMonitorTestStage()489 void BasicWifiTest::startScanMonitorTestStage() {
490 LOGI("startScanMonitorTestStage - Wifi capabilities: %" PRIu32,
491 mWifiCapabilities);
492 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
493 testConfigureScanMonitorAsync(true /* enable */,
494 &kEnableScanMonitoringCookie);
495 resetCurrentWifiRequest(&kEnableScanMonitoringCookie,
496 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
497 CHRE_ASYNC_RESULT_TIMEOUT_NS);
498 } else {
499 mTestSuccessMarker.markStageAndSuccessOnFinish(
500 BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
501 startScanAsyncTestStage();
502 }
503 }
504
startScanAsyncTestStage()505 void BasicWifiTest::startScanAsyncTestStage() {
506 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
507 testRequestScanAsync();
508 resetCurrentWifiRequest(&kOnDemandScanCookie,
509 CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN,
510 CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
511 } else if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
512 mTestSuccessMarker.markStageAndSuccessOnFinish(
513 BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
514 testConfigureScanMonitorAsync(false /* enable */,
515 &kDisableScanMonitoringCookie);
516 resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
517 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
518 CHRE_ASYNC_RESULT_TIMEOUT_NS);
519 } else {
520 mTestSuccessMarker.markStageAndSuccessOnFinish(
521 BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
522 mStartTimestampNs = chreGetTime();
523 startRangingAsyncTestStage();
524 }
525 }
526
startRangingAsyncTestStage()527 void BasicWifiTest::startRangingAsyncTestStage() {
528 // If no scans were received, the test has nothing to range with so simply
529 // mark it as a success.
530 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_RTT_RANGING &&
531 mLatestWifiScanResults.size() != 0) {
532 testRequestRangingAsync(mLatestWifiScanResults.data(),
533 mLatestWifiScanResults.size());
534 resetCurrentWifiRequest(&kRequestRangingCookie,
535 CHRE_WIFI_REQUEST_TYPE_RANGING,
536 CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
537 } else {
538 mTestSuccessMarker.markStageAndSuccessOnFinish(
539 BASIC_WIFI_TEST_STAGE_SCAN_RTT);
540 }
541 }
542
resetCurrentWifiRequest(const void * cookie,uint8_t requestType,uint64_t timeoutNs)543 void BasicWifiTest::resetCurrentWifiRequest(const void *cookie,
544 uint8_t requestType,
545 uint64_t timeoutNs) {
546 chreAsyncRequest request = {.cookie = cookie,
547 .requestType = requestType,
548 .requestTimeNs = chreGetTime(),
549 .timeoutNs = timeoutNs};
550 mCurrentWifiRequest = request;
551 }
552
validateWifiScanEvent(const chreWifiScanEvent * eventData)553 void BasicWifiTest::validateWifiScanEvent(const chreWifiScanEvent *eventData) {
554 if (eventData->version != CHRE_WIFI_SCAN_EVENT_VERSION) {
555 sendFatalFailureToHostUint8("Got unexpected scan event version %d",
556 eventData->version);
557 }
558
559 if (mNextExpectedIndex != eventData->eventIndex) {
560 LOGE("Expected index: %" PRIu32 ", received index: %" PRIu8,
561 mNextExpectedIndex, eventData->eventIndex);
562 sendFatalFailureToHost("Received out-of-order events");
563 }
564 mNextExpectedIndex++;
565
566 if (eventData->eventIndex == 0) {
567 mWiFiScanResultRemaining = eventData->resultTotal;
568 }
569 if (mWiFiScanResultRemaining < eventData->resultCount) {
570 LOGE("Remaining scan results %" PRIu32 ", received %" PRIu8,
571 mWiFiScanResultRemaining, eventData->resultCount);
572 sendFatalFailureToHost("Received too many WiFi scan results");
573 }
574 mWiFiScanResultRemaining -= eventData->resultCount;
575
576 validateWifiScanResult(eventData->resultCount, eventData->results);
577
578 // Save the latest results for future tests retaining old data if the new
579 // scan is empty (so the test has something to use).
580 if (eventData->resultCount > 0) {
581 mLatestWifiScanResults.copy_array(eventData->results,
582 eventData->resultCount);
583 }
584
585 LOGI("Remaining scan result is %" PRIu32, mWiFiScanResultRemaining);
586
587 if (mWiFiScanResultRemaining == 0) {
588 mNextExpectedIndex = 0;
589 mNextScanResultWasRequested = false;
590 mTestSuccessMarker.markStageAndSuccessOnFinish(
591 BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
592 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
593 testConfigureScanMonitorAsync(false /* enable */,
594 &kDisableScanMonitoringCookie);
595 resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
596 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
597 CHRE_ASYNC_RESULT_TIMEOUT_NS);
598 } else {
599 mStartTimestampNs = chreGetTime();
600 startRangingAsyncTestStage();
601 }
602 }
603 }
604
validateWifiScanResult(uint8_t count,const chreWifiScanResult * results)605 void BasicWifiTest::validateWifiScanResult(uint8_t count,
606 const chreWifiScanResult *results) {
607 for (uint8_t i = 0; i < count; ++i) {
608 if (results[i].ssidLen > CHRE_WIFI_SSID_MAX_LEN) {
609 sendFatalFailureToHostUint8("Got unexpected ssidLen %d",
610 results[i].ssidLen);
611 }
612
613 // TODO: Enable fatal failures on band, RSSI, and primary channel
614 // validations when proper error waiver is implemented in CHQTS.
615 if (results[i].band != CHRE_WIFI_BAND_2_4_GHZ &&
616 results[i].band != CHRE_WIFI_BAND_5_GHZ) {
617 LOGE("Got unexpected band %d", results[i].band);
618 }
619
620 validateRssi(results[i].rssi);
621
622 validatePrimaryChannel(results[i]);
623 validateCenterFreq(results[i]);
624 }
625 }
626
validateRangingEvent(const chreWifiRangingEvent * eventData)627 void BasicWifiTest::validateRangingEvent(
628 const chreWifiRangingEvent *eventData) {
629 if (eventData->version != CHRE_WIFI_RANGING_EVENT_VERSION) {
630 sendFatalFailureToHostUint8("Got unexpected ranging event version %d",
631 eventData->version);
632 }
633
634 validateRangingEventArray(mLatestWifiScanResults.data(),
635 mLatestWifiScanResults.size(), eventData);
636
637 for (uint8_t i = 0; i < eventData->resultCount; i++) {
638 auto &result = eventData->results[i];
639 auto currentTime = chreGetTime();
640 if (result.timestamp < mStartTimestampNs ||
641 result.timestamp > currentTime) {
642 LOGE("Invalid Ranging result timestamp = %" PRIu64 " (%" PRIu64
643 ", %" PRIu64 "). Status = %" PRIu8,
644 result.timestamp, mStartTimestampNs, currentTime, result.status);
645 sendFatalFailureToHost("Invalid ranging result timestamp");
646 }
647
648 if (result.status != CHRE_WIFI_RANGING_STATUS_SUCCESS) {
649 if (result.rssi != 0 || result.distance != 0 ||
650 result.distanceStdDev != 0) {
651 sendFatalFailureToHost(
652 "Ranging result with failure status had non-zero state");
653 }
654 } else {
655 validateRssi(result.rssi);
656
657 // TODO(b/289432591): Use sendFatalFailureToHost to check ranging distance
658 // results.
659 constexpr uint32_t kMaxDistanceMillimeters = 100 * 1000;
660 if (result.distance > kMaxDistanceMillimeters) {
661 LOGE("Ranging result was more than 100 meters away %" PRIu32,
662 result.distance);
663 }
664
665 constexpr uint32_t kMaxStdDevMillimeters = 10 * 1000;
666 if (result.distanceStdDev > kMaxStdDevMillimeters) {
667 LOGE("Ranging result distance stddev was more than 10 meters %" PRIu32,
668 result.distanceStdDev);
669 }
670
671 if (result.flags & CHRE_WIFI_RTT_RESULT_HAS_LCI) {
672 validateLci(&result.lci);
673 }
674 }
675 }
676 }
677
rangingEventExpected()678 bool BasicWifiTest::rangingEventExpected() {
679 return mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_ASYNC) &&
680 !mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_RTT);
681 }
682
scanEventExpected()683 bool BasicWifiTest::scanEventExpected() {
684 bool scanMonitoringFinished =
685 mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
686 bool onDemandScanFinished =
687 mTestSuccessMarker.isStageMarked(BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
688 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
689 return !scanMonitoringFinished && !onDemandScanFinished;
690 } else {
691 return scanMonitoringFinished && !onDemandScanFinished;
692 }
693 }
694
695 } // namespace general_test
696