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