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 { 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 */ toScanDetail(ScanResult scanResult)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 */ isScanResultForPskNetwork(ScanResult scanResult)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 */ isScanResultForEapNetwork(ScanResult scanResult)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 EAP network or not. 67 * This checks if the provided capabilities string contains EAP encryption type or not. 68 */ isScanResultForEapSuiteBNetwork(ScanResult scanResult)69 public static boolean isScanResultForEapSuiteBNetwork(ScanResult scanResult) { 70 return scanResult.capabilities.contains("SUITE-B-192"); 71 } 72 73 /** 74 * Helper method to check if the provided |scanResult| corresponds to a WEP network or not. 75 * This checks if the provided capabilities string contains WEP encryption type or not. 76 */ isScanResultForWepNetwork(ScanResult scanResult)77 public static boolean isScanResultForWepNetwork(ScanResult scanResult) { 78 return scanResult.capabilities.contains("WEP"); 79 } 80 81 /** 82 * Helper method to check if the provided |scanResult| corresponds to OWE network. 83 * This checks if the provided capabilities string contains OWE or not. 84 */ isScanResultForOweNetwork(ScanResult scanResult)85 public static boolean isScanResultForOweNetwork(ScanResult scanResult) { 86 return scanResult.capabilities.contains("OWE"); 87 } 88 89 /** 90 * Helper method to check if the provided |scanResult| corresponds to OWE transition network. 91 * This checks if the provided capabilities string contains OWE_TRANSITION or not. 92 */ isScanResultForOweTransitionNetwork(ScanResult scanResult)93 public static boolean isScanResultForOweTransitionNetwork(ScanResult scanResult) { 94 return scanResult.capabilities.contains("OWE_TRANSITION"); 95 } 96 97 /** 98 * Helper method to check if the provided |scanResult| corresponds to SAE network. 99 * This checks if the provided capabilities string contains SAE or not. 100 */ isScanResultForSaeNetwork(ScanResult scanResult)101 public static boolean isScanResultForSaeNetwork(ScanResult scanResult) { 102 return scanResult.capabilities.contains("SAE"); 103 } 104 105 /** 106 * Helper method to check if the provided |scanResult| corresponds to PSK-SAE transition 107 * network. This checks if the provided capabilities string contains PSK+SAE or not. 108 */ isScanResultForPskSaeTransitionNetwork(ScanResult scanResult)109 public static boolean isScanResultForPskSaeTransitionNetwork(ScanResult scanResult) { 110 return scanResult.capabilities.contains("PSK+SAE"); 111 } 112 113 /** 114 * Helper method to check if the provided |scanResult| corresponds to an open network or not. 115 * This checks if the provided capabilities string does not contain either of WEP, PSK, SAE 116 * or EAP encryption types or not. 117 */ isScanResultForOpenNetwork(ScanResult scanResult)118 public static boolean isScanResultForOpenNetwork(ScanResult scanResult) { 119 return (!(isScanResultForWepNetwork(scanResult) || isScanResultForPskNetwork(scanResult) 120 || isScanResultForEapNetwork(scanResult) || isScanResultForSaeNetwork(scanResult) 121 || isScanResultForEapSuiteBNetwork(scanResult))); 122 } 123 124 /** 125 * Helper method to quote the SSID in Scan result to use for comparing/filling SSID stored in 126 * WifiConfiguration object. 127 */ 128 @VisibleForTesting createQuotedSSID(String ssid)129 public static String createQuotedSSID(String ssid) { 130 return "\"" + ssid + "\""; 131 } 132 133 /** 134 * Creates a network configuration object using the provided |scanResult|. 135 * This is used to create ephemeral network configurations. 136 */ createNetworkFromScanResult(ScanResult scanResult)137 public static WifiConfiguration createNetworkFromScanResult(ScanResult scanResult) { 138 WifiConfiguration config = new WifiConfiguration(); 139 config.SSID = createQuotedSSID(scanResult.SSID); 140 setAllowedKeyManagementFromScanResult(scanResult, config); 141 return config; 142 } 143 144 /** 145 * Sets the {@link WifiConfiguration#allowedKeyManagement} field on the given 146 * {@link WifiConfiguration} based on its corresponding {@link ScanResult}. 147 */ setAllowedKeyManagementFromScanResult(ScanResult scanResult, WifiConfiguration config)148 public static void setAllowedKeyManagementFromScanResult(ScanResult scanResult, 149 WifiConfiguration config) { 150 if (isScanResultForSaeNetwork(scanResult)) { 151 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 152 } else if (isScanResultForPskNetwork(scanResult)) { 153 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 154 } else if (isScanResultForEapSuiteBNetwork(scanResult)) { 155 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B); 156 } else if (isScanResultForEapNetwork(scanResult)) { 157 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); 158 } else if (isScanResultForWepNetwork(scanResult)) { 159 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP); 160 } else if (isScanResultForOweNetwork(scanResult)) { 161 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 162 } else { 163 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 164 } 165 } 166 167 /** 168 * Dump the provided scan results list to |pw|. 169 */ dumpScanResults(PrintWriter pw, List<ScanResult> scanResults, long nowMs)170 public static void dumpScanResults(PrintWriter pw, List<ScanResult> scanResults, long nowMs) { 171 if (scanResults != null && scanResults.size() != 0) { 172 pw.println(" BSSID Frequency RSSI Age(sec) SSID " 173 + " Flags"); 174 for (ScanResult r : scanResults) { 175 long timeStampMs = r.timestamp / 1000; 176 String age; 177 if (timeStampMs <= 0) { 178 age = "___?___"; 179 } else if (nowMs < timeStampMs) { 180 age = " 0.000"; 181 } else if (timeStampMs < nowMs - 1000000) { 182 age = ">1000.0"; 183 } else { 184 age = String.format("%3.3f", (nowMs - timeStampMs) / 1000.0); 185 } 186 String ssid = r.SSID == null ? "" : r.SSID; 187 String rssiInfo = ""; 188 if (ArrayUtils.size(r.radioChainInfos) == 1) { 189 rssiInfo = String.format("%5d(%1d:%3d) ", r.level, 190 r.radioChainInfos[0].id, r.radioChainInfos[0].level); 191 } else if (ArrayUtils.size(r.radioChainInfos) == 2) { 192 rssiInfo = String.format("%5d(%1d:%3d/%1d:%3d)", r.level, 193 r.radioChainInfos[0].id, r.radioChainInfos[0].level, 194 r.radioChainInfos[1].id, r.radioChainInfos[1].level); 195 } else { 196 rssiInfo = String.format("%9d ", r.level); 197 } 198 pw.printf(" %17s %9d %18s %7s %-32s %s\n", 199 r.BSSID, 200 r.frequency, 201 rssiInfo, 202 age, 203 String.format("%1.32s", ssid), 204 r.capabilities); 205 } 206 } 207 } 208 } 209