Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 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;
     18 
     19 import android.os.Parcelable;
     20 import android.os.Parcel;
     21 
     22 import java.util.BitSet;
     23 
     24 import java.nio.ByteBuffer;
     25 
     26 import java.util.Date;
     27 
     28 /**
     29  * Describes information about a detected access point. In addition
     30  * to the attributes described here, the supplicant keeps track of
     31  * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
     32  * but does not currently report them to external clients.
     33  */
     34 public class WifiParser {
     35 
     36     public WifiParser() {}
     37 
     38 
     39     /*
     40      * {@hide}
     41      */
     42     class IE {
     43         int id;
     44         byte data[];
     45     }
     46 
     47     private static final int VENDOR_SPECIFIC_IE = 221;
     48     private static final int IEEE_RSN_IE = 48; //IEEE 2012 8.4.2.27
     49 
     50 
     51     private static final int WPA_IE_VENDOR_TYPE = 0x0050f201; //WFA WPA vendor IE OUI/type
     52 
     53     /*
     54      * parse beacon or probe response frame and build the capabilities
     55      * {@hide}
     56      *
     57      * This function is called so as to build the capabilities string of the scan result, hence it is called
     58      * by AutoJoin controller when handling scan results that are coming from WifiScanner.
     59      *
     60      * It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, but build the
     61      * ScanResult.capabilities String in a way that mirror the values returned by wpa_supplicant.
     62      *
     63      * Once the capabilities string is build, the ScanResult can be used be the system as if it was coming from supplicant.
     64      */
     65      /* @hide
     66      * */
     67     static public String parse_akm(IE full_IE[], BitSet ieee_cap) {
     68         boolean privacy = false;
     69         boolean error = false;
     70         if (ieee_cap == null)
     71             return null;
     72 
     73         if (full_IE == null)
     74             return null;
     75 
     76         privacy = ieee_cap.get(4);
     77 
     78         String capabilities = "";
     79         boolean rsne_found = false;
     80         boolean wpa_found = false;
     81 
     82         for (IE ie : full_IE) {
     83             String security = "";
     84             if (ie.id == IEEE_RSN_IE) {
     85                 rsne_found = true;
     86                 //parsing WPA2 capabilities
     87 
     88                 ByteBuffer buf = ByteBuffer.wrap(ie.data);
     89 
     90                 int total_len = ie.data.length;
     91                 int offset = 2;
     92 
     93                 //version
     94                 if ((total_len - offset) < 2) {
     95                     //not enough space for version field
     96                     security = "";
     97                     error = true;
     98                     break;
     99                 }
    100                 int val = 0;
    101                 if (0x0100 != buf.getShort(offset)) {
    102                     //incorrect version
    103                     security = "";
    104                     error = true;
    105                     break;
    106                 }
    107                 offset += 2;
    108 
    109 
    110                 //group cipher
    111                 if ((total_len - offset) < 4) {
    112                     security = ""; //parse error on group cipher suite
    113                     error = true;
    114                     break;
    115                 }
    116                 offset += 4; //skip the group cipher
    117 
    118                 security = "[WPA2"; //found the RSNE IE, hence start building the capability string
    119 
    120                 //pairwise cipher
    121                 if ((total_len - offset) < 2) {
    122                     security = ""; //parse error no pairwise cipher
    123                     error = true;
    124                     break;
    125                 }
    126                 val = buf.getShort(offset);
    127                 if ((total_len - offset) < (2 + val * 4)) {
    128                     security = ""; //parse error no pairwise cipher
    129                     error = true;
    130                     break;
    131                 }
    132                 offset += 2 + val * 4; //skip the pairwise ciphers
    133 
    134                 //AKM
    135                 if ((total_len - offset) < 2) {
    136                     security = ""; //parse error no AKM
    137                     error = true;
    138                     break;
    139                 }
    140                 val = buf.getShort(offset);
    141                 if ((total_len - offset) < (2 + val * 4)) {
    142                     security = ""; //parse error no pairwise cipher
    143                     error = true;
    144                     break;
    145                 }
    146                 offset += 2;
    147                 if (val == 0) {
    148                     security += "-EAP"; //default AKM
    149                 }
    150                 for (int i = 0; i < val; i++) {
    151                     int akm = buf.getInt(offset);
    152                     boolean found = false;
    153                     switch (akm) {
    154                         case 0x01ac0f00:
    155                             security += found ? "+" : "-" + "EAP";
    156                             found = true;
    157                             break;
    158                         case 0x02ac0f00:
    159                             security += found ? "+" : "-" + "PSK"; //PSK as 802.11-2012 11.6.1.2
    160                             found = true;
    161                             break;
    162                         case 0x03ac0f00:
    163                             security += found ? "+" : "-" + "FT/EAP";
    164                             found = true;
    165                             break;
    166                         case 0x04ac0f00:
    167                             security += found ? "+" : "-" + "FT/PSK";
    168                             found = true;
    169                             break;
    170                         case 0x06ac0f00:
    171                             security += found ? "+" : "-" + "PSK-SHA256";
    172                             found = true;
    173                             break;
    174                         case 0x05ac0f00:
    175                             security += found ? "+" : "-" + "EAP-SHA256";
    176                             found = true;
    177                             break;
    178                     }
    179                     offset += 4;
    180                 }
    181                 //we parsed what we want at this point
    182                 security += "]";
    183                 capabilities += security;
    184 
    185             }
    186 
    187             if (ie.id == VENDOR_SPECIFIC_IE) {
    188                 int total_len = ie.data.length;
    189                 int offset = 2;
    190 
    191                 //version
    192                 if ((total_len - offset) < 4) {
    193                     //not enough space for OUI and type field
    194                     security = "";
    195                     error = true;
    196                     break;
    197                 }
    198 
    199                 ByteBuffer buf = ByteBuffer.wrap(ie.data);
    200 
    201                 if (buf.getInt(offset) != 0x01F25000) {
    202                     //look for HS2.0 and WPA IE
    203                     security = "";
    204                     continue;
    205                 }
    206 
    207                 security = "[WPA"; //prep the string for WPA
    208 
    209                 //version
    210                 if ((total_len - offset) < 2) {
    211                     //not enough space for version field
    212                     security = "";
    213                     error = true;
    214                     break;
    215                 }
    216                 int val = 0;
    217                 if (0x0100 != buf.getShort(offset)) {
    218                     //incorrect version
    219                     security = "";
    220                     error = true;
    221                     break;
    222                 }
    223                 offset += 2;
    224 
    225 
    226                 //group cipher
    227                 if ((total_len - offset) < 4) {
    228                     security = ""; //parse error on group cipher suite
    229                     error = true;
    230                     break;
    231                 }
    232                 offset += 4; //skip the group cipher
    233 
    234 
    235                 //pairwise cipher
    236                 if ((total_len - offset) < 2) {
    237                     security = ""; //parse error no pairwise cipher
    238                     error = true;
    239                     break;
    240                 }
    241                 val = buf.getShort(offset);
    242                 if ((total_len - offset) < (2 + val * 4)) {
    243                     security = ""; //parse error no pairwise cipher
    244                     error = true;
    245                     break;
    246                 }
    247                 offset += 2 + val * 4; //skip the pairwise ciphers
    248 
    249                 //AKM
    250                 if ((total_len - offset) < 2) {
    251                     security = ""; //parse error no AKM
    252                     error = true;
    253                     break;
    254                 }
    255                 val = buf.getShort(offset);
    256                 if ((total_len - offset) < (2 + val * 4)) {
    257                     security = ""; //parse error no pairwise cipher
    258                     error = true;
    259                     break;
    260                 }
    261                 offset += 2;
    262                 if (val == 0) {
    263                     security += "-EAP"; //default AKM
    264                 }
    265                 for (int i = 0; i < val; i++) {
    266                     int akm = buf.getInt(offset);
    267                     boolean found = false;
    268                     switch (akm) {
    269                         case 0x01f25000:
    270                             security += found ? "+" : "-" + "EAP";
    271                             found = true;
    272                             break;
    273                         case 0x02f25000:
    274                             security += found ? "+" : "-" + "PSK"; //PSK as 802.11-2012 11.6.1.2
    275                             found = true;
    276                             break;
    277 
    278                     }
    279                     offset += 4;
    280                 }
    281                 //we parsed what we want at this point
    282                 security += "]";
    283             }
    284         }
    285 
    286         if (rsne_found == false && wpa_found == false && privacy) {
    287             //private Beacon without an RSNE or WPA IE, hence WEP0
    288             capabilities += "[WEP]";
    289         }
    290 
    291         if (error)
    292             return null;
    293         else
    294             return capabilities;
    295     }
    296 
    297 
    298 }
    299