blob: 6ae4dc709ef9f103a97ed4867034a7da9df26e39 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import android.os.Parcelable;
import android.os.Parcel;
import java.util.BitSet;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* Describes information about a detected access point. In addition
* to the attributes described here, the supplicant keeps track of
* {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
* but does not currently report them to external clients.
*/
public class WifiParser {
public WifiParser() {}
/*
* {@hide}
*/
class IE {
int id;
byte data[];
}
private static final int VENDOR_SPECIFIC_IE = 221;
private static final int IEEE_RSN_IE = 48; //IEEE 2012 8.4.2.27
private static final int WPA_IE_VENDOR_TYPE = 0x0050f201; //WFA WPA vendor IE OUI/type
/*
* parse beacon or probe response frame and build the capabilities
* {@hide}
*
* This function is called so as to build the capabilities string of the scan result, hence it is called
* by AutoJoin controller when handling scan results that are coming from WifiScanner.
*
* It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, but build the
* ScanResult.capabilities String in a way that mirror the values returned by wpa_supplicant.
*
* Once the capabilities string is build, the ScanResult can be used be the system as if it was coming from supplicant.
*/
/* @hide
* */
static public String parse_akm(IE full_IE[], BitSet ieee_cap) {
boolean privacy = false;
boolean error = false;
if (ieee_cap == null)
return null;
if (full_IE == null)
return null;
privacy = ieee_cap.get(4);
String capabilities = "";
boolean rsne_found = false;
boolean wpa_found = false;
for (IE ie : full_IE) {
String security = "";
if (ie.id == IEEE_RSN_IE) {
rsne_found = true;
//parsing WPA2 capabilities
ByteBuffer buf = ByteBuffer.wrap(ie.data);
int total_len = ie.data.length;
int offset = 2;
//version
if ((total_len - offset) < 2) {
//not enough space for version field
security = "";
error = true;
break;
}
int val = 0;
if (0x0100 != buf.getShort(offset)) {
//incorrect version
security = "";
error = true;
break;
}
offset += 2;
//group cipher
if ((total_len - offset) < 4) {
security = ""; //parse error on group cipher suite
error = true;
break;
}
offset += 4; //skip the group cipher
security = "[WPA2"; //found the RSNE IE, hence start building the capability string
//pairwise cipher
if ((total_len - offset) < 2) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
val = buf.getShort(offset);
if ((total_len - offset) < (2 + val * 4)) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
offset += 2 + val * 4; //skip the pairwise ciphers
//AKM
if ((total_len - offset) < 2) {
security = ""; //parse error no AKM
error = true;
break;
}
val = buf.getShort(offset);
if ((total_len - offset) < (2 + val * 4)) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
offset += 2;
if (val == 0) {
security += "-EAP"; //default AKM
}
for (int i = 0; i < val; i++) {
int akm = buf.getInt(offset);
boolean found = false;
switch (akm) {
case 0x01ac0f00:
security += found ? "+" : "-" + "EAP";
found = true;
break;
case 0x02ac0f00:
security += found ? "+" : "-" + "PSK"; //PSK as 802.11-2012 11.6.1.2
found = true;
break;
case 0x03ac0f00:
security += found ? "+" : "-" + "FT/EAP";
found = true;
break;
case 0x04ac0f00:
security += found ? "+" : "-" + "FT/PSK";
found = true;
break;
case 0x06ac0f00:
security += found ? "+" : "-" + "PSK-SHA256";
found = true;
break;
case 0x05ac0f00:
security += found ? "+" : "-" + "EAP-SHA256";
found = true;
break;
}
offset += 4;
}
//we parsed what we want at this point
security += "]";
capabilities += security;
}
if (ie.id == VENDOR_SPECIFIC_IE) {
int total_len = ie.data.length;
int offset = 2;
//version
if ((total_len - offset) < 4) {
//not enough space for OUI and type field
security = "";
error = true;
break;
}
ByteBuffer buf = ByteBuffer.wrap(ie.data);
if (buf.getInt(offset) != 0x01F25000) {
//look for HS2.0 and WPA IE
security = "";
continue;
}
security = "[WPA"; //prep the string for WPA
//version
if ((total_len - offset) < 2) {
//not enough space for version field
security = "";
error = true;
break;
}
int val = 0;
if (0x0100 != buf.getShort(offset)) {
//incorrect version
security = "";
error = true;
break;
}
offset += 2;
//group cipher
if ((total_len - offset) < 4) {
security = ""; //parse error on group cipher suite
error = true;
break;
}
offset += 4; //skip the group cipher
//pairwise cipher
if ((total_len - offset) < 2) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
val = buf.getShort(offset);
if ((total_len - offset) < (2 + val * 4)) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
offset += 2 + val * 4; //skip the pairwise ciphers
//AKM
if ((total_len - offset) < 2) {
security = ""; //parse error no AKM
error = true;
break;
}
val = buf.getShort(offset);
if ((total_len - offset) < (2 + val * 4)) {
security = ""; //parse error no pairwise cipher
error = true;
break;
}
offset += 2;
if (val == 0) {
security += "-EAP"; //default AKM
}
for (int i = 0; i < val; i++) {
int akm = buf.getInt(offset);
boolean found = false;
switch (akm) {
case 0x01f25000:
security += found ? "+" : "-" + "EAP";
found = true;
break;
case 0x02f25000:
security += found ? "+" : "-" + "PSK"; //PSK as 802.11-2012 11.6.1.2
found = true;
break;
}
offset += 4;
}
//we parsed what we want at this point
security += "]";
}
}
if (rsne_found == false && wpa_found == false && privacy) {
//private Beacon without an RSNE or WPA IE, hence WEP0
capabilities += "[WEP]";
}
if (error)
return null;
else
return capabilities;
}
}