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 <chre.h>
20 #include <shared/send_message.h>
21 #include <shared/time_util.h>
22
23 using nanoapp_testing::kOneMillisecondInNanoseconds;
24 using nanoapp_testing::sendFatalFailureToHost;
25 using nanoapp_testing::sendFatalFailureToHostUint8;
26 using nanoapp_testing::sendSuccessToHost;
27
28 /*
29 * Test to check expected functionality of the CHRE WiFi APIs.
30 *
31 * 1. If scan monitor is not supported, skip to 5;
32 * otherwise enables scan monitor.
33 * 2. Checks async result of enabling scan monitor.
34 * 3. Disables scan monitor.
35 * 4. Checks async result of disabling scan monitor.
36 * 5. If on demand WiFi scan is not supported, skip to end;
37 * otherwise sends default scan request.
38 * 6. Checks the result of on demand WiFi scan.
39 */
40 namespace general_test {
41
42 namespace {
43
44 //! A dummy cookie to pass into the enable
45 //! configure scan monitoring async request.
46 constexpr uint32_t kEnableScanMonitoringCookie = 0x1337;
47
48 //! A dummy cookie to pass into the disable
49 //! configure scan monitoring async request.
50 constexpr uint32_t kDisableScanMonitoringCookie = 0x1338;
51
52 //! A dummy cookie to pass into request scan async.
53 constexpr uint32_t kOnDemandScanCookie = 0xcafe;
54
55 //! Starting frequency of band 2.4 GHz
56 constexpr uint32_t kWifiBandStartFreq_2_4_GHz = 2407;
57
58 //! Starting frequency of band 5 GHz
59 constexpr uint32_t kWifiBandStartFreq_5_GHz = 5000;
60
61 //! Frequency of channel 14
62 constexpr uint32_t kWifiBandFreqOfChannel_14 = 2484;
63
64 /**
65 * Calls API testConfigureScanMonitorAsync. Sends fatal failure to host
66 * if API call fails.
67 *
68 * @param enable Set to true to enable monitoring scan results,
69 * false to disable.
70 * @param cookie An opaque value that will be included in the chreAsyncResult
71 * sent in relation to this request.
72 */
testConfigureScanMonitorAsync(bool enable,const void * cookie)73 void testConfigureScanMonitorAsync(bool enable, const void * cookie) {
74 if (!chreWifiConfigureScanMonitorAsync(enable, cookie)) {
75 if (enable) {
76 sendFatalFailureToHost("Failed to request to enable scan monitor.");
77 } else {
78 sendFatalFailureToHost("Failed to request to disable scan monitor.");
79 }
80 }
81 }
82
83 /**
84 * Calls API chreWifiRequestScanAsyncDefault. Sends fatal failure to host
85 * if API call fails.
86 */
testRequestScanAsync()87 void testRequestScanAsync() {
88 if (!chreWifiRequestScanAsyncDefault(&kOnDemandScanCookie)) {
89 sendFatalFailureToHost("Failed to request for on-demand WiFi scan.");
90 }
91 }
92
93 /**
94 * Validates primaryChannel and sends fatal failure to host if failing.
95 * 1. (primaryChannel - start frequecny) is a multiple of 5.
96 * 2. primaryChannelNumber is multiple of 5 and between [1, maxChannelNumber].
97 *
98 * @param primaryChannel primary channel of a WiFi scan result.
99 * @param startFrequency start frequency of band 2.4/5 GHz.
100 * @param maxChannelNumber max channel number of band 2.4/5 GHz.
101 */
validatePrimaryChannel(uint32_t primaryChannel,uint32_t startFrequency,uint8_t maxChannelNumber)102 void validatePrimaryChannel(uint32_t primaryChannel,
103 uint32_t startFrequency,
104 uint8_t maxChannelNumber) {
105 if ((primaryChannel - startFrequency) % 5 != 0) {
106 chreLog(CHRE_LOG_ERROR,
107 "primaryChannel - %d must be a multiple of 5,"
108 "got primaryChannel: %d",
109 startFrequency, primaryChannel);
110 }
111
112 uint32_t primaryChannelNumber = (primaryChannel - startFrequency) / 5;
113 if (primaryChannelNumber < 1 || primaryChannelNumber > maxChannelNumber) {
114 chreLog(CHRE_LOG_ERROR,
115 "primaryChannelNumber must be between 1 and %d,"
116 "got primaryChannel: %d",
117 maxChannelNumber, primaryChannel);
118 }
119 }
120
121 /**
122 * Validates primaryChannel for band 2.4/5 GHz.
123 *
124 * primaryChannelNumber of band 2.4 GHz is between 1 and 13,
125 * plus a special case for channel 14 (primaryChannel == 2484);
126 * primaryChannelNumber of band 5 GHz is between 1 and 200,
127 * ref: IEEE Std 802.11-2016, 19.3.15.2.
128 * Also, (primaryChannel - start frequecny) is a multiple of 5,
129 * except channel 14 of 2.4 GHz.
130 *
131 * @param result WiFi scan result.
132 */
validatePrimaryChannel(const chreWifiScanResult & result)133 void validatePrimaryChannel(const chreWifiScanResult& result) {
134 // channel 14 (primaryChannel = 2484) is not applicable for this test.
135 if (result.band == CHRE_WIFI_BAND_2_4_GHZ &&
136 result.primaryChannel != kWifiBandFreqOfChannel_14) {
137 validatePrimaryChannel(result.primaryChannel,
138 kWifiBandStartFreq_2_4_GHz,
139 13);
140 } else if (result.band == CHRE_WIFI_BAND_5_GHZ) {
141 validatePrimaryChannel(result.primaryChannel,
142 kWifiBandStartFreq_5_GHz,
143 200);
144 }
145 }
146
147 /**
148 * Validates centerFreqPrimary and centerFreqSecondary
149 * TODO (jacksun) add test when channelWidth is 20, 40, 80, or 160 MHz
150 */
validateCenterFreq(const chreWifiScanResult & result)151 void validateCenterFreq(const chreWifiScanResult& result) {
152 if (result.channelWidth != CHRE_WIFI_CHANNEL_WIDTH_80_PLUS_80_MHZ
153 && result.centerFreqSecondary != 0) {
154 // TODO (jacksun) Format the centerFreqSecondary into the message
155 // after redesigning of sendFatalFailureToHost()
156 sendFatalFailureToHost(
157 "centerFreqSecondary must be 0 if channelWidth is not 80+80MHZ");
158 }
159 }
160
161 } // anonymous namespace
162
BasicWifiTest()163 BasicWifiTest::BasicWifiTest()
164 : Test(CHRE_API_VERSION_1_1) {
165 }
166
setUp(uint32_t messageSize,const void *)167 void BasicWifiTest::setUp(
168 uint32_t messageSize, const void * /* message */) {
169 if (messageSize != 0) {
170 sendFatalFailureToHost(
171 "Expected 0 byte message, got more bytes:", &messageSize);
172 } else {
173 mWifiCapabilities = chreWifiGetCapabilities();
174 startScanMonitorTestStage();
175 }
176 }
177
handleEvent(uint32_t,uint16_t eventType,const void * eventData)178 void BasicWifiTest::handleEvent(uint32_t /* senderInstanceId */,
179 uint16_t eventType,
180 const void *eventData) {
181 if (eventData == nullptr) {
182 sendFatalFailureToHost("Received null eventData");
183 }
184 switch (eventType) {
185 case CHRE_EVENT_WIFI_ASYNC_RESULT:
186 handleChreWifiAsyncEvent(
187 static_cast<const chreAsyncResult *>(eventData));
188 break;
189 case CHRE_EVENT_WIFI_SCAN_RESULT:
190 {
191 const auto *result = static_cast<const chreWifiScanEvent *>(eventData);
192 if (isActiveWifiScanType(result)) {
193 // The first chreWifiScanResult is expected to come immediately,
194 // but a long delay is possible if it's implemented incorrectly,
195 // e.g. the async result comes right away (before the scan is actually
196 // completed), then there's a long delay to the scan result.
197 if (mStartTimestampNs != 0
198 && chreGetTime() - mStartTimestampNs >
199 50 * kOneMillisecondInNanoseconds) {
200 sendFatalFailureToHost(
201 "Did not receive chreWifiScanResult within 50 milliseconds.");
202 }
203 mStartTimestampNs = 0;
204 validateWifiScanEvent(result);
205 }
206 }
207 break;
208 default:
209 unexpectedEvent(eventType);
210 break;
211 }
212 }
213
handleChreWifiAsyncEvent(const chreAsyncResult * result)214 void BasicWifiTest::handleChreWifiAsyncEvent(const chreAsyncResult *result) {
215 if (!mCurrentWifiRequest.has_value()) {
216 nanoapp_testing::sendFailureToHost("Unexpected async result");
217 }
218 validateChreAsyncResult(result, mCurrentWifiRequest.value());
219
220 switch (result->requestType) {
221 case CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN:
222 mStartTimestampNs = chreGetTime();
223 break;
224 case CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR:
225 if (mCurrentWifiRequest->cookie == &kDisableScanMonitoringCookie) {
226 mTestSuccessMarker.markStageAndSuccessOnFinish(
227 BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
228 startScanAsyncTestStage();
229 } else {
230 testConfigureScanMonitorAsync(false /* enable */,
231 &kDisableScanMonitoringCookie);
232 resetCurrentWifiRequest(&kDisableScanMonitoringCookie,
233 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
234 CHRE_ASYNC_RESULT_TIMEOUT_NS);
235 }
236 break;
237 default:
238 sendFatalFailureToHostUint8(
239 "Received unexpected requestType %d", result->requestType);
240 break;
241 }
242 }
243
isActiveWifiScanType(const chreWifiScanEvent * eventData)244 bool BasicWifiTest::isActiveWifiScanType(const chreWifiScanEvent *eventData) {
245 return (eventData->scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE);
246 }
247
startScanMonitorTestStage()248 void BasicWifiTest::startScanMonitorTestStage() {
249 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
250 testConfigureScanMonitorAsync(true /* enable */,
251 &kEnableScanMonitoringCookie);
252 resetCurrentWifiRequest(&kEnableScanMonitoringCookie,
253 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR,
254 CHRE_ASYNC_RESULT_TIMEOUT_NS);
255 } else {
256 mTestSuccessMarker.markStageAndSuccessOnFinish(
257 BASIC_WIFI_TEST_STAGE_SCAN_MONITOR);
258 startScanAsyncTestStage();
259 }
260 }
261
startScanAsyncTestStage()262 void BasicWifiTest::startScanAsyncTestStage() {
263 if (mWifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
264 testRequestScanAsync();
265 resetCurrentWifiRequest(&kOnDemandScanCookie,
266 CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN,
267 CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
268 } else {
269 mTestSuccessMarker.markStageAndSuccessOnFinish(
270 BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
271 }
272 }
273
resetCurrentWifiRequest(const void * cookie,uint8_t requestType,uint64_t timeoutNs)274 void BasicWifiTest::resetCurrentWifiRequest(const void *cookie,
275 uint8_t requestType,
276 uint64_t timeoutNs) {
277 chreAsyncRequest request = {
278 .cookie = cookie,
279 .requestType = requestType,
280 .requestTimeNs = chreGetTime(),
281 .timeoutNs = timeoutNs
282 };
283 mCurrentWifiRequest = request;
284 }
285
validateWifiScanEvent(const chreWifiScanEvent * eventData)286 void BasicWifiTest::validateWifiScanEvent(const chreWifiScanEvent *eventData) {
287 if (eventData->version != CHRE_WIFI_SCAN_EVENT_VERSION) {
288 sendFatalFailureToHostUint8(
289 "Got unexpected scan event version %d", eventData->version);
290 }
291
292 if (mNextExpectedIndex != eventData->eventIndex) {
293 chreLog(CHRE_LOG_ERROR, "Expected index: %d, received index: %d",
294 mNextExpectedIndex, eventData->eventIndex);
295 sendFatalFailureToHost("Received out-of-order events");
296 }
297 mNextExpectedIndex++;
298
299 if (eventData->eventIndex == 0) {
300 mWiFiScanResultRemaining = eventData->resultTotal;
301 }
302 if (mWiFiScanResultRemaining < eventData->resultCount) {
303 chreLog(CHRE_LOG_ERROR, "Remaining scan results %d, received %d",
304 mWiFiScanResultRemaining, eventData->resultCount);
305 sendFatalFailureToHost("Received too many WiFi scan results");
306 }
307 mWiFiScanResultRemaining -= eventData->resultCount;
308
309 validateWifiScanResult(eventData->resultCount, eventData->results);
310 if (mWiFiScanResultRemaining == 0) {
311 mNextExpectedIndex = 0;
312 mTestSuccessMarker.markStageAndSuccessOnFinish(
313 BASIC_WIFI_TEST_STAGE_SCAN_ASYNC);
314 }
315 }
316
validateWifiScanResult(uint8_t count,const chreWifiScanResult * results)317 void BasicWifiTest::validateWifiScanResult(
318 uint8_t count, const chreWifiScanResult *results) {
319 for (uint8_t i = 0; i < count; ++i) {
320 if (results[i].ssidLen > CHRE_WIFI_SSID_MAX_LEN) {
321 sendFatalFailureToHostUint8(
322 "Got unexpected ssidLen %d", results[i].ssidLen);
323 }
324
325 // TODO: Enable fatal failures on band, RSSI, and primary channel
326 // validations when proper error waiver is implemented in CHQTS.
327 if (results[i].band != CHRE_WIFI_BAND_2_4_GHZ
328 && results[i].band != CHRE_WIFI_BAND_5_GHZ) {
329 chreLog(CHRE_LOG_ERROR, "Got unexpected band %d", results[i].band);
330 }
331
332 // It's possible for WiFi RSSI be positive if the phone is placed
333 // right next to a high-power AP (e.g. transmitting at 20 dBm),
334 // in which case RSSI will be < 20 dBm. Place a high threshold to check
335 // against values likely to be erroneous (36 dBm/4W).
336 if (results[i].rssi >= 36) {
337 chreLog(CHRE_LOG_ERROR, "RSSI should be less than 36, got: %d",
338 results[i].rssi);
339 }
340
341 validatePrimaryChannel(results[i]);
342 validateCenterFreq(results[i]);
343 }
344 }
345
346 } // namespace general_test
347