Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2016 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 com.android.server.wifi.util;
     18 
     19 import static org.junit.Assert.assertArrayEquals;
     20 import static org.junit.Assert.assertEquals;
     21 import static org.junit.Assert.assertFalse;
     22 import static org.junit.Assert.assertTrue;
     23 
     24 import android.net.wifi.ScanResult.InformationElement;
     25 import android.test.suitebuilder.annotation.SmallTest;
     26 
     27 import com.android.server.wifi.hotspot2.NetworkDetail;
     28 
     29 import org.junit.Test;
     30 
     31 import java.io.ByteArrayOutputStream;
     32 import java.io.IOException;
     33 import java.util.Arrays;
     34 import java.util.BitSet;
     35 
     36 /**
     37  * Unit tests for {@link com.android.server.wifi.util.InformationElementUtil}.
     38  */
     39 @SmallTest
     40 public class InformationElementUtilTest {
     41 
     42     // SSID Information Element tags
     43     private static final byte[] TEST_SSID_BYTES_TAG = new byte[] { (byte) 0x00, (byte) 0x0B };
     44     // SSID Information Element entry used for testing.
     45     private static final byte[] TEST_SSID_BYTES = "GoogleGuest".getBytes();
     46     // Valid zero length tag.
     47     private static final byte[] TEST_VALID_ZERO_LENGTH_TAG =
     48             new byte[] { (byte) 0x0B, (byte) 0x00 };
     49     // BSS_LOAD Information Element entry used for testing.
     50     private static final byte[] TEST_BSS_LOAD_BYTES_IE =
     51             new byte[] { (byte) 0x0B, (byte) 0x01, (byte) 0x08 };
     52 
     53     /*
     54      * Function to provide SSID Information Element (SSID = "GoogleGuest").
     55      *
     56      * @return byte[] Byte array representing the test SSID
     57      */
     58     private byte[] getTestSsidIEBytes() throws IOException {
     59         return concatenateByteArrays(TEST_SSID_BYTES_TAG, TEST_SSID_BYTES);
     60     }
     61 
     62     /*
     63      * Function used to set byte arrays used for testing.
     64      *
     65      * @param byteArrays variable number of byte arrays to concatenate
     66      * @return byte[] Byte array resulting from concatenating the arrays passed to the function
     67      */
     68     private static byte[] concatenateByteArrays(byte[]... byteArrays) throws IOException {
     69         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
     70         for (byte[] b : byteArrays) {
     71             baos.write(b);
     72         }
     73         baos.flush();
     74         return baos.toByteArray();
     75     }
     76 
     77     /**
     78      * Test parseInformationElements with an empty byte array.
     79      * Expect parseInformationElement to return an empty InformationElement array.
     80      */
     81     @Test
     82     public void parseInformationElements_withEmptyByteArray() {
     83         byte[] emptyBytes = new byte[0];
     84         InformationElement[] results =
     85                 InformationElementUtil.parseInformationElements(emptyBytes);
     86         assertEquals("parsed results should be empty", 0, results.length);
     87     }
     88 
     89     /**
     90      * Test parseInformationElements called with a null parameter.
     91      * Expect parseInfomrationElement to return an empty InformationElement array.
     92      */
     93     @Test
     94     public void parseInformationElements_withNullBytes() {
     95         byte[] nullBytes = null;
     96         InformationElement[] results =
     97                 InformationElementUtil.parseInformationElements(nullBytes);
     98         assertEquals("parsed results should be empty", 0, results.length);
     99     }
    100 
    101     /*
    102      * Test parseInformationElements with a single element represented in the byte array.
    103      * Expect a single element to be returned in the InformationElements array.  The
    104      * length of this array should be 1 and the contents should be valid.
    105      *
    106      * @throws java.io.IOException
    107      */
    108     @Test
    109     public void parseInformationElements_withSingleElement() throws IOException {
    110         byte[] ssidBytes = getTestSsidIEBytes();
    111 
    112         InformationElement[] results =
    113                 InformationElementUtil.parseInformationElements(ssidBytes);
    114         assertEquals("Parsed results should have 1 IE", 1, results.length);
    115         assertEquals("Parsed result should be a ssid", InformationElement.EID_SSID, results[0].id);
    116         assertArrayEquals("parsed SSID does not match input",
    117                 TEST_SSID_BYTES, results[0].bytes);
    118     }
    119 
    120     /*
    121      * Test parseInformationElement with extra padding in the data to parse.
    122      * Expect the function to return the SSID information element.
    123      *
    124      * Note: Experience shows that APs often pad messages with 0x00.  This happens to be the tag for
    125      * EID_SSID.  This test checks if padding will be properly discarded.
    126      *
    127      * @throws java.io.IOException
    128      */
    129     @Test
    130     public void parseInformationElements_withExtraPadding() throws IOException {
    131         byte[] paddingBytes = new byte[10];
    132         Arrays.fill(paddingBytes, (byte) 0x00);
    133         byte[] ssidBytesWithPadding = concatenateByteArrays(getTestSsidIEBytes(), paddingBytes);
    134 
    135         InformationElement[] results =
    136                 InformationElementUtil.parseInformationElements(ssidBytesWithPadding);
    137         assertEquals("Parsed results should have 1 IE", 1, results.length);
    138         assertEquals("Parsed result should be a ssid", InformationElement.EID_SSID, results[0].id);
    139         assertArrayEquals("parsed SSID does not match input",
    140                 TEST_SSID_BYTES, results[0].bytes);
    141     }
    142 
    143     /*
    144      * Test parseInformationElement with two elements where the second element has an invalid
    145      * length.
    146      * Expect the function to return the first valid entry and skip the remaining information.
    147      *
    148      * Note:  This test partially exposes issues with blindly parsing the data.  A higher level
    149      * function to validate the parsed data may be added.
    150      *
    151      * @throws java.io.IOException
    152      * */
    153     @Test
    154     public void parseInformationElements_secondElementInvalidLength() throws IOException {
    155         byte[] invalidTag = new byte[] { (byte) 0x01, (byte) 0x08, (byte) 0x08 };
    156         byte[] twoTagsSecondInvalidBytes = concatenateByteArrays(getTestSsidIEBytes(), invalidTag);
    157 
    158         InformationElement[] results =
    159                 InformationElementUtil.parseInformationElements(twoTagsSecondInvalidBytes);
    160         assertEquals("Parsed results should have 1 IE", 1, results.length);
    161         assertEquals("Parsed result should be a ssid.", InformationElement.EID_SSID, results[0].id);
    162         assertArrayEquals("parsed SSID does not match input",
    163                 TEST_SSID_BYTES, results[0].bytes);
    164     }
    165 
    166     /*
    167      * Test parseInformationElements with two valid Information Element entries.
    168      * Expect the function to return an InformationElement array with two entries containing valid
    169      * data.
    170      *
    171      * @throws java.io.IOException
    172      */
    173     @Test
    174     public void parseInformationElements_twoElements() throws IOException {
    175         byte[] twoValidTagsBytes =
    176                 concatenateByteArrays(getTestSsidIEBytes(), TEST_BSS_LOAD_BYTES_IE);
    177 
    178         InformationElement[] results =
    179                 InformationElementUtil.parseInformationElements(twoValidTagsBytes);
    180         assertEquals("parsed results should have 2 elements", 2, results.length);
    181         assertEquals("First parsed element should be a ssid",
    182                 InformationElement.EID_SSID, results[0].id);
    183         assertArrayEquals("parsed SSID does not match input",
    184                 TEST_SSID_BYTES, results[0].bytes);
    185         assertEquals("second element should be a BSS_LOAD tag",
    186                 InformationElement.EID_BSS_LOAD, results[1].id);
    187         assertEquals("second element should have data of length 1", 1, results[1].bytes.length);
    188         assertEquals("second element data was not parsed correctly.",
    189                 (byte) 0x08, results[1].bytes[0]);
    190     }
    191 
    192     /*
    193      * Test parseInformationElements with two elements where the first information element has a
    194      * length of zero.
    195      * Expect the function to return an InformationElement array with two entries containing valid
    196      * data.
    197      *
    198      * @throws java.io.IOException
    199      */
    200     @Test
    201     public void parseInformationElements_firstElementZeroLength() throws IOException {
    202         byte[] zeroLengthTagWithSSIDBytes =
    203                 concatenateByteArrays(TEST_VALID_ZERO_LENGTH_TAG, getTestSsidIEBytes());
    204 
    205         InformationElement[] results =
    206                 InformationElementUtil.parseInformationElements(zeroLengthTagWithSSIDBytes);
    207         assertEquals("Parsed results should have 2 elements.", 2, results.length);
    208         assertEquals("First element tag should be EID_BSS_LOAD",
    209                 InformationElement.EID_BSS_LOAD, results[0].id);
    210         assertEquals("First element should be length 0", 0, results[0].bytes.length);
    211 
    212         assertEquals("Second element should be a ssid", InformationElement.EID_SSID, results[1].id);
    213         assertArrayEquals("parsed SSID does not match input",
    214                 TEST_SSID_BYTES, results[1].bytes);
    215     }
    216 
    217     /*
    218      * Test parseInformationElements with two elements where the first element has an invalid
    219      * length.  The invalid length in the first element causes us to miss the start of the second
    220      * Infomation Element.  This results in a single element in the returned array.
    221      * Expect the function to return a single entry in an InformationElement array. This returned
    222      * entry is not validated at this time and does not contain valid data (since the incorrect
    223      * length was used).
    224      * TODO: attempt to validate the data and recover as much as possible.  When the follow-on CL
    225      * is in development, this test will be updated to reflect the change.
    226      *
    227      * @throws java.io.IOException
    228      */
    229     @Test
    230     public void parseInformationElements_firstElementWrongLength() throws IOException {
    231         byte[] invalidLengthTag = new byte[] {(byte) 0x0B, (byte) 0x01 };
    232         byte[] invalidLengthTagWithSSIDBytes =
    233                 concatenateByteArrays(invalidLengthTag, getTestSsidIEBytes());
    234 
    235         InformationElement[] results =
    236                 InformationElementUtil.parseInformationElements(invalidLengthTagWithSSIDBytes);
    237         assertEquals("Parsed results should have 1 element", 1, results.length);
    238         assertEquals("First result should be a EID_BSS_LOAD tag.",
    239                 InformationElement.EID_BSS_LOAD, results[0].id);
    240         assertEquals("First result should have data of 1 byte", 1, results[0].bytes.length);
    241         assertEquals("First result should have data set to 0x00",
    242                 invalidLengthTagWithSSIDBytes[2], results[0].bytes[0]);
    243     }
    244 
    245     /**
    246      * Test Capabilities.generateCapabilitiesString() with a RSN IE.
    247      * Expect the function to return a string with the proper security information.
    248      */
    249     @Test
    250     public void buildCapabilities_rsnElement() {
    251         InformationElement ie = new InformationElement();
    252         ie.id = InformationElement.EID_RSN;
    253         ie.bytes = new byte[] { (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    254                                 (byte) 0xAC, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    255                                 (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x04,
    256                                 (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02,
    257                                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    258                                 (byte) 0xAC, (byte) 0x02, (byte) 0x00, (byte) 0x00 };
    259 
    260         InformationElement[] ies = new InformationElement[] { ie };
    261 
    262         BitSet beaconCap = new BitSet(16);
    263         beaconCap.set(4);
    264 
    265         InformationElementUtil.Capabilities capabilities =
    266                 new InformationElementUtil.Capabilities();
    267         capabilities.from(ies, beaconCap);
    268         String result = capabilities.generateCapabilitiesString();
    269 
    270         assertEquals("[WPA2-PSK-CCMP+TKIP]", result);
    271     }
    272 
    273     /**
    274      * Test Capabilities.generateCapabilitiesString() with a RSN IE which is malformed.
    275      * Expect the function to return a string with empty key management & pairswise cipher security
    276      * information.
    277      */
    278     @Test
    279     public void buildCapabilities_malformedRsnElement() {
    280         InformationElement ie = new InformationElement();
    281         ie.id = InformationElement.EID_RSN;
    282         ie.bytes = new byte[] { (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    283                 (byte) 0xAC, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    284                 (byte) 0x00, (byte) 0x0F, (byte) 0xAC };
    285 
    286         InformationElement[] ies = new InformationElement[] { ie };
    287 
    288         BitSet beaconCap = new BitSet(16);
    289         beaconCap.set(4);
    290 
    291         InformationElementUtil.Capabilities capabilities =
    292                 new InformationElementUtil.Capabilities();
    293         capabilities.from(ies, beaconCap);
    294         String result = capabilities.generateCapabilitiesString();
    295 
    296         assertEquals("[WPA2]", result);
    297     }
    298 
    299     /**
    300      * Test Capabilities.generateCapabilitiesString() with a WPA type 1 IE.
    301      * Expect the function to return a string with the proper security information.
    302      */
    303     @Test
    304     public void buildCapabilities_wpa1Element() {
    305         InformationElement ie = new InformationElement();
    306         ie.id = InformationElement.EID_VSA;
    307         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x01,
    308                                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    309                                 (byte) 0xF2, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    310                                 (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x04,
    311                                 (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x02,
    312                                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    313                                 (byte) 0xF2, (byte) 0x02, (byte) 0x00, (byte) 0x00 };
    314 
    315         InformationElement[] ies = new InformationElement[] { ie };
    316 
    317         BitSet beaconCap = new BitSet(16);
    318         beaconCap.set(4);
    319         InformationElementUtil.Capabilities capabilities =
    320                 new InformationElementUtil.Capabilities();
    321         capabilities.from(ies, beaconCap);
    322         String result = capabilities.generateCapabilitiesString();
    323 
    324         assertEquals("[WPA-PSK-CCMP+TKIP]", result);
    325     }
    326 
    327     /**
    328      * Test Capabilities.generateCapabilitiesString() with a WPA type 1 IE which is malformed.
    329      * Expect the function to return a string with empty key management & pairswise cipher security
    330      * information.
    331      */
    332     @Test
    333     public void buildCapabilities_malformedWpa1Element() {
    334         InformationElement ie = new InformationElement();
    335         ie.id = InformationElement.EID_VSA;
    336         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x01,
    337                 (byte) 0x01, (byte) 0x00 };
    338 
    339         InformationElement[] ies = new InformationElement[] { ie };
    340 
    341         BitSet beaconCap = new BitSet(16);
    342         beaconCap.set(4);
    343         InformationElementUtil.Capabilities capabilities =
    344                 new InformationElementUtil.Capabilities();
    345         capabilities.from(ies, beaconCap);
    346         String result = capabilities.generateCapabilitiesString();
    347 
    348         assertEquals("[WPA]", result);
    349     }
    350 
    351     /**
    352      * Test Capabilities.generateCapabilitiesString() with both RSN and WPA1 IE.
    353      * Expect the function to return a string with the proper security information.
    354      */
    355     @Test
    356     public void buildCapabilities_rsnAndWpaElement() {
    357         InformationElement ieRsn = new InformationElement();
    358         ieRsn.id = InformationElement.EID_RSN;
    359         ieRsn.bytes = new byte[] { (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    360                                    (byte) 0xAC, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    361                                    (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x04,
    362                                    (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02,
    363                                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    364                                    (byte) 0xAC, (byte) 0x02, (byte) 0x00, (byte) 0x00 };
    365 
    366         InformationElement ieWpa = new InformationElement();
    367         ieWpa.id = InformationElement.EID_VSA;
    368         ieWpa.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x01,
    369                                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    370                                    (byte) 0xF2, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    371                                    (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x04,
    372                                    (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x02,
    373                                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    374                                    (byte) 0xF2, (byte) 0x02, (byte) 0x00, (byte) 0x00 };
    375 
    376         InformationElement[] ies = new InformationElement[] { ieWpa, ieRsn };
    377 
    378         BitSet beaconCap = new BitSet(16);
    379         beaconCap.set(4);
    380 
    381         InformationElementUtil.Capabilities capabilities =
    382                 new InformationElementUtil.Capabilities();
    383         capabilities.from(ies, beaconCap);
    384         String result = capabilities.generateCapabilitiesString();
    385 
    386         assertEquals("[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP]", result);
    387     }
    388 
    389     /**
    390      * Test Capabilities.generateCapabilitiesString() with both RSN and WPA1 IE which are malformed.
    391      * Expect the function to return a string with empty key management & pairswise cipher security
    392      * information.
    393      */
    394     @Test
    395     public void buildCapabilities_malformedRsnAndWpaElement() {
    396         InformationElement ieRsn = new InformationElement();
    397         ieRsn.id = InformationElement.EID_RSN;
    398         ieRsn.bytes = new byte[] { (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F,
    399                 (byte) 0xAC, (byte) 0x02, (byte) 0x02 };
    400 
    401         InformationElement ieWpa = new InformationElement();
    402         ieWpa.id = InformationElement.EID_VSA;
    403         ieWpa.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x01,
    404                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    405                 (byte) 0xF2, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    406                 (byte) 0x00, (byte) 0x50 };
    407 
    408         InformationElement[] ies = new InformationElement[] { ieWpa, ieRsn };
    409 
    410         BitSet beaconCap = new BitSet(16);
    411         beaconCap.set(4);
    412 
    413         InformationElementUtil.Capabilities capabilities =
    414                 new InformationElementUtil.Capabilities();
    415         capabilities.from(ies, beaconCap);
    416         String result = capabilities.generateCapabilitiesString();
    417 
    418         assertEquals("[WPA][WPA2]", result);
    419     }
    420 
    421     /**
    422      * Test Capabilities.generateCapabilitiesString() with both WPS and WPA1 IE.
    423      * Expect the function to return a string with the proper security information.
    424      */
    425     @Test
    426     public void buildCapabilities_wpaAndWpsElement() {
    427         InformationElement ieWpa = new InformationElement();
    428         ieWpa.id = InformationElement.EID_VSA;
    429         ieWpa.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x01,
    430                                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    431                                    (byte) 0xF2, (byte) 0x02, (byte) 0x02, (byte) 0x00,
    432                                    (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x04,
    433                                    (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x02,
    434                                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x50,
    435                                    (byte) 0xF2, (byte) 0x02, (byte) 0x00, (byte) 0x00 };
    436 
    437         InformationElement ieWps = new InformationElement();
    438         ieWps.id = InformationElement.EID_VSA;
    439         ieWps.bytes = new byte[] { (byte) 0x00, (byte) 0x50, (byte) 0xF2, (byte) 0x04 };
    440 
    441         InformationElement[] ies = new InformationElement[] { ieWpa, ieWps };
    442 
    443         BitSet beaconCap = new BitSet(16);
    444         beaconCap.set(4);
    445 
    446 
    447         InformationElementUtil.Capabilities capabilities =
    448                  new InformationElementUtil.Capabilities();
    449         capabilities.from(ies, beaconCap);
    450         String result = capabilities.generateCapabilitiesString();
    451 
    452         assertEquals("[WPA-PSK-CCMP+TKIP][WPS]", result);
    453     }
    454 
    455     /**
    456      * Test Capabilities.generateCapabilitiesString() with a vendor specific element which
    457      * is not WPA type 1. Beacon Capability Information field has the Privacy
    458      * bit set.
    459      *
    460      * Expect the function to return a string with the proper security information.
    461      */
    462     @Test
    463     public void buildCapabilities_nonRsnWpa1Element_privacySet() {
    464         InformationElement ie = new InformationElement();
    465         ie.id = InformationElement.EID_VSA;
    466         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01,
    467                                 (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00,
    468                                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
    469 
    470         InformationElement[] ies = new InformationElement[] { ie };
    471 
    472         BitSet beaconCap = new BitSet(16);
    473         beaconCap.set(4);
    474 
    475         InformationElementUtil.Capabilities capabilities =
    476                 new InformationElementUtil.Capabilities();
    477         capabilities.from(ies, beaconCap);
    478         String result = capabilities.generateCapabilitiesString();
    479 
    480 
    481         assertEquals("[WEP]", result);
    482     }
    483 
    484     /**
    485      * Test Capabilities.generateCapabilitiesString() with a vendor specific element which
    486      * is not WPA type 1. Beacon Capability Information field doesn't have the
    487      * Privacy bit set.
    488      *
    489      * Expect the function to return an empty string.
    490      */
    491     @Test
    492     public void buildCapabilities_nonRsnWpa1Element_privacyClear() {
    493         InformationElement ie = new InformationElement();
    494         ie.id = InformationElement.EID_VSA;
    495         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01,
    496                                 (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00,
    497                                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
    498 
    499         InformationElement[] ies = new InformationElement[] { ie };
    500 
    501         BitSet beaconCap = new BitSet(16);
    502         beaconCap.clear(4);
    503 
    504         InformationElementUtil.Capabilities capabilities =
    505                 new InformationElementUtil.Capabilities();
    506         capabilities.from(ies, beaconCap);
    507         String result = capabilities.generateCapabilitiesString();
    508 
    509 
    510         assertEquals("", result);
    511     }
    512 
    513     /**
    514      * Test Capabilities.generateCapabilitiesString() with a vendor specific element which
    515      * is not WPA type 1. Beacon Capability Information field has the ESS bit set.
    516      *
    517      * Expect the function to return a string with [ESS] there.
    518      */
    519     @Test
    520     public void buildCapabilities_nonRsnWpa1Element_essSet() {
    521         InformationElement ie = new InformationElement();
    522         ie.id = InformationElement.EID_VSA;
    523         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01,
    524                                 (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00,
    525                                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
    526 
    527         InformationElement[] ies = new InformationElement[] { ie };
    528 
    529         BitSet beaconCap = new BitSet(16);
    530         beaconCap.set(0);
    531 
    532         InformationElementUtil.Capabilities capabilities =
    533                 new InformationElementUtil.Capabilities();
    534         capabilities.from(ies, beaconCap);
    535         String result = capabilities.generateCapabilitiesString();
    536 
    537 
    538         assertEquals("[ESS]", result);
    539     }
    540 
    541     /**
    542      * Test Capabilities.generateCapabilitiesString() with a vendor specific element which
    543      * is not WPA type 1. Beacon Capability Information field doesn't have the
    544      * ESS bit set.
    545      *
    546      * Expect the function to return an empty string.
    547      */
    548     @Test
    549     public void buildCapabilities_nonRsnWpa1Element_essClear() {
    550         InformationElement ie = new InformationElement();
    551         ie.id = InformationElement.EID_VSA;
    552         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x04, (byte) 0x0E, (byte) 0x01,
    553                                 (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x00,
    554                                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
    555 
    556         InformationElement[] ies = new InformationElement[] { ie };
    557 
    558         BitSet beaconCap = new BitSet(16);
    559         beaconCap.clear(0);
    560 
    561         InformationElementUtil.Capabilities capabilities =
    562                 new InformationElementUtil.Capabilities();
    563         capabilities.from(ies, beaconCap);
    564         String result = capabilities.generateCapabilitiesString();
    565 
    566 
    567         assertEquals("", result);
    568     }
    569 
    570     /**
    571      * Verify the expectations when building an ExtendedCapabilites IE from data with no bits set.
    572      * Both ExtendedCapabilities#isStrictUtf8() and ExtendedCapabilites#is80211McRTTResponder()
    573      * should return false.
    574      */
    575     @Test
    576     public void buildExtendedCapabilities_emptyBitSet() {
    577         InformationElement ie = new InformationElement();
    578         ie.id = InformationElement.EID_EXTENDED_CAPS;
    579         ie.bytes = new byte[8];
    580 
    581         InformationElementUtil.ExtendedCapabilities extendedCap =
    582                 new InformationElementUtil.ExtendedCapabilities();
    583         extendedCap.from(ie);
    584         assertFalse(extendedCap.isStrictUtf8());
    585         assertFalse(extendedCap.is80211McRTTResponder());
    586     }
    587 
    588     /**
    589      * Verify the expectations when building an ExtendedCapabilites IE from data with UTF-8 SSID
    590      * bit set (bit 48).  ExtendedCapabilities#isStrictUtf8() should return true.
    591      */
    592     @Test
    593     public void buildExtendedCapabilites_strictUtf8() {
    594         InformationElement ie = new InformationElement();
    595         ie.id = InformationElement.EID_EXTENDED_CAPS;
    596         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    597                                 (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00 };
    598 
    599         InformationElementUtil.ExtendedCapabilities extendedCap =
    600                 new InformationElementUtil.ExtendedCapabilities();
    601         extendedCap.from(ie);
    602         assertTrue(extendedCap.isStrictUtf8());
    603         assertFalse(extendedCap.is80211McRTTResponder());
    604     }
    605 
    606     /**
    607      * Verify the expectations when building an ExtendedCapabilites IE from data with RTT Response
    608      * Enable bit set (bit 70).  ExtendedCapabilities#is80211McRTTResponder() should return true.
    609      */
    610     @Test
    611     public void buildExtendedCapabilites_80211McRTTResponder() {
    612         InformationElement ie = new InformationElement();
    613         ie.id = InformationElement.EID_EXTENDED_CAPS;
    614         ie.bytes = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    615                                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    616                                 (byte) 0x40 };
    617 
    618         InformationElementUtil.ExtendedCapabilities extendedCap =
    619                 new InformationElementUtil.ExtendedCapabilities();
    620         extendedCap.from(ie);
    621         assertFalse(extendedCap.isStrictUtf8());
    622         assertTrue(extendedCap.is80211McRTTResponder());
    623     }
    624 
    625     /**
    626      * Test a that a correctly formed TIM Information Element is decoded into a valid TIM element,
    627      * and the values are captured
    628      */
    629     @Test
    630     public void parseTrafficIndicationMapInformationElementValid() {
    631         InformationElement ie = new InformationElement();
    632         ie.id = InformationElement.EID_TIM;
    633         ie.bytes = new byte[] { (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x00};
    634         InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
    635                 new InformationElementUtil.TrafficIndicationMap();
    636         trafficIndicationMap.from(ie);
    637         assertEquals(trafficIndicationMap.mLength, 4);
    638         assertEquals(trafficIndicationMap.mDtimCount, 3);
    639         assertEquals(trafficIndicationMap.mDtimPeriod, 5);
    640         assertEquals(trafficIndicationMap.mBitmapControl, 0);
    641         assertEquals(trafficIndicationMap.isValid(), true);
    642     }
    643 
    644     /**
    645      * Test that a short invalid Information Element is marked as being an invalid TIM element when
    646      * parsed as Traffic Indication Map.
    647      */
    648     @Test
    649     public void parseTrafficIndicationMapInformationElementInvalidTooShort() {
    650         InformationElement ie = new InformationElement();
    651         ie.id = InformationElement.EID_TIM;
    652         ie.bytes = new byte[] { (byte) 0x01, (byte) 0x07 };
    653         InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
    654                 new InformationElementUtil.TrafficIndicationMap();
    655         trafficIndicationMap.from(ie);
    656         assertEquals(trafficIndicationMap.isValid(), false);
    657     }
    658 
    659     /**
    660      * Test that a too-large invalid Information Element is marked as an invalid TIM element when
    661      * parsed as Traffic Indication Map.
    662      */
    663     @Test
    664     public void parseTrafficIndicationMapInformationElementInvalidTooLong() {
    665         InformationElement ie = new InformationElement();
    666         ie.id = InformationElement.EID_TIM;
    667         ie.bytes = new byte[255]; // bytes length of upto 254 is valid for TIM
    668         Arrays.fill(ie.bytes, (byte) 7);
    669         InformationElementUtil.TrafficIndicationMap trafficIndicationMap =
    670                 new InformationElementUtil.TrafficIndicationMap();
    671         trafficIndicationMap.from(ie);
    672         assertEquals(trafficIndicationMap.isValid(), false);
    673     }
    674 
    675     /**
    676      * Verify that the expected Roaming Consortium information element is parsed and retrieved
    677      * from the list of IEs.
    678      *
    679      * @throws Exception
    680      */
    681     @Test
    682     public void getRoamingConsortiumIE() throws Exception {
    683         InformationElement ie = new InformationElement();
    684         ie.id = InformationElement.EID_ROAMING_CONSORTIUM;
    685         /**
    686          * Roaming Consortium Format;
    687          * | Number of OIs | OI#1 and OI#2 Lengths | OI #1 | OI #2 (optional) | OI #3 (optional) |
    688          *        1                  1              variable     variable           variable
    689          */
    690         ie.bytes = new byte[] { (byte) 0x01 /* number of OIs */, (byte) 0x03 /* OI Length */,
    691                                 (byte) 0x11, (byte) 0x22, (byte) 0x33};
    692         InformationElementUtil.RoamingConsortium roamingConsortium =
    693                 InformationElementUtil.getRoamingConsortiumIE(new InformationElement[] {ie});
    694         assertEquals(1, roamingConsortium.anqpOICount);
    695         assertEquals(1, roamingConsortium.roamingConsortiums.length);
    696         assertEquals(0x112233, roamingConsortium.roamingConsortiums[0]);
    697     }
    698 
    699     /**
    700      * Verify that the expected Hotspot 2.0 Vendor Specific information element is parsed and
    701      * retrieved from the list of IEs.
    702      *
    703      * @throws Exception
    704      */
    705     @Test
    706     public void getHS2VendorSpecificIE() throws Exception {
    707         InformationElement ie = new InformationElement();
    708         ie.id = InformationElement.EID_VSA;
    709         /**
    710          * Vendor Specific OI Format:
    711          * | OI | Type | Hotspot Configuration | PPS MO ID (optional) | ANQP Domain ID (optional)
    712          *    3    1              1                    2                        2
    713          *
    714          * With OI=0x506F9A and Type=0x10 for Hotspot 2.0
    715          *
    716          * The Format of Hotspot Configuration:
    717          *        B0               B1                   B2             B3    B4              B7
    718          * | DGAF Disabled | PPS MO ID Flag | ANQP Domain ID Flag | reserved | Release Number |
    719          */
    720         ie.bytes = new byte[] { (byte) 0x50, (byte) 0x6F, (byte) 0x9A, (byte) 0x10,
    721                                 (byte) 0x14 /* Hotspot Configuration */, (byte) 0x11, (byte) 0x22};
    722         InformationElementUtil.Vsa vsa =
    723                 InformationElementUtil.getHS2VendorSpecificIE(new InformationElement[] {ie});
    724         assertEquals(NetworkDetail.HSRelease.R2, vsa.hsRelease);
    725         assertEquals(0x2211, vsa.anqpDomainID);
    726     }
    727 
    728     /**
    729      * Verify that the expected Interworking information element is parsed and retrieved from the
    730      * list of IEs.
    731      *
    732      * @throws Exception
    733      */
    734     @Test
    735     public void getInterworkingElementIE() throws Exception {
    736         InformationElement ie = new InformationElement();
    737         ie.id = InformationElement.EID_INTERWORKING;
    738         /**
    739          * Interworking Format:
    740          * | Access Network Option | Venue Info (optional) | HESSID (optional) |
    741          *           1                       2                     6
    742          *
    743          * Access Network Option Format:
    744          *
    745          * B0                   B3    B4       B5    B6     B7
    746          * | Access Network Type | Internet | ASRA | ESR | UESA |
    747          */
    748         ie.bytes = new byte[] { (byte) 0x10, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44,
    749                                 (byte) 0x55, (byte) 0x66 };
    750         InformationElementUtil.Interworking interworking =
    751                 InformationElementUtil.getInterworkingIE(new InformationElement[] {ie});
    752         assertTrue(interworking.internet);
    753         assertEquals(NetworkDetail.Ant.Private, interworking.ant);
    754         assertEquals(0x112233445566L, interworking.hessid);
    755     }
    756 }
    757