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 (!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