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 android.net.wifi.ScanResult; 20 import android.net.wifi.WifiConfiguration; 21 22 import com.android.internal.annotations.VisibleForTesting; 23 import com.android.internal.util.ArrayUtils; 24 import com.android.server.wifi.ScanDetail; 25 import com.android.server.wifi.hotspot2.NetworkDetail; 26 27 import java.io.PrintWriter; 28 import java.util.List; 29 /** 30 * Scan result utility for any {@link ScanResult} related operations. 31 * Currently contains: 32 * > Helper method for converting a ScanResult to a ScanDetail. 33 * Only fields that are supported in ScanResult are copied. 34 * > Helper methods to identify the encryption of a ScanResult. 35 */ 36 public class ScanResultUtil { 37 private ScanResultUtil() { /* not constructable */ } 38 39 /** 40 * This method should only be used when the informationElements field in the provided scan 41 * result is filled in with the IEs from the beacon. 42 */ 43 public static ScanDetail toScanDetail(ScanResult scanResult) { 44 NetworkDetail networkDetail = new NetworkDetail(scanResult.BSSID, 45 scanResult.informationElements, scanResult.anqpLines, scanResult.frequency); 46 return new ScanDetail(scanResult, networkDetail); 47 } 48 49 /** 50 * Helper method to check if the provided |scanResult| corresponds to a PSK network or not. 51 * This checks if the provided capabilities string contains PSK encryption type or not. 52 */ 53 public static boolean isScanResultForPskNetwork(ScanResult scanResult) { 54 return scanResult.capabilities.contains("PSK"); 55 } 56 57 /** 58 * Helper method to check if the provided |scanResult| corresponds to a EAP network or not. 59 * This checks if the provided capabilities string contains EAP encryption type or not. 60 */ 61 public static boolean isScanResultForEapNetwork(ScanResult scanResult) { 62 return scanResult.capabilities.contains("EAP"); 63 } 64 65 /** 66 * Helper method to check if the provided |scanResult| corresponds to a WEP network or not. 67 * This checks if the provided capabilities string contains WEP encryption type or not. 68 */ 69 public static boolean isScanResultForWepNetwork(ScanResult scanResult) { 70 return scanResult.capabilities.contains("WEP"); 71 } 72 73 /** 74 * Helper method to check if the provided |scanResult| corresponds to an open network or not. 75 * This checks if the provided capabilities string does not contain either of WEP, PSK or EAP 76 * encryption types or not. 77 */ 78 public static boolean isScanResultForOpenNetwork(ScanResult scanResult) { 79 return !(isScanResultForWepNetwork(scanResult) || isScanResultForPskNetwork(scanResult) 80 || isScanResultForEapNetwork(scanResult)); 81 } 82 83 /** 84 * Helper method to quote the SSID in Scan result to use for comparing/filling SSID stored in 85 * WifiConfiguration object. 86 */ 87 @VisibleForTesting 88 public static String createQuotedSSID(String ssid) { 89 return "\"" + ssid + "\""; 90 } 91 92 /** 93 * Creates a network configuration object using the provided |scanResult|. 94 * This is used to create ephemeral network configurations. 95 */ 96 public static WifiConfiguration createNetworkFromScanResult(ScanResult scanResult) { 97 WifiConfiguration config = new WifiConfiguration(); 98 config.SSID = createQuotedSSID(scanResult.SSID); 99 setAllowedKeyManagementFromScanResult(scanResult, config); 100 return config; 101 } 102 103 /** 104 * Sets the {@link WifiConfiguration#allowedKeyManagement} field on the given 105 * {@link WifiConfiguration} based on its corresponding {@link ScanResult}. 106 */ 107 public static void setAllowedKeyManagementFromScanResult(ScanResult scanResult, 108 WifiConfiguration config) { 109 if (isScanResultForPskNetwork(scanResult)) { 110 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 111 } else if (isScanResultForEapNetwork(scanResult)) { 112 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); 113 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); 114 } else if (isScanResultForWepNetwork(scanResult)) { 115 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 116 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 117 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 118 } else { 119 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 120 } 121 } 122 123 /** 124 * Dump the provided scan results list to |pw|. 125 */ 126 public static void dumpScanResults(PrintWriter pw, List<ScanResult> scanResults, long nowMs) { 127 if (scanResults != null && scanResults.size() != 0) { 128 pw.println(" BSSID Frequency RSSI Age(sec) SSID " 129 + " Flags"); 130 for (ScanResult r : scanResults) { 131 long timeStampMs = r.timestamp / 1000; 132 String age; 133 if (timeStampMs <= 0) { 134 age = "___?___"; 135 } else if (nowMs < timeStampMs) { 136 age = " 0.000"; 137 } else if (timeStampMs < nowMs - 1000000) { 138 age = ">1000.0"; 139 } else { 140 age = String.format("%3.3f", (nowMs - timeStampMs) / 1000.0); 141 } 142 String ssid = r.SSID == null ? "" : r.SSID; 143 String rssiInfo = ""; 144 if (ArrayUtils.size(r.radioChainInfos) == 1) { 145 rssiInfo = String.format("%5d(%1d:%3d) ", r.level, 146 r.radioChainInfos[0].id, r.radioChainInfos[0].level); 147 } else if (ArrayUtils.size(r.radioChainInfos) == 2) { 148 rssiInfo = String.format("%5d(%1d:%3d/%1d:%3d)", r.level, 149 r.radioChainInfos[0].id, r.radioChainInfos[0].level, 150 r.radioChainInfos[1].id, r.radioChainInfos[1].level); 151 } else { 152 rssiInfo = String.format("%9d ", r.level); 153 } 154 pw.printf(" %17s %9d %18s %7s %-32s %s\n", 155 r.BSSID, 156 r.frequency, 157 rssiInfo, 158 age, 159 String.format("%1.32s", ssid), 160 r.capabilities); 161 } 162 } 163 } 164 } 165