1. ie
之前获取扫描结果的流程中有个将从kernel获取的scan result转换成framework的过程
/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
ArrayList<ScanDetail> results = new ArrayList<>();
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return results;
}
try {
NativeScanResult[] nativeResults;
if (scanType == SCAN_TYPE_SINGLE_SCAN) {
nativeResults = scannerImpl.getScanResults();
} else {
nativeResults = scannerImpl.getPnoScanResults();
}
for (NativeScanResult result : nativeResults) {
WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
String bssid;
try {
bssid = NativeUtil.macAddressFromByteArray(result.bssid);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + result.bssid, e);
continue;
}
if (bssid == null) {
Log.e(TAG, "Illegal null bssid");
continue;
}
ScanResult.InformationElement[] ies =
InformationElementUtil.parseInformationElements(result.infoElement);
InformationElementUtil.Capabilities capabilities =
new InformationElementUtil.Capabilities();
capabilities.from(ies, result.capability);
String flags = capabilities.generateCapabilitiesString();
NetworkDetail networkDetail;
try {
networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
continue;
}
ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
result.signalMbm / 100, result.frequency, result.tsf, ies, null);
ScanResult scanResult = scanDetail.getScanResult();
// Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
// network and it uses EAP.
if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
&& mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
scanResult.isCarrierAp = true;
scanResult.carrierApEapType =
mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
scanResult.carrierName =
mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
}
// Fill up the radio chain info.
if (result.radioChainInfos != null) {
scanResult.radioChainInfos =
new ScanResult.RadioChainInfo[result.radioChainInfos.size()];
int idx = 0;
for (RadioChainInfo nativeRadioChainInfo : result.radioChainInfos) {
scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.chainId;
scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.level;
idx++;
}
}
results.add(scanDetail);
}
} catch (RemoteException e1) {
Log.e(TAG, "Failed to create ScanDetail ArrayList");
}
if (mVerboseLoggingEnabled) {
Log.d(TAG, "get " + results.size() + " scan results from wificond");
}
return results;
}
从上面可以看到解析出ssid和bssid
加密方式没怎么看的到,抽出来看下这一段
ScanResult.InformationElement[] ies =
InformationElementUtil.parseInformationElements(result.infoElement);
InformationElementUtil.Capabilities capabilities =
new InformationElementUtil.Capabilities();
capabilities.from(ies, result.capability);
String flags = capabilities.generateCapabilitiesString();
NetworkDetail networkDetail;
try {
networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
continue;
}
ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
result.signalMbm / 100, result.frequency, result.tsf, ies, null);
ScanResult scanResult = scanDetail.getScanResult();
看下capabilities.from
/**
* Parse the Information Element and the 16-bit Capability Information field
* to build the InformationElemmentUtil.capabilities object.
*
* @param ies -- Information Element array
* @param beaconCap -- 16-bit Beacon Capability Information field
*/
public void from(InformationElement[] ies, BitSet beaconCap) {
protocol = new ArrayList<Integer>();
keyManagement = new ArrayList<ArrayList<Integer>>();
groupCipher = new ArrayList<Integer>();
pairwiseCipher = new ArrayList<ArrayList<Integer>>();
if (ies == null || beaconCap == null) {
return;
}
isESS = beaconCap.get(CAP_ESS_BIT_OFFSET);
isPrivacy = beaconCap.get(CAP_PRIVACY_BIT_OFFSET);
for (InformationElement ie : ies) {
if (ie.id == InformationElement.EID_RSN) {
parseRsnElement(ie);
}
if (ie.id == InformationElement.EID_VSA) {
if (isWpaOneElement(ie)) {
parseWpaOneElement(ie);
}
if (isWpsElement(ie)) {
// TODO(b/62134557): parse WPS IE to provide finer granularity information.
isWPS = true;
}
}
}
}
// RSNE format (size unit: byte)
//
// | Element ID | Length | Version | Group Data Cipher Suite |
// 1 1 2 4
// | Pairwise Cipher Suite Count | Pairwise Cipher Suite List |
// 2 4 * m
// | AKM Suite Count | AKM Suite List | RSN Capabilities |
// 2 4 * n 2
// | PMKID Count | PMKID List | Group Management Cipher Suite |
// 2 16 * s 4
//
// Note: InformationElement.bytes has 'Element ID' and 'Length'
// stripped off already
private void parseRsnElement(InformationElement ie) {
ByteBuffer buf = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN);
try {
// version
if (buf.getShort() != RSNE_VERSION) {
// incorrect version
return;
}
// found the RSNE IE, hence start building the capability string
protocol.add(ScanResult.PROTOCOL_WPA2);
// group data cipher suite
groupCipher.add(parseRsnCipher(buf.getInt()));
// pairwise cipher suite count
short cipherCount = buf.getShort();
ArrayList<Integer> rsnPairwiseCipher = new ArrayList<>();
// pairwise cipher suite list
for (int i = 0; i < cipherCount; i++) {
rsnPairwiseCipher.add(parseRsnCipher(buf.getInt()));
}
pairwiseCipher.add(rsnPairwiseCipher);
// AKM
// AKM suite count
short akmCount = buf.getShort();
ArrayList<Integer> rsnKeyManagement = new ArrayList<>();
for (int i = 0; i < akmCount; i++) {
int akm = buf.getInt();
switch (akm) {
case WPA2_AKM_EAP:
rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP);
break;
case WPA2_AKM_PSK:
rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK);
break;
case WPA2_AKM_FT_EAP:
rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_EAP);
break;
case WPA2_AKM_FT_PSK:
rsnKeyManagement.add(ScanResult.KEY_MGMT_FT_PSK);
break;
case WPA2_AKM_EAP_SHA256:
rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP_SHA256);
break;
case WPA2_AKM_PSK_SHA256:
rsnKeyManagement.add(ScanResult.KEY_MGMT_PSK_SHA256);
break;
default:
// do nothing
break;
}
}
// Default AKM
if (rsnKeyManagement.isEmpty()) {
rsnKeyManagement.add(ScanResult.KEY_MGMT_EAP);
}
keyManagement.add(rsnKeyManagement);
} catch (BufferUnderflowException e) {
Log.e("IE_Capabilities", "Couldn't parse RSNE, buffer underflow");
}
}
这边不怎么看的懂了,但大概就是将加密方式解析出来了
然后生成Capabilities显示成我们常见的加密方式
/**
* Build the ScanResult.capabilities String.
*
* @return security string that mirrors what wpa_supplicant generates
*/
public String generateCapabilitiesString() {
String capabilities = "";
// private Beacon without an RSNE or WPA IE, hence WEP0
boolean isWEP = (protocol.isEmpty()) && isPrivacy;
if (isWEP) {
capabilities += "[WEP]";
}
for (int i = 0; i < protocol.size(); i++) {
capabilities += "[" + protocolToString(protocol.get(i));
if (i < keyManagement.size()) {
for (int j = 0; j < keyManagement.get(i).size(); j++) {
capabilities += ((j == 0) ? "-" : "+")
+ keyManagementToString(keyManagement.get(i).get(j));
}
}
if (i < pairwiseCipher.size()) {
for (int j = 0; j < pairwiseCipher.get(i).size(); j++) {
capabilities += ((j == 0) ? "-" : "+")
+ cipherToString(pairwiseCipher.get(i).get(j));
}
}
capabilities += "]";
}
if (isESS) {
capabilities += "[ESS]";
}
if (isWPS) {
capabilities += "[WPS]";
}
return capabilities;
}
}
private String keyManagementToString(int akm) {
switch (akm) {
case ScanResult.KEY_MGMT_NONE:
return "None";
case ScanResult.KEY_MGMT_PSK:
return "PSK";
case ScanResult.KEY_MGMT_EAP:
return "EAP";
case ScanResult.KEY_MGMT_FT_EAP:
return "FT/EAP";
case ScanResult.KEY_MGMT_FT_PSK:
return "FT/PSK";
case ScanResult.KEY_MGMT_EAP_SHA256:
return "EAP-SHA256";
case ScanResult.KEY_MGMT_PSK_SHA256:
return "PSK-SHA256";
default:
return "?";
}
}
看下AccessPoint怎么获取加密方式的
private static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
} else if (result.capabilities.contains("PSK")) {
return SECURITY_PSK;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
}
return SECURITY_NONE;
}
可以看到是和上面对应的,虽然这边就是简单的判断是否包含字符串。
2.总结
看了个大概,加密方式大概是从扫描结果中的ie解析出来放在一个叫做capabilities里的,后续上面判断加密方式就简单判断下是否包含特定加密方式的字符串就好了。