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 package android.net.wifi;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.junit.Assert.assertArrayEquals;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.Mockito.validateMockitoUsage;
29 
30 import android.net.wifi.ScanResult.InformationElement;
31 import android.net.wifi.util.ScanResultUtil;
32 import android.os.Parcel;
33 
34 import androidx.test.filters.SmallTest;
35 
36 import com.android.dx.mockito.inline.extended.ExtendedMockito;
37 
38 import org.junit.After;
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.mockito.MockitoAnnotations;
42 import org.mockito.MockitoSession;
43 
44 import java.util.List;
45 import java.util.stream.Collectors;
46 
47 /**
48  * Unit tests for {@link android.net.wifi.WifiScanner}.
49  */
50 @SmallTest
51 public class ScanResultTest {
52     public static final String TEST_SSID = "\"test_ssid\"";
53     public static final String TEST_SSID_NON_UTF_8 = "b9c8b8e8";
54     public static final String TEST_BSSID = "04:ac:fe:45:34:10";
55     public static final String TEST_CAPS = "CCMP";
56     public static final int TEST_LEVEL = -56;
57     public static final int TEST_FREQUENCY = 2412;
58     public static final long TEST_TSF = 04660l;
59     public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
60             ScanResult.WIFI_STANDARD_11AC;
61     public static final String TEST_IFACE_NAME = "test_ifname";
62 
63     /**
64      * Frequency to channel map. This include some frequencies used outside the US.
65      * Representing it using a vector (instead of map) for simplification.
66      */
67     private static final int[] FREQUENCY_TO_CHANNEL_MAP = {
68             2412, WifiScanner.WIFI_BAND_24_GHZ, 1,
69             2417, WifiScanner.WIFI_BAND_24_GHZ, 2,
70             2422, WifiScanner.WIFI_BAND_24_GHZ, 3,
71             2427, WifiScanner.WIFI_BAND_24_GHZ, 4,
72             2432, WifiScanner.WIFI_BAND_24_GHZ, 5,
73             2437, WifiScanner.WIFI_BAND_24_GHZ, 6,
74             2442, WifiScanner.WIFI_BAND_24_GHZ, 7,
75             2447, WifiScanner.WIFI_BAND_24_GHZ, 8,
76             2452, WifiScanner.WIFI_BAND_24_GHZ, 9,
77             2457, WifiScanner.WIFI_BAND_24_GHZ, 10,
78             2462, WifiScanner.WIFI_BAND_24_GHZ, 11,
79             /* 12, 13 are only legitimate outside the US. */
80             2467, WifiScanner.WIFI_BAND_24_GHZ, 12,
81             2472, WifiScanner.WIFI_BAND_24_GHZ, 13,
82             /* 14 is for Japan, DSSS and CCK only. */
83             2484, WifiScanner.WIFI_BAND_24_GHZ, 14,
84             /* 34 valid in Japan. */
85             5170, WifiScanner.WIFI_BAND_5_GHZ, 34,
86             5180, WifiScanner.WIFI_BAND_5_GHZ, 36,
87             5190, WifiScanner.WIFI_BAND_5_GHZ, 38,
88             5200, WifiScanner.WIFI_BAND_5_GHZ, 40,
89             5210, WifiScanner.WIFI_BAND_5_GHZ, 42,
90             5220, WifiScanner.WIFI_BAND_5_GHZ, 44,
91             5230, WifiScanner.WIFI_BAND_5_GHZ, 46,
92             5240, WifiScanner.WIFI_BAND_5_GHZ, 48,
93             5260, WifiScanner.WIFI_BAND_5_GHZ, 52,
94             5280, WifiScanner.WIFI_BAND_5_GHZ, 56,
95             5300, WifiScanner.WIFI_BAND_5_GHZ, 60,
96             5320, WifiScanner.WIFI_BAND_5_GHZ, 64,
97             5500, WifiScanner.WIFI_BAND_5_GHZ, 100,
98             5520, WifiScanner.WIFI_BAND_5_GHZ, 104,
99             5540, WifiScanner.WIFI_BAND_5_GHZ, 108,
100             5560, WifiScanner.WIFI_BAND_5_GHZ, 112,
101             5580, WifiScanner.WIFI_BAND_5_GHZ, 116,
102             /* 120, 124, 128 valid in Europe/Japan. */
103             5600, WifiScanner.WIFI_BAND_5_GHZ, 120,
104             5620, WifiScanner.WIFI_BAND_5_GHZ, 124,
105             5640, WifiScanner.WIFI_BAND_5_GHZ, 128,
106             /* 132+ valid in US. */
107             5660, WifiScanner.WIFI_BAND_5_GHZ, 132,
108             5680, WifiScanner.WIFI_BAND_5_GHZ, 136,
109             5700, WifiScanner.WIFI_BAND_5_GHZ, 140,
110             /* 144 is supported by a subset of WiFi chips. */
111             5720, WifiScanner.WIFI_BAND_5_GHZ, 144,
112             5745, WifiScanner.WIFI_BAND_5_GHZ, 149,
113             5765, WifiScanner.WIFI_BAND_5_GHZ, 153,
114             5785, WifiScanner.WIFI_BAND_5_GHZ, 157,
115             5805, WifiScanner.WIFI_BAND_5_GHZ, 161,
116             5825, WifiScanner.WIFI_BAND_5_GHZ, 165,
117             5845, WifiScanner.WIFI_BAND_5_GHZ, 169,
118             5865, WifiScanner.WIFI_BAND_5_GHZ, 173,
119             /* Now some 6GHz channels */
120             5955, WifiScanner.WIFI_BAND_6_GHZ, 1,
121             5935, WifiScanner.WIFI_BAND_6_GHZ, 2,
122             5970, WifiScanner.WIFI_BAND_6_GHZ, 4,
123             6110, WifiScanner.WIFI_BAND_6_GHZ, 32
124     };
125 
126     /**
127      * Setup before tests.
128      */
129     @Before
setUp()130     public void setUp() throws Exception {
131         MockitoAnnotations.initMocks(this);
132     }
133 
134     /**
135      * Clean up after tests.
136      */
137     @After
cleanup()138     public void cleanup() {
139         validateMockitoUsage();
140     }
141 
142     /**
143      * Verify the logic that determines whether a frequency is PSC.
144      */
145     @Test
testIs6GHzPsc()146     public void testIs6GHzPsc() {
147         int test2G = 2412;
148         int test6GNonPsc = ScanResult.BAND_6_GHZ_PSC_START_MHZ
149                 + ScanResult.BAND_6_GHZ_PSC_STEP_SIZE_MHZ - 20;
150         int test6GPsc = ScanResult.BAND_6_GHZ_PSC_START_MHZ
151                 + ScanResult.BAND_6_GHZ_PSC_STEP_SIZE_MHZ;
152         assertFalse(ScanResult.is6GHzPsc(test2G));
153         assertFalse(ScanResult.is6GHzPsc(test6GNonPsc));
154         assertTrue(ScanResult.is6GHzPsc(test6GPsc));
155     }
156 
157     /**
158      * Verify parcel read/write for ScanResult.
159      */
160     @Test
verifyScanResultParcelWithoutRadioChainInfo()161     public void verifyScanResultParcelWithoutRadioChainInfo() throws Exception {
162         ScanResult writeScanResult = createScanResult();
163         ScanResult readScanResult = parcelReadWrite(writeScanResult);
164         assertScanResultEquals(writeScanResult, readScanResult);
165     }
166 
167     /**
168      * Verify parcel read/write for ScanResult with non-UTF-8 SSID.
169      */
170     @Test
verifyScanResultParcelWithNonUtf8Ssid()171     public void verifyScanResultParcelWithNonUtf8Ssid() throws Exception {
172         ScanResult writeScanResult = createScanResult();
173         writeScanResult.setWifiSsid(WifiSsid.fromString(TEST_SSID_NON_UTF_8));
174         ScanResult readScanResult = parcelReadWrite(writeScanResult);
175         assertScanResultEquals(writeScanResult, readScanResult);
176     }
177 
178 
179     /**
180      * Verify parcel read/write for ScanResult.
181      */
182     @Test
verifyScanResultParcelWithZeroRadioChainInfo()183     public void verifyScanResultParcelWithZeroRadioChainInfo() throws Exception {
184         ScanResult writeScanResult = createScanResult();
185         writeScanResult.radioChainInfos = new ScanResult.RadioChainInfo[0];
186         ScanResult readScanResult = parcelReadWrite(writeScanResult);
187         assertNull(readScanResult.radioChainInfos);
188     }
189 
190     /**
191      * Verify parcel read/write for ScanResult.
192      */
193     @Test
verifyScanResultParcelWithRadioChainInfo()194     public void verifyScanResultParcelWithRadioChainInfo() throws Exception {
195         ScanResult writeScanResult = createScanResult();
196         writeScanResult.radioChainInfos = new ScanResult.RadioChainInfo[2];
197         writeScanResult.radioChainInfos[0] = new ScanResult.RadioChainInfo();
198         writeScanResult.radioChainInfos[0].id = 0;
199         writeScanResult.radioChainInfos[0].level = -45;
200         writeScanResult.radioChainInfos[1] = new ScanResult.RadioChainInfo();
201         writeScanResult.radioChainInfos[1].id = 1;
202         writeScanResult.radioChainInfos[1].level = -54;
203         ScanResult readScanResult = parcelReadWrite(writeScanResult);
204         assertScanResultEquals(writeScanResult, readScanResult);
205     }
206 
207     /**
208      * Verify copy constructor for ScanResult.
209      */
210     @Test
verifyScanResultCopyWithoutRadioChainInfo()211     public void verifyScanResultCopyWithoutRadioChainInfo() throws Exception {
212         ScanResult scanResult = createScanResult();
213         ScanResult copyScanResult = new ScanResult(scanResult);
214         assertScanResultEquals(scanResult, copyScanResult);
215     }
216 
217     /**
218      * Verify copy constructor for ScanResult.
219      */
220     @Test
verifyScanResultCopyWithRadioChainInfo()221     public void verifyScanResultCopyWithRadioChainInfo() throws Exception {
222         ScanResult scanResult = createScanResult();
223         scanResult.radioChainInfos = new ScanResult.RadioChainInfo[2];
224         scanResult.radioChainInfos[0] = new ScanResult.RadioChainInfo();
225         scanResult.radioChainInfos[0].id = 0;
226         scanResult.radioChainInfos[0].level = -45;
227         scanResult.radioChainInfos[1] = new ScanResult.RadioChainInfo();
228         scanResult.radioChainInfos[1].id = 1;
229         scanResult.radioChainInfos[1].level = -54;
230         ScanResult copyScanResult = new ScanResult(scanResult);
231         assertScanResultEquals(scanResult, copyScanResult);
232     }
233 
234     /**
235      * Verify parcel read/write for ScanResult with Information Element
236      */
237     @Test
verifyScanResultParcelWithInformationElement()238     public void verifyScanResultParcelWithInformationElement() throws Exception {
239         ScanResult writeScanResult = createScanResult();
240         writeScanResult.informationElements = new ScanResult.InformationElement[2];
241         writeScanResult.informationElements[0] = new ScanResult.InformationElement();
242         writeScanResult.informationElements[0].id = InformationElement.EID_HT_OPERATION;
243         writeScanResult.informationElements[0].idExt = 0;
244         writeScanResult.informationElements[0].bytes = new byte[]{0x11, 0x22, 0x33};
245         writeScanResult.informationElements[1] = new ScanResult.InformationElement();
246         writeScanResult.informationElements[1].id = InformationElement.EID_EXTENSION_PRESENT;
247         writeScanResult.informationElements[1].idExt = InformationElement.EID_EXT_HE_OPERATION;
248         writeScanResult.informationElements[1].bytes = new byte[]{0x44, 0x55, 0x66};
249         ScanResult readScanResult = new ScanResult(writeScanResult);
250         assertScanResultEquals(writeScanResult, readScanResult);
251     }
252 
253     /**
254      * Verify toString for ScanResult.
255      */
256     @Test
verifyScanResultToStringWithoutRadioChainInfo()257     public void verifyScanResultToStringWithoutRadioChainInfo() throws Exception {
258         ScanResult scanResult = createScanResult();
259         assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
260                 + "level: -56, frequency: 2412, timestamp: 2480, "
261                 + "distance: 0(cm), distanceSd: 0(cm), "
262                 + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
263                 + "standard: 11ac, "
264                 + "80211mcResponder: is not supported, "
265                 + "80211azNtbResponder: is not supported, "
266                 + "TWT Responder: no, "
267                 + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString());
268     }
269 
270     /**
271      * Verify toString for ScanResult.
272      */
273     @Test
verifyScanResultToStringWithRadioChainInfo()274     public void verifyScanResultToStringWithRadioChainInfo() throws Exception {
275         ScanResult scanResult = createScanResult();
276         scanResult.radioChainInfos = new ScanResult.RadioChainInfo[2];
277         scanResult.radioChainInfos[0] = new ScanResult.RadioChainInfo();
278         scanResult.radioChainInfos[0].id = 0;
279         scanResult.radioChainInfos[0].level = -45;
280         scanResult.radioChainInfos[1] = new ScanResult.RadioChainInfo();
281         scanResult.radioChainInfos[1].id = 1;
282         scanResult.radioChainInfos[1].level = -54;
283         assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
284                 + "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), "
285                 + "distanceSd: 0(cm), "
286                 + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
287                 + "standard: 11ac, "
288                 + "80211mcResponder: is not supported, "
289                 + "80211azNtbResponder: is not supported, "
290                 + "TWT Responder: no, "
291                 + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, "
292                 + "RadioChainInfo: id=1, level=-54], interface name: test_ifname",
293                 scanResult.toString());
294     }
295 
296     /**
297      * Verify toString for ScanResult with non-UTF-8 SSID.
298      */
299     @Test
verifyScanResultToStringWithNonUtf8Ssid()300     public void verifyScanResultToStringWithNonUtf8Ssid() throws Exception {
301         ScanResult scanResult = createScanResult();
302         scanResult.setWifiSsid(WifiSsid.fromString(TEST_SSID_NON_UTF_8));
303         assertEquals("SSID: b9c8b8e8, BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
304                 + "level: -56, frequency: 2412, timestamp: 2480, "
305                 + "distance: 0(cm), distanceSd: 0(cm), "
306                 + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
307                 + "standard: 11ac, "
308                 + "80211mcResponder: is not supported, "
309                 + "80211azNtbResponder: is not supported, "
310                 + "TWT Responder: no, "
311                 + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString());
312     }
313 
314     /**
315      * verify frequency to channel conversion for all possible frequencies.
316      */
317     @Test
convertFrequencyToChannel()318     public void convertFrequencyToChannel() throws Exception {
319         for (int i = 0; i < FREQUENCY_TO_CHANNEL_MAP.length; i += 3) {
320             assertEquals(FREQUENCY_TO_CHANNEL_MAP[i + 2],
321                     ScanResult.convertFrequencyMhzToChannelIfSupported(
322                     FREQUENCY_TO_CHANNEL_MAP[i]));
323         }
324     }
325 
326     /**
327      * Verify frequency to channel conversion failed for an invalid frequency.
328      */
329     @Test
convertFrequencyToChannelWithInvalidFreq()330     public void convertFrequencyToChannelWithInvalidFreq() throws Exception {
331         assertEquals(-1, ScanResult.convertFrequencyMhzToChannelIfSupported(8000));
332     }
333 
334     /**
335      * Verify that getSecurityTypes returns the types derived from the generated security params
336      */
337     @Test
verifyGetSecurityTypesDerivedFromSecurityParams()338     public void verifyGetSecurityTypesDerivedFromSecurityParams() {
339         List<Integer> wifiConfigSecurityTypes = List.of(
340                 WifiConfiguration.SECURITY_TYPE_OPEN,
341                 WifiConfiguration.SECURITY_TYPE_WEP,
342                 WifiConfiguration.SECURITY_TYPE_PSK,
343                 WifiConfiguration.SECURITY_TYPE_EAP,
344                 WifiConfiguration.SECURITY_TYPE_SAE,
345                 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
346                 WifiConfiguration.SECURITY_TYPE_OWE,
347                 WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
348                 WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
349                 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
350                 WifiConfiguration.SECURITY_TYPE_OSEN,
351                 WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
352                 WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3);
353         List<SecurityParams> securityParamsList = wifiConfigSecurityTypes.stream()
354                 .map(SecurityParams::createSecurityParamsBySecurityType)
355                 .collect(Collectors.toList());
356         List<Integer> wifiInfoSecurityTypes = wifiConfigSecurityTypes.stream()
357                 .map(WifiInfo::convertWifiConfigurationSecurityType)
358                 .collect(Collectors.toList());
359 
360         MockitoSession session =
361                 ExtendedMockito.mockitoSession().spyStatic(ScanResultUtil.class).startMocking();
362         try {
363             ScanResult scanResult = new ScanResult();
364             scanResult.capabilities = "";
365             doReturn(securityParamsList).when(
366                     () -> ScanResultUtil.generateSecurityParamsListFromScanResult(scanResult));
367             assertThat(scanResult.getSecurityTypes())
368                     .asList().containsExactlyElementsIn(wifiInfoSecurityTypes);
369         } finally {
370             session.finishMocking();
371         }
372     }
373 
374     /**
375      * Write the provided {@link ScanResult} to a parcel and deserialize it.
376      */
parcelReadWrite(ScanResult writeResult)377     private static ScanResult parcelReadWrite(ScanResult writeResult) throws Exception {
378         Parcel parcel = Parcel.obtain();
379         writeResult.writeToParcel(parcel, 0);
380         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
381         return ScanResult.CREATOR.createFromParcel(parcel);
382     }
383 
createScanResult()384     private static ScanResult createScanResult() {
385         ScanResult result = new ScanResult();
386         result.setWifiSsid(WifiSsid.fromString(TEST_SSID));
387         result.BSSID = TEST_BSSID;
388         result.capabilities = TEST_CAPS;
389         result.level = TEST_LEVEL;
390         result.frequency = TEST_FREQUENCY;
391         result.timestamp = TEST_TSF;
392         result.setWifiStandard(TEST_WIFI_STANDARD);
393         result.ifaceName = TEST_IFACE_NAME;
394 
395         return result;
396     }
397 
assertScanResultEquals(ScanResult expected, ScanResult actual)398     private static void assertScanResultEquals(ScanResult expected, ScanResult actual) {
399         assertEquals(expected.SSID, actual.SSID);
400         assertEquals(expected.getWifiSsid(), actual.getWifiSsid());
401         assertEquals(expected.BSSID, actual.BSSID);
402         assertEquals(expected.capabilities, actual.capabilities);
403         assertEquals(expected.level, actual.level);
404         assertEquals(expected.frequency, actual.frequency);
405         assertEquals(expected.timestamp, actual.timestamp);
406         assertEquals(expected.getWifiStandard(), actual.getWifiStandard());
407         assertArrayEquals(expected.radioChainInfos, actual.radioChainInfos);
408         assertArrayEquals(expected.informationElements, actual.informationElements);
409     }
410 
411     /**
412      * Test ScanResult.getBand() function.
413      */
414     @Test
testScanResultGetBand()415     public void testScanResultGetBand() throws Exception {
416         ScanResult scanResult = createScanResult();
417         assertEquals(WifiScanner.WIFI_BAND_24_GHZ, scanResult.getBand());
418     }
419 
420     /**
421      * Test ScanResult.toBand() function.
422      */
423     @Test
testScanResultToBand()424     public void testScanResultToBand() throws Exception {
425         assertEquals(WifiScanner.WIFI_BAND_24_GHZ, ScanResult.toBand(TEST_FREQUENCY));
426     }
427 
428     /**
429      * Test ScanResult.getBandFromOpClass() function.
430      */
431     @Test
testScanResultGetBandFromOpCalss()432     public void testScanResultGetBandFromOpCalss() throws Exception {
433         assertEquals(WifiScanner.WIFI_BAND_24_GHZ, ScanResult.getBandFromOpClass(81, 11));
434         assertEquals(WifiScanner.WIFI_BAND_UNSPECIFIED, ScanResult.getBandFromOpClass(81, 36));
435         assertEquals(WifiScanner.WIFI_BAND_5_GHZ, ScanResult.getBandFromOpClass(120, 149));
436         assertEquals(WifiScanner.WIFI_BAND_6_GHZ, ScanResult.getBandFromOpClass(131, 32));
437     }
438 }
439