InformationElementUtil.java revision 3571366ac36c70746b9f013ec2b54482861c9292
15d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills/* 25d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Copyright (C) 2015 The Android Open Source Project 35d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 45d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Licensed under the Apache License, Version 2.0 (the "License"); 55d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * you may not use this file except in compliance with the License. 65d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * You may obtain a copy of the License at 75d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 85d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * http://www.apache.org/licenses/LICENSE-2.0 95d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * 105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * Unless required by applicable law or agreed to in writing, software 115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * distributed under the License is distributed on an "AS IS" BASIS, 125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * See the License for the specific language governing permissions and 145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills * limitations under the License. 155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills */ 165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willspackage com.android.server.wifi.util; 175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 183571366ac36c70746b9f013ec2b54482861c9292Randy Panimport static com.android.server.wifi.anqp.Constants.getInteger; 193571366ac36c70746b9f013ec2b54482861c9292Randy Pan 205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.net.wifi.ScanResult.InformationElement; 215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport android.util.Log; 225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.anqp.Constants; 245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.anqp.VenueNameElement; 255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport com.android.server.wifi.hotspot2.NetworkDetail; 265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.net.ProtocolException; 283571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.nio.BufferUnderflowException; 295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteBuffer; 305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.nio.ByteOrder; 315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willsimport java.util.ArrayList; 323571366ac36c70746b9f013ec2b54482861c9292Randy Panimport java.util.BitSet; 335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Willspublic class InformationElementUtil { 355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static InformationElement[] parseInformationElements(byte[] bytes) { 37da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein if (bytes == null) { 38da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein return new InformationElement[0]; 39da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein } 405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); 415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ArrayList<InformationElement> infoElements = new ArrayList<>(); 435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills boolean found_ssid = false; 445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills while (data.remaining() > 1) { 455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int eid = data.get() & Constants.BYTE_MASK; 465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int elementLength = data.get() & Constants.BYTE_MASK; 475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 483571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (elementLength > data.remaining() || (eid == InformationElement.EID_SSID 493571366ac36c70746b9f013ec2b54482861c9292Randy Pan && found_ssid)) { 50da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // APs often pad the data with bytes that happen to match that of the EID_SSID 51da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // marker. This is not due to a known issue for APs to incorrectly send the SSID 52da51c12f413d54517aea317e37ba82e45d1e4a30Rebecca Silberstein // name multiple times. 535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 553571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (eid == InformationElement.EID_SSID) { 565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills found_ssid = true; 575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills InformationElement ie = new InformationElement(); 605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.id = eid; 615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ie.bytes = new byte[elementLength]; 625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills data.get(ie.bytes); 635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills infoElements.add(ie); 645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return infoElements.toArray(new InformationElement[infoElements.size()]); 665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class BssLoad { 705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int stationCount = 0; 715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelUtilization = 0; 725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int capacity = 0; 735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 753571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_BSS_LOAD) { 765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not BSS_LOAD, : " + ie.id); 775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length != 5) { 793571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("BSS Load element length is not 5: " 803571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.bytes.length); 815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills stationCount = data.getShort() & Constants.SHORT_MASK; 845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelUtilization = data.get() & Constants.BYTE_MASK; 855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills capacity = data.getShort() & Constants.SHORT_MASK; 865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class HtOperation { 905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int secondChannelOffset = 0; 915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 933571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (secondChannelOffset != 0) { 945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 1; 953571366ac36c70746b9f013ec2b54482861c9292Randy Pan } else { 965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0(int primaryFrequency) { 1019f743918a412fec9ad5a0386fbf6cf0361313f58xinhe //40 MHz 1029f743918a412fec9ad5a0386fbf6cf0361313f58xinhe if (secondChannelOffset != 0) { 1035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (secondChannelOffset == 1) { 1049f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency + 10; 1055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else if (secondChannelOffset == 3) { 1069f743918a412fec9ad5a0386fbf6cf0361313f58xinhe return primaryFrequency - 10; 1075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Log.e("HtOperation", "Error on secondChannelOffset: " + secondChannelOffset); 1095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1173571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_HT_OPERATION) { 1185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not HT_OPERATION, : " + ie.id); 1195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills secondChannelOffset = ie.bytes[1] & 0x3; 1215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class VhtOperation { 1255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int channelMode = 0; 1265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex1 = 0; 1275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int centerFreqIndex2 = 0; 1285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isValid() { 1305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode != 0; 1315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getChannelWidth() { 1345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return channelMode + 1; 1355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq0() { 1385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills //convert channel index to frequency in MHz, channel 36 is 5180MHz 1395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex1 - 36) * 5 + 5180; 1405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int getCenterFreq1() { 1433571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (channelMode > 1) { //160MHz 1445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return (centerFreqIndex2 - 36) * 5 + 5180; 1455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 1465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return 0; 1475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1513571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_VHT_OPERATION) { 1525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not VHT_OPERATION, : " + ie.id); 1535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills channelMode = ie.bytes[0] & Constants.BYTE_MASK; 1555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex1 = ie.bytes[1] & Constants.BYTE_MASK; 1565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills centerFreqIndex2 = ie.bytes[2] & Constants.BYTE_MASK; 1575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Interworking { 1615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.Ant ant = null; 1625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean internet = false; 1635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public VenueNameElement.VenueGroup venueGroup = null; 1645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public VenueNameElement.VenueType venueType = null; 1655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long hessid = 0L; 1665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 1683571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_INTERWORKING) { 1695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException("Element id is not INTERWORKING, : " + ie.id); 1705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 1725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int anOptions = data.get() & Constants.BYTE_MASK; 1735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ant = NetworkDetail.Ant.values()[anOptions & 0x0f]; 1745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills internet = (anOptions & 0x10) != 0; 1755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills // Len 1 none, 3 venue-info, 7 HESSID, 9 venue-info & HESSID 1765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 3 || ie.bytes.length == 9) { 1775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills try { 1785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer vinfo = data.duplicate(); 1795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills vinfo.limit(vinfo.position() + 2); 1805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills VenueNameElement vne = new VenueNameElement( 1815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Constants.ANQPElementType.ANQPVenueName, vinfo); 1825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills venueGroup = vne.getGroup(); 1835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills venueType = vne.getType(); 1845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } catch (ProtocolException pe) { 1855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills /*Cannot happen*/ 1865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else if (ie.bytes.length != 1 && ie.bytes.length != 7) { 1883571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Bad Interworking element length: " 1893571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.bytes.length); 1905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length == 7 || ie.bytes.length == 9) { 1925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hessid = getInteger(data, ByteOrder.BIG_ENDIAN, 6); 1935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 1965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 1975d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class RoamingConsortium { 1985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpOICount = 0; 1995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public long[] roamingConsortiums = null; 2005d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2023571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id != InformationElement.EID_ROAMING_CONSORTIUM) { 2033571366ac36c70746b9f013ec2b54482861c9292Randy Pan throw new IllegalArgumentException("Element id is not ROAMING_CONSORTIUM, : " 2043571366ac36c70746b9f013ec2b54482861c9292Randy Pan + ie.id); 2055d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2065d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2075d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpOICount = data.get() & Constants.BYTE_MASK; 2085d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2095d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi12Length = data.get() & Constants.BYTE_MASK; 2105d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi1Length = oi12Length & Constants.NIBBLE_MASK; 2115d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi2Length = (oi12Length >>> 4) & Constants.NIBBLE_MASK; 2125d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oi3Length = ie.bytes.length - 2 - oi1Length - oi2Length; 2135d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int oiCount = 0; 2145d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0) { 2155d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2165d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0) { 2175d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2185d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0) { 2195d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills oiCount++; 2205d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2215d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2225d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2235d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums = new long[oiCount]; 2245d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi1Length > 0 && roamingConsortiums.length > 0) { 2255d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[0] = 2265d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi1Length); 2275d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2285d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi2Length > 0 && roamingConsortiums.length > 1) { 2295d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[1] = 2305d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi2Length); 2315d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2325d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (oi3Length > 0 && roamingConsortiums.length > 2) { 2335d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills roamingConsortiums[2] = 2345d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills getInteger(data, ByteOrder.BIG_ENDIAN, oi3Length); 2355d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2365d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2375d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2385d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2395d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class Vsa { 2405d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int ANQP_DOMID_BIT = 0x04; 2415d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2425d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public NetworkDetail.HSRelease hsRelease = null; 2435d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP. 2445d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2455d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2465d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2475d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) { 2485d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int hsConf = data.get() & Constants.BYTE_MASK; 2495d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills switch ((hsConf >> 4) & Constants.NIBBLE_MASK) { 2505d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 0: 2515d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R1; 2525d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills case 1: 2545d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.R2; 2555d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2565d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills default: 2575d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills hsRelease = NetworkDetail.HSRelease.Unknown; 2585d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills break; 2595d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2605d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if ((hsConf & ANQP_DOMID_BIT) != 0) { 2615d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills if (ie.bytes.length < 7) { 2625d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills throw new IllegalArgumentException( 2635d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills "HS20 indication element too short: " + ie.bytes.length); 2645d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2655d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills anqpDomainID = data.getShort() & Constants.SHORT_MASK; 2665d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2675d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2685d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2695d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2705d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2715d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public static class ExtendedCapabilities { 2725d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final int RTT_RESP_ENABLE_BIT = 70; 2735d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills private static final long SSID_UTF8_BIT = 0x0001000000000000L; 2745d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2755d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public Long extendedCapabilities = null; 2765d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean is80211McRTTResponder = false; 2775d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2785d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities() { 2795d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2805d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2815d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public ExtendedCapabilities(ExtendedCapabilities other) { 2825d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = other.extendedCapabilities; 2835d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = other.is80211McRTTResponder; 2845d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2855d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2865d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public boolean isStrictUtf8() { 2875d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills return extendedCapabilities != null && (extendedCapabilities & SSID_UTF8_BIT) != 0; 2885d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 2895d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2905d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills public void from(InformationElement ie) { 2915d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 2925d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills extendedCapabilities = 2935d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills Constants.getInteger(data, ByteOrder.LITTLE_ENDIAN, ie.bytes.length); 2945d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills 2955d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills int index = RTT_RESP_ENABLE_BIT / 8; 2965d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills byte offset = RTT_RESP_ENABLE_BIT % 8; 2973571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.bytes.length < index + 1) { 2985d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills is80211McRTTResponder = false; 2995d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } else { 3003571366ac36c70746b9f013ec2b54482861c9292Randy Pan is80211McRTTResponder = (ie.bytes[index] & ((byte) 0x1 << offset)) != 0; 3015d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3025d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3035d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills } 3043571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3053571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 3063571366ac36c70746b9f013ec2b54482861c9292Randy Pan * parse beacon to build the capabilities 3073571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 3083571366ac36c70746b9f013ec2b54482861c9292Randy Pan * This class is used to build the capabilities string of the scan results coming 3093571366ac36c70746b9f013ec2b54482861c9292Randy Pan * from HAL. It parses the ieee beacon's capability field, WPA and RSNE IE as per spec, 3103571366ac36c70746b9f013ec2b54482861c9292Randy Pan * and builds the ScanResult.capabilities String in a way that mirrors the values returned 3113571366ac36c70746b9f013ec2b54482861c9292Randy Pan * by wpa_supplicant. 3123571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 3133571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static class Capabilities { 3143571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int CAP_PRIVACY_BIT_OFFSET = 4; 3153571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3163571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_VENDOR_OUI_TYPE_ONE = 0x01f25000; 3173571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short WPA_VENDOR_OUI_VERSION = 0x0001; 3183571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final short RSNE_VERSION = 0x0001; 3193571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3203571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_EAP = 0x01f25000; 3213571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA_AKM_PSK = 0x02f25000; 3223571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3233571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP = 0x01ac0f00; 3243571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK = 0x02ac0f00; 3253571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_EAP = 0x03ac0f00; 3263571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_FT_PSK = 0x04ac0f00; 3273571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_EAP_SHA256 = 0x05ac0f00; 3283571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static final int WPA2_AKM_PSK_SHA256 = 0x06ac0f00; 3293571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3303571366ac36c70746b9f013ec2b54482861c9292Randy Pan public Capabilities() { 3313571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3323571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3333571366ac36c70746b9f013ec2b54482861c9292Randy Pan // RSNE format (size unit: byte) 3343571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | Version | Group Data Cipher Suite | 3363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 2 4 3373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 3383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 3393571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | RSN Capabilities | 3403571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 2 3413571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | PMKID Count | PMKID List | Group Management Cipher Suite | 3423571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 16 * s 4 3433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 3443571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 3453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 3463571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static String parseRsnElement(InformationElement ie) { 3473571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 3483571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3493571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 3503571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 3513571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != RSNE_VERSION) { 3523571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 3533571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 3543571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3553571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3563571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 3573571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance the buffer position 3583571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 3593571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3603571366ac36c70746b9f013ec2b54482861c9292Randy Pan // found the RSNE IE, hence start building the capability string 3613571366ac36c70746b9f013ec2b54482861c9292Randy Pan String security = "[WPA2"; 3623571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3633571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 3643571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 3653571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3663571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite list 3673571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 3683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance the buffer position 3693571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 3703571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3713571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3723571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 3733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 3743571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 3753571366ac36c70746b9f013ec2b54482861c9292Randy Pan 3763571366ac36c70746b9f013ec2b54482861c9292Randy Pan // parse AKM suite list 3773571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (akmCount == 0) { 3783571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "-EAP"; //default AKM 3793571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 3803571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean found = false; 3813571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 3823571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 3833571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 3843571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP: 3853571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP"; 3863571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3873571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3883571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK: 3893571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK"; 3903571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3913571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3923571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_EAP: 3933571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "FT/EAP"; 3943571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3953571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 3963571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_FT_PSK: 3973571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "FT/PSK"; 3983571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 3993571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4003571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_EAP_SHA256: 4013571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP-SHA256"; 4023571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4033571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4043571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA2_AKM_PSK_SHA256: 4053571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK-SHA256"; 4063571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4073571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4083571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4093571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4103571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4113571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4123571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4133571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4143571366ac36c70746b9f013ec2b54482861c9292Randy Pan // we parsed what we want at this point 4153571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "]"; 4163571366ac36c70746b9f013ec2b54482861c9292Randy Pan return security; 4173571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4183571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow"); 4193571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 4203571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4213571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4223571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4233571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static boolean isWpaOneElement(InformationElement ie) { 4243571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4253571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4263571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4273571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA OUI and type 4283571366ac36c70746b9f013ec2b54482861c9292Randy Pan return (buf.getInt() == WPA_VENDOR_OUI_TYPE_ONE); 4293571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 4303571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse VSA IE, buffer underflow"); 4313571366ac36c70746b9f013ec2b54482861c9292Randy Pan return false; 4323571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4333571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4343571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4353571366ac36c70746b9f013ec2b54482861c9292Randy Pan // WPA type 1 format (size unit: byte) 4363571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4373571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Element ID | Length | OUI | Type | Version | 4383571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 1 1 3 1 2 4393571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | Pairwise Cipher Suite Count | Pairwise Cipher Suite List | 4403571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * m 4413571366ac36c70746b9f013ec2b54482861c9292Randy Pan // | AKM Suite Count | AKM Suite List | 4423571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 2 4 * n 4433571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4443571366ac36c70746b9f013ec2b54482861c9292Randy Pan // Note: InformationElement.bytes has 'Element ID' and 'Length' 4453571366ac36c70746b9f013ec2b54482861c9292Randy Pan // stripped off already 4463571366ac36c70746b9f013ec2b54482861c9292Randy Pan // 4473571366ac36c70746b9f013ec2b54482861c9292Randy Pan private static String parseWpaOneElement(InformationElement ie) { 4483571366ac36c70746b9f013ec2b54482861c9292Randy Pan ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN); 4493571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4503571366ac36c70746b9f013ec2b54482861c9292Randy Pan try { 4513571366ac36c70746b9f013ec2b54482861c9292Randy Pan // skip WPA OUI and type parsing. isWpaOneElement() should have 4523571366ac36c70746b9f013ec2b54482861c9292Randy Pan // been called for verification before we reach here. 4533571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4543571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4553571366ac36c70746b9f013ec2b54482861c9292Randy Pan // start building the string 4563571366ac36c70746b9f013ec2b54482861c9292Randy Pan String security = "[WPA"; 4573571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4583571366ac36c70746b9f013ec2b54482861c9292Randy Pan // version 4593571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (buf.getShort() != WPA_VENDOR_OUI_VERSION) { 4603571366ac36c70746b9f013ec2b54482861c9292Randy Pan // incorrect version 4613571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 4623571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4633571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4643571366ac36c70746b9f013ec2b54482861c9292Randy Pan // group data cipher suite 4653571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance buffer position 4663571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4673571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4683571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise cipher suite count 4693571366ac36c70746b9f013ec2b54482861c9292Randy Pan short cipherCount = buf.getShort(); 4703571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4713571366ac36c70746b9f013ec2b54482861c9292Randy Pan // pairwise chipher suite list 4723571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < cipherCount; i++) { 4733571366ac36c70746b9f013ec2b54482861c9292Randy Pan // here we simply advance buffer position 4743571366ac36c70746b9f013ec2b54482861c9292Randy Pan buf.getInt(); 4753571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4763571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4773571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM 4783571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite count 4793571366ac36c70746b9f013ec2b54482861c9292Randy Pan short akmCount = buf.getShort(); 4803571366ac36c70746b9f013ec2b54482861c9292Randy Pan 4813571366ac36c70746b9f013ec2b54482861c9292Randy Pan // AKM suite list 4823571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (akmCount == 0) { 4833571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "-EAP"; //default AKM 4843571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 4853571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean found = false; 4863571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (int i = 0; i < akmCount; i++) { 4873571366ac36c70746b9f013ec2b54482861c9292Randy Pan int akm = buf.getInt(); 4883571366ac36c70746b9f013ec2b54482861c9292Randy Pan switch (akm) { 4893571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_EAP: 4903571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "EAP"; 4913571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4923571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4933571366ac36c70746b9f013ec2b54482861c9292Randy Pan case WPA_AKM_PSK: 4943571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += (found ? "+" : "-") + "PSK"; 4953571366ac36c70746b9f013ec2b54482861c9292Randy Pan found = true; 4963571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 4973571366ac36c70746b9f013ec2b54482861c9292Randy Pan default: 4983571366ac36c70746b9f013ec2b54482861c9292Randy Pan // do nothing 4993571366ac36c70746b9f013ec2b54482861c9292Randy Pan break; 5003571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5013571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5023571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5033571366ac36c70746b9f013ec2b54482861c9292Randy Pan // we parsed what we want at this point 5043571366ac36c70746b9f013ec2b54482861c9292Randy Pan security += "]"; 5053571366ac36c70746b9f013ec2b54482861c9292Randy Pan return security; 5063571366ac36c70746b9f013ec2b54482861c9292Randy Pan } catch (BufferUnderflowException e) { 5073571366ac36c70746b9f013ec2b54482861c9292Randy Pan Log.e("IE_Capabilities", "Couldn't parse type 1 WPA, buffer underflow"); 5083571366ac36c70746b9f013ec2b54482861c9292Randy Pan return null; 5093571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5103571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5113571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5123571366ac36c70746b9f013ec2b54482861c9292Randy Pan /** 5133571366ac36c70746b9f013ec2b54482861c9292Randy Pan * Parse the Information Element and the 16-bit Capability Information field 5143571366ac36c70746b9f013ec2b54482861c9292Randy Pan * to build the ScanResult.capabilities String. 5153571366ac36c70746b9f013ec2b54482861c9292Randy Pan * 5163571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param ies -- Information Element array 5173571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @param beaconCap -- 16-bit Beacon Capability Information field 5183571366ac36c70746b9f013ec2b54482861c9292Randy Pan * @return security string that mirrors what wpa_supplicant generates 5193571366ac36c70746b9f013ec2b54482861c9292Randy Pan */ 5203571366ac36c70746b9f013ec2b54482861c9292Randy Pan public static String buildCapabilities(InformationElement[] ies, BitSet beaconCap) { 5213571366ac36c70746b9f013ec2b54482861c9292Randy Pan String capabilities = ""; 5223571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean rsneFound = false; 5233571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean wpaFound = false; 5243571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5253571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ies == null || beaconCap == null) { 5263571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 5273571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5283571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5293571366ac36c70746b9f013ec2b54482861c9292Randy Pan boolean privacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET); 5303571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5313571366ac36c70746b9f013ec2b54482861c9292Randy Pan for (InformationElement ie : ies) { 5323571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_RSN) { 5333571366ac36c70746b9f013ec2b54482861c9292Randy Pan rsneFound = true; 5343571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += parseRsnElement(ie); 5353571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5363571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5373571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (ie.id == InformationElement.EID_VSA) { 5383571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (isWpaOneElement(ie)) { 5393571366ac36c70746b9f013ec2b54482861c9292Randy Pan wpaFound = true; 5403571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += parseWpaOneElement(ie); 5413571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5423571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5433571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5443571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5453571366ac36c70746b9f013ec2b54482861c9292Randy Pan if (!rsneFound && !wpaFound && privacy) { 5463571366ac36c70746b9f013ec2b54482861c9292Randy Pan //private Beacon without an RSNE or WPA IE, hence WEP0 5473571366ac36c70746b9f013ec2b54482861c9292Randy Pan capabilities += "[WEP]"; 5483571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5493571366ac36c70746b9f013ec2b54482861c9292Randy Pan 5503571366ac36c70746b9f013ec2b54482861c9292Randy Pan return capabilities; 5513571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5523571366ac36c70746b9f013ec2b54482861c9292Randy Pan } 5535d31cedf4024e0f038b4dfc2081016c8631ee8feMitchell Wills} 554