WifiNative.java revision da4958bd7409aaf26ead2b221754d4a5035f7bdf
1/* 2 * Copyright (C) 2008 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 17package com.android.server.wifi; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.content.Context; 22import android.net.apf.ApfCapabilities; 23import android.net.wifi.RttManager; 24import android.net.wifi.RttManager.ResponderConfig; 25import android.net.wifi.ScanResult; 26import android.net.wifi.WifiConfiguration; 27import android.net.wifi.WifiEnterpriseConfig; 28import android.net.wifi.WifiLinkLayerStats; 29import android.net.wifi.WifiScanner; 30import android.net.wifi.WifiSsid; 31import android.net.wifi.WifiWakeReasonAndCounts; 32import android.net.wifi.WpsInfo; 33import android.net.wifi.p2p.WifiP2pConfig; 34import android.net.wifi.p2p.WifiP2pGroup; 35import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 36import android.os.SystemClock; 37import android.os.SystemProperties; 38import android.text.TextUtils; 39import android.util.LocalLog; 40import android.util.Log; 41 42import com.android.internal.annotations.Immutable; 43import com.android.internal.annotations.VisibleForTesting; 44import com.android.internal.util.HexDump; 45import com.android.server.connectivity.KeepalivePacketData; 46import com.android.server.wifi.hotspot2.NetworkDetail; 47import com.android.server.wifi.hotspot2.PasspointEventHandler; 48import com.android.server.wifi.hotspot2.Utils; 49import com.android.server.wifi.util.FrameParser; 50import com.android.server.wifi.util.InformationElementUtil; 51 52import libcore.util.HexEncoding; 53 54import org.json.JSONException; 55import org.json.JSONObject; 56 57import java.io.PrintWriter; 58import java.io.StringWriter; 59import java.io.UnsupportedEncodingException; 60import java.net.URLDecoder; 61import java.net.URLEncoder; 62import java.nio.ByteBuffer; 63import java.nio.CharBuffer; 64import java.nio.charset.CharacterCodingException; 65import java.nio.charset.CharsetDecoder; 66import java.nio.charset.StandardCharsets; 67import java.text.SimpleDateFormat; 68import java.util.ArrayList; 69import java.util.BitSet; 70import java.util.Date; 71import java.util.HashMap; 72import java.util.Iterator; 73import java.util.List; 74import java.util.Locale; 75import java.util.Map; 76import java.util.Objects; 77import java.util.Set; 78import java.util.TimeZone; 79 80 81/** 82 * Native calls for bring up/shut down of the supplicant daemon and for 83 * sending requests to the supplicant daemon 84 * 85 * waitForEvent() is called on the monitor thread for events. All other methods 86 * must be serialized from the framework. 87 * 88 * {@hide} 89 */ 90public class WifiNative { 91 private static boolean DBG = false; 92 93 // Must match wifi_hal.h 94 public static final int WIFI_SUCCESS = 0; 95 96 /** 97 * Hold this lock before calling supplicant or HAL methods 98 * it is required to mutually exclude access to the driver 99 */ 100 public static final Object sLock = new Object(); 101 102 private static final LocalLog sLocalLog = new LocalLog(8192); 103 104 public @NonNull LocalLog getLocalLog() { 105 return sLocalLog; 106 } 107 108 /* Register native functions */ 109 static { 110 /* Native functions are defined in libwifi-service.so */ 111 System.loadLibrary("wifi-service"); 112 registerNatives(); 113 } 114 115 private static native int registerNatives(); 116 117 /* 118 * Singleton WifiNative instances 119 */ 120 private static WifiNative wlanNativeInterface = 121 new WifiNative(SystemProperties.get("wifi.interface", "wlan0"), true); 122 public static WifiNative getWlanNativeInterface() { 123 return wlanNativeInterface; 124 } 125 126 private static WifiNative p2pNativeInterface = 127 // commands for p2p0 interface don't need prefix 128 new WifiNative(SystemProperties.get("wifi.direct.interface", "p2p0"), false); 129 public static WifiNative getP2pNativeInterface() { 130 return p2pNativeInterface; 131 } 132 133 134 private final String mTAG; 135 private final String mInterfaceName; 136 private final String mInterfacePrefix; 137 private WifiSupplicantHal mWifiSupplicantHal; 138 private WifiVendorHal mWifiVendorHal; 139 140 private Context mContext = null; 141 public void initContext(Context context) { 142 if (mContext == null && context != null) { 143 mContext = context; 144 } 145 } 146 147 /** 148 * Explicitly sets the WifiSupplicantHal instance 149 * TODO(b/34722734): move this into the constructor of WifiNative when I clean up the awful 150 * double singleton pattern 151 */ 152 public void setWifiSupplicantHal(WifiSupplicantHal wifiSupplicantHal) { 153 mWifiSupplicantHal = wifiSupplicantHal; 154 } 155 156 /** 157 * Explicitly sets the WifiVendorHal instance 158 * TODO(b/34722734): move this into the constructor of WifiNative when I clean up the awful 159 * double singleton pattern 160 */ 161 public void setWifiVendorHal(WifiVendorHal wifiVendorHal) { 162 mWifiVendorHal = wifiVendorHal; 163 } 164 165 private WifiNative(String interfaceName, 166 boolean requiresPrefix) { 167 mInterfaceName = interfaceName; 168 mTAG = "WifiNative-" + interfaceName; 169 170 if (requiresPrefix) { 171 mInterfacePrefix = "IFNAME=" + interfaceName + " "; 172 } else { 173 mInterfacePrefix = ""; 174 } 175 } 176 177 /** 178 * Initializes the vendor HAL. This is just used to initialize the {@link HalDeviceManager}. 179 */ 180 public boolean initializeVendorHal() { 181 return mWifiVendorHal.initialize(); 182 } 183 184 /** 185 * Registers a service notification for the ISupplicant service, which gets the service, 186 * ISupplicantStaIface and ISupplicantP2pIface. 187 * @return true if the service notification was successfully registered 188 */ 189 public boolean initializeSupplicantHal() { 190 return mWifiSupplicantHal.initialize(); 191 } 192 193 public String getInterfaceName() { 194 return mInterfaceName; 195 } 196 197 // Note this affects logging on for all interfaces 198 void enableVerboseLogging(int verbose) { 199 if (verbose > 0) { 200 DBG = true; 201 } else { 202 DBG = false; 203 } 204 } 205 206 private void localLog(String s) { 207 if (sLocalLog != null) sLocalLog.log(mInterfaceName + ": " + s); 208 } 209 210 211 212 /* 213 * Supplicant management 214 */ 215 private native static boolean connectToSupplicantNative(); 216 public boolean connectToSupplicant() { 217 synchronized (sLock) { 218 localLog(mInterfacePrefix + "connectToSupplicant"); 219 return connectToSupplicantNative(); 220 } 221 } 222 223 private native static void closeSupplicantConnectionNative(); 224 public void closeSupplicantConnection() { 225 synchronized (sLock) { 226 localLog(mInterfacePrefix + "closeSupplicantConnection"); 227 closeSupplicantConnectionNative(); 228 } 229 } 230 231 /** 232 * Wait for the supplicant to send an event, returning the event string. 233 * @return the event string sent by the supplicant. 234 */ 235 private native static String waitForEventNative(); 236 public String waitForEvent() { 237 // No synchronization necessary .. it is implemented in WifiMonitor 238 return waitForEventNative(); 239 } 240 241 242 /* 243 * Supplicant Command Primitives 244 */ 245 private native boolean doBooleanCommandNative(String command); 246 247 private native int doIntCommandNative(String command); 248 249 private native String doStringCommandNative(String command); 250 251 private boolean doBooleanCommand(String command) { 252 if (DBG) Log.d(mTAG, "doBoolean: " + command); 253 synchronized (sLock) { 254 String toLog = mInterfacePrefix + command; 255 boolean result = doBooleanCommandNative(mInterfacePrefix + command); 256 localLog(toLog + " -> " + result); 257 if (DBG) Log.d(mTAG, command + ": returned " + result); 258 return result; 259 } 260 } 261 262 private boolean doBooleanCommandWithoutLogging(String command) { 263 if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command); 264 synchronized (sLock) { 265 boolean result = doBooleanCommandNative(mInterfacePrefix + command); 266 if (DBG) Log.d(mTAG, command + ": returned " + result); 267 return result; 268 } 269 } 270 271 private int doIntCommand(String command) { 272 if (DBG) Log.d(mTAG, "doInt: " + command); 273 synchronized (sLock) { 274 String toLog = mInterfacePrefix + command; 275 int result = doIntCommandNative(mInterfacePrefix + command); 276 localLog(toLog + " -> " + result); 277 if (DBG) Log.d(mTAG, " returned " + result); 278 return result; 279 } 280 } 281 282 private String doStringCommand(String command) { 283 if (DBG) { 284 //GET_NETWORK commands flood the logs 285 if (!command.startsWith("GET_NETWORK")) { 286 Log.d(mTAG, "doString: [" + command + "]"); 287 } 288 } 289 synchronized (sLock) { 290 String toLog = mInterfacePrefix + command; 291 String result = doStringCommandNative(mInterfacePrefix + command); 292 if (result == null) { 293 if (DBG) Log.d(mTAG, "doStringCommandNative no result"); 294 } else { 295 if (!command.startsWith("STATUS-")) { 296 localLog(toLog + " -> " + result); 297 } 298 if (DBG) Log.d(mTAG, " returned " + result.replace("\n", " ")); 299 } 300 return result; 301 } 302 } 303 304 private String doStringCommandWithoutLogging(String command) { 305 if (DBG) { 306 //GET_NETWORK commands flood the logs 307 if (!command.startsWith("GET_NETWORK")) { 308 Log.d(mTAG, "doString: [" + command + "]"); 309 } 310 } 311 synchronized (sLock) { 312 return doStringCommandNative(mInterfacePrefix + command); 313 } 314 } 315 316 public String doCustomSupplicantCommand(String command) { 317 return doStringCommand(command); 318 } 319 320 /* 321 * Wrappers for supplicant commands 322 */ 323 public boolean ping() { 324 String pong = doStringCommand("PING"); 325 return (pong != null && pong.equals("PONG")); 326 } 327 328 public void setSupplicantLogLevel(String level) { 329 doStringCommand("LOG_LEVEL " + level); 330 } 331 332 /* 333 * Convert string to Hexadecimal before passing to wifi native layer 334 * In native function "doCommand()" have trouble in converting Unicode character string to UTF8 335 * conversion to hex is required because SSIDs can have space characters in them; 336 * and that can confuses the supplicant because it uses space charaters as delimiters 337 */ 338 public static String encodeSSID(String ssid) { 339 int length = ssid.length(); 340 if ((length > 1) && (ssid.charAt(0) == '"') 341 && (ssid.charAt(length - 1) == '"')) { 342 ssid = ssid.substring(1, length - 1); 343 } 344 return Utils.toHex(ssid.getBytes(StandardCharsets.UTF_8)); 345 } 346 347 /** 348 * Start a scan using wpa_supplicant for the given frequencies. 349 * @param freqs list of frequencies to scan for, if null scan all supported channels. 350 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 351 */ 352 public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) { 353 String freqList = null; 354 String hiddenNetworkSSIDList = null; 355 if (freqs != null && freqs.size() != 0) { 356 freqList = TextUtils.join(",", freqs); 357 } 358 if (hiddenNetworkSSIDs != null && hiddenNetworkSSIDs.size() != 0) { 359 StringBuilder ssidList = new StringBuilder(); 360 for (String ssid : hiddenNetworkSSIDs) { 361 ssidList.append(encodeSSID(ssid)).append(" "); 362 } 363 hiddenNetworkSSIDList = ssidList.toString(); 364 } 365 return scanWithParams(freqList, hiddenNetworkSSIDList); 366 } 367 368 private boolean scanWithParams(String freqList, String hiddenNetworkSSIDList) { 369 StringBuilder scanCommand = new StringBuilder(); 370 scanCommand.append("SCAN TYPE=ONLY"); 371 if (freqList != null) { 372 scanCommand.append(" freq=" + freqList); 373 } 374 if (hiddenNetworkSSIDList != null) { 375 scanCommand.append(" ssid " + hiddenNetworkSSIDList); 376 } 377 return doBooleanCommand(scanCommand.toString()); 378 } 379 380 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 381 * 382 * Note that underneath we use a harsh-sounding "terminate" supplicant command 383 * for a graceful stop and a mild-sounding "stop" interface 384 * to kill the process 385 */ 386 public boolean stopSupplicant() { 387 return doBooleanCommand("TERMINATE"); 388 } 389 390 public String listNetworks() { 391 return doStringCommand("LIST_NETWORKS"); 392 } 393 394 public String listNetworks(int last_id) { 395 return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id); 396 } 397 398 public int addNetwork() { 399 return doIntCommand("ADD_NETWORK"); 400 } 401 402 public boolean setNetworkExtra(int netId, String name, Map<String, String> values) { 403 String encoded = createNetworkExtra(values); 404 if (encoded == null) { 405 return false; 406 } 407 return setNetworkVariable(netId, name, "\"" + encoded + "\""); 408 } 409 410 @VisibleForTesting 411 public static String createNetworkExtra(Map<String, String> values) { 412 final String encoded; 413 try { 414 encoded = URLEncoder.encode(new JSONObject(values).toString(), "UTF-8"); 415 } catch (NullPointerException e) { 416 Log.e(TAG, "Unable to serialize networkExtra: " + e.toString()); 417 return null; 418 } catch (UnsupportedEncodingException e) { 419 Log.e(TAG, "Unable to serialize networkExtra: " + e.toString()); 420 return null; 421 } 422 return encoded; 423 } 424 425 public boolean setNetworkVariable(int netId, String name, String value) { 426 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; 427 if (name.equals(WifiConfiguration.pskVarName) 428 || name.equals(WifiEnterpriseConfig.PASSWORD_KEY) 429 || name.equals(WifiEnterpriseConfig.IDENTITY_KEY) 430 || name.equals(WifiEnterpriseConfig.ANON_IDENTITY_KEY)) { 431 return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value); 432 } else { 433 return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); 434 } 435 } 436 437 public Map<String, String> getNetworkExtra(int netId, String name) { 438 final String extraString = getNetworkVariable(netId, name); 439 return parseNetworkExtra(extraString); 440 } 441 442 public static Map<String, String> parseNetworkExtra(String extraSting) { 443 if (extraSting == null || !extraSting.startsWith("\"") || !extraSting.endsWith("\"")) { 444 return null; 445 } 446 try { 447 final String encoded = extraSting.substring(1, extraSting.length() - 1); 448 // This method reads a JSON dictionary that was written by setNetworkExtra(). However, 449 // on devices that upgraded from Marshmallow, it may encounter a legacy value instead - 450 // an FQDN stored as a plain string. If such a value is encountered, the JSONObject 451 // constructor will thrown a JSONException and the method will return null. 452 final JSONObject json = new JSONObject(URLDecoder.decode(encoded, "UTF-8")); 453 final Map<String, String> values = new HashMap<>(); 454 final Iterator<?> it = json.keys(); 455 while (it.hasNext()) { 456 final String key = (String) it.next(); 457 final Object value = json.get(key); 458 if (value instanceof String) { 459 values.put(key, (String) value); 460 } 461 } 462 return values; 463 } catch (UnsupportedEncodingException e) { 464 Log.e(TAG, "Unable to deserialize networkExtra: " + e.toString()); 465 return null; 466 } catch (JSONException e) { 467 // This is not necessarily an error. This exception will also occur if we encounter a 468 // legacy FQDN stored as a plain string. We want to return null in this case as no JSON 469 // dictionary of extras was found. 470 return null; 471 } 472 } 473 474 public String getNetworkVariable(int netId, String name) { 475 if (TextUtils.isEmpty(name)) return null; 476 477 // GET_NETWORK will likely flood the logs ... 478 return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name); 479 } 480 481 public boolean removeNetwork(int netId) { 482 return doBooleanCommand("REMOVE_NETWORK " + netId); 483 } 484 485 /** 486 * Remove all saved networks from wpa_supplicant. 487 */ 488 public boolean removeAllNetworks() { 489 return doBooleanCommand("REMOVE_NETWORK all"); 490 } 491 492 private void logDbg(String debug) { 493 long now = SystemClock.elapsedRealtimeNanos(); 494 String ts = String.format("[%,d us] ", now/1000); 495 Log.e("WifiNative: ", ts+debug+ " stack:" 496 + Thread.currentThread().getStackTrace()[2].getMethodName() +" - " 497 + Thread.currentThread().getStackTrace()[3].getMethodName() +" - " 498 + Thread.currentThread().getStackTrace()[4].getMethodName() +" - " 499 + Thread.currentThread().getStackTrace()[5].getMethodName()+" - " 500 + Thread.currentThread().getStackTrace()[6].getMethodName()); 501 502 } 503 504 /** 505 * Enables a network in wpa_supplicant. 506 * @param netId - Network ID of the network to be enabled. 507 * @return true if command succeeded, false otherwise. 508 */ 509 public boolean enableNetwork(int netId) { 510 if (DBG) logDbg("enableNetwork nid=" + Integer.toString(netId)); 511 return doBooleanCommand("ENABLE_NETWORK " + netId); 512 } 513 514 /** 515 * Enable a network in wpa_supplicant, do not connect. 516 * @param netId - Network ID of the network to be enabled. 517 * @return true if command succeeded, false otherwise. 518 */ 519 public boolean enableNetworkWithoutConnect(int netId) { 520 if (DBG) logDbg("enableNetworkWithoutConnect nid=" + Integer.toString(netId)); 521 return doBooleanCommand("ENABLE_NETWORK " + netId + " " + "no-connect"); 522 } 523 524 /** 525 * Disables a network in wpa_supplicant. 526 * @param netId - Network ID of the network to be disabled. 527 * @return true if command succeeded, false otherwise. 528 */ 529 public boolean disableNetwork(int netId) { 530 if (DBG) logDbg("disableNetwork nid=" + Integer.toString(netId)); 531 return doBooleanCommand("DISABLE_NETWORK " + netId); 532 } 533 534 /** 535 * Select a network in wpa_supplicant (Disables all others). 536 * @param netId - Network ID of the network to be selected. 537 * @return true if command succeeded, false otherwise. 538 */ 539 public boolean selectNetwork(int netId) { 540 if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId)); 541 return doBooleanCommand("SELECT_NETWORK " + netId); 542 } 543 544 public boolean reconnect() { 545 if (DBG) logDbg("RECONNECT "); 546 return doBooleanCommand("RECONNECT"); 547 } 548 549 public boolean reassociate() { 550 if (DBG) logDbg("REASSOCIATE "); 551 return doBooleanCommand("REASSOCIATE"); 552 } 553 554 public boolean disconnect() { 555 if (DBG) logDbg("DISCONNECT "); 556 return doBooleanCommand("DISCONNECT"); 557 } 558 559 public String status() { 560 return status(false); 561 } 562 563 public String status(boolean noEvents) { 564 if (noEvents) { 565 return doStringCommand("STATUS-NO_EVENTS"); 566 } else { 567 return doStringCommand("STATUS"); 568 } 569 } 570 571 public String getMacAddress() { 572 //Macaddr = XX.XX.XX.XX.XX.XX 573 String ret = doStringCommand("DRIVER MACADDR"); 574 if (!TextUtils.isEmpty(ret)) { 575 String[] tokens = ret.split(" = "); 576 if (tokens.length == 2) return tokens[1]; 577 } 578 return null; 579 } 580 581 582 583 /** 584 * Format of results: 585 * ================= 586 * id=1 587 * bssid=68:7f:76:d7:1a:6e 588 * freq=2412 589 * level=-44 590 * tsf=1344626243700342 591 * flags=[WPA2-PSK-CCMP][WPS][ESS] 592 * ssid=zfdy 593 * ==== 594 * id=2 595 * bssid=68:5f:74:d7:1a:6f 596 * freq=5180 597 * level=-73 598 * tsf=1344626243700373 599 * flags=[WPA2-PSK-CCMP][WPS][ESS] 600 * ssid=zuby 601 * ==== 602 * 603 * RANGE=ALL gets all scan results 604 * RANGE=ID- gets results from ID 605 * MASK=<N> BSS command information mask. 606 * 607 * The mask used in this method, 0x21d97, gets the following fields: 608 * 609 * WPA_BSS_MASK_ID (Bit 0) 610 * WPA_BSS_MASK_BSSID (Bit 1) 611 * WPA_BSS_MASK_FREQ (Bit 2) 612 * WPA_BSS_MASK_CAPABILITIES (Bit 4) 613 * WPA_BSS_MASK_LEVEL (Bit 7) 614 * WPA_BSS_MASK_TSF (Bit 8) 615 * WPA_BSS_MASK_IE (Bit 10) 616 * WPA_BSS_MASK_SSID (Bit 12) 617 * WPA_BSS_MASK_INTERNETW (Bit 15) (adds ANQP info) 618 * WPA_BSS_MASK_DELIM (Bit 17) 619 * 620 * See wpa_supplicant/src/common/wpa_ctrl.h for details. 621 */ 622 private String getRawScanResults(String range) { 623 return doStringCommandWithoutLogging("BSS RANGE=" + range + " MASK=0x21d97"); 624 } 625 626 private static final String BSS_IE_STR = "ie="; 627 private static final String BSS_ID_STR = "id="; 628 private static final String BSS_CAPABILITIES_STR = "capabilities="; 629 private static final String BSS_BSSID_STR = "bssid="; 630 private static final String BSS_FREQ_STR = "freq="; 631 private static final String BSS_LEVEL_STR = "level="; 632 private static final String BSS_TSF_STR = "tsf="; 633 private static final String BSS_SSID_STR = "ssid="; 634 private static final String BSS_DELIMITER_STR = "===="; 635 private static final String BSS_END_STR = "####"; 636 637 public ArrayList<ScanDetail> getScanResults() { 638 int next_sid = 0; 639 ArrayList<ScanDetail> results = new ArrayList<>(); 640 while(next_sid >= 0) { 641 String rawResult = getRawScanResults(next_sid+"-"); 642 next_sid = -1; 643 644 if (TextUtils.isEmpty(rawResult)) 645 break; 646 647 String[] lines = rawResult.split("\n"); 648 649 650 // note that all these splits and substrings keep references to the original 651 // huge string buffer while the amount we really want is generally pretty small 652 // so make copies instead (one example b/11087956 wasted 400k of heap here). 653 final int bssidStrLen = BSS_BSSID_STR.length(); 654 655 String bssid = ""; 656 int level = 0; 657 int freq = 0; 658 long tsf = 0; 659 int cap = 0; 660 String flags = ""; 661 WifiSsid wifiSsid = null; 662 String infoElementsStr = null; 663 List<String> anqpLines = null; 664 665 for (String line : lines) { 666 if (line.startsWith(BSS_ID_STR)) { // Will find the last id line 667 try { 668 next_sid = Integer.parseInt(line.substring(BSS_ID_STR.length())) + 1; 669 } catch (NumberFormatException e) { 670 // Nothing to do 671 } 672 } else if (line.startsWith(BSS_BSSID_STR)) { 673 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 674 } else if (line.startsWith(BSS_FREQ_STR)) { 675 try { 676 freq = Integer.parseInt(line.substring(BSS_FREQ_STR.length())); 677 } catch (NumberFormatException e) { 678 freq = 0; 679 } 680 } else if (line.startsWith(BSS_LEVEL_STR)) { 681 try { 682 level = Integer.parseInt(line.substring(BSS_LEVEL_STR.length())); 683 /* some implementations avoid negative values by adding 256 684 * so we need to adjust for that here. 685 */ 686 if (level > 0) level -= 256; 687 } catch (NumberFormatException e) { 688 level = 0; 689 } 690 } else if (line.startsWith(BSS_TSF_STR)) { 691 try { 692 tsf = Long.parseLong(line.substring(BSS_TSF_STR.length())); 693 } catch (NumberFormatException e) { 694 tsf = 0; 695 } 696 } else if (line.startsWith(BSS_CAPABILITIES_STR)) { 697 try { 698 cap = Integer.decode(line.substring(BSS_CAPABILITIES_STR.length())); 699 } catch (NumberFormatException e) { 700 cap = 0; 701 } 702 } else if (line.startsWith(BSS_SSID_STR)) { 703 wifiSsid = WifiSsid.createFromAsciiEncoded( 704 line.substring(BSS_SSID_STR.length())); 705 } else if (line.startsWith(BSS_IE_STR)) { 706 infoElementsStr = line; 707 } else if (PasspointEventHandler.isAnqpAttribute(line)) { 708 if (anqpLines == null) { 709 anqpLines = new ArrayList<>(); 710 } 711 anqpLines.add(line); 712 } else if (line.startsWith(BSS_DELIMITER_STR) || line.startsWith(BSS_END_STR)) { 713 if (bssid != null) { 714 try { 715 if (infoElementsStr == null) { 716 throw new IllegalArgumentException("Null information element data"); 717 } 718 int seperator = infoElementsStr.indexOf('='); 719 if (seperator < 0) { 720 throw new IllegalArgumentException("No element separator"); 721 } 722 723 ScanResult.InformationElement[] infoElements = 724 InformationElementUtil.parseInformationElements( 725 Utils.hexToBytes(infoElementsStr.substring(seperator + 1))); 726 727 NetworkDetail networkDetail = new NetworkDetail(bssid, 728 infoElements, anqpLines, freq); 729 String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 730 if (!xssid.equals(networkDetail.getTrimmedSSID())) { 731 Log.d(TAG, String.format( 732 "Inconsistent SSID on BSSID '%s': '%s' vs '%s': %s", 733 bssid, xssid, networkDetail.getSSID(), infoElementsStr)); 734 } 735 736 if (networkDetail.hasInterworking()) { 737 if (DBG) Log.d(TAG, "HSNwk: '" + networkDetail); 738 } 739 BitSet beaconCapBits = new BitSet(16); 740 for (int i = 0; i < 16; i++) { 741 if ((cap & (1 << i)) != 0) { 742 beaconCapBits.set(i); 743 } 744 } 745 746 InformationElementUtil.Capabilities capabilities = 747 new InformationElementUtil.Capabilities(); 748 capabilities.from(infoElements, beaconCapBits); 749 flags = capabilities.generateCapabilitiesString(); 750 ScanDetail scan = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 751 level, freq, tsf, infoElements, anqpLines); 752 results.add(scan); 753 } catch (IllegalArgumentException iae) { 754 Log.d(TAG, "Failed to parse information elements: " + iae); 755 } 756 } 757 bssid = null; 758 level = 0; 759 freq = 0; 760 tsf = 0; 761 cap = 0; 762 flags = ""; 763 wifiSsid = null; 764 infoElementsStr = null; 765 anqpLines = null; 766 } 767 } 768 } 769 return results; 770 } 771 772 /** 773 * Format of result: 774 * id=1016 775 * bssid=00:03:7f:40:84:10 776 * freq=2462 777 * beacon_int=200 778 * capabilities=0x0431 779 * qual=0 780 * noise=0 781 * level=-46 782 * tsf=0000002669008476 783 * age=5 784 * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555... 785 * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20] 786 * ssid=QCA-HS20-R2-TEST 787 * p2p_device_name= 788 * p2p_config_methods=0x0SET_NE 789 * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f... 790 * anqp_network_auth_type=010000 791 * anqp_roaming_consortium=03506f9a05001bc504bd 792 * anqp_ip_addr_type_availability=0c 793 * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2... 794 * anqp_3gpp=000600040132f465 795 * anqp_domain_name=0b65786d61706c652e636f6d 796 * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869... 797 * hs20_wan_metrics=01c40900008001000000000a00 798 * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0... 799 * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d... 800 */ 801 public String scanResult(String bssid) { 802 return doStringCommand("BSS " + bssid); 803 } 804 805 /** 806 * Start filtering out Multicast V4 packets 807 * @return {@code true} if the operation succeeded, {@code false} otherwise 808 * 809 * Multicast filtering rules work as follows: 810 * 811 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 812 * a power optimized mode (typically when screen goes off). 813 * 814 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 815 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 816 * 817 * DRIVER RXFILTER-ADD Num 818 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 819 * 820 * and DRIVER RXFILTER-START 821 * In order to stop the usage of these rules, we do 822 * 823 * DRIVER RXFILTER-STOP 824 * DRIVER RXFILTER-REMOVE Num 825 * where Num is as described for RXFILTER-ADD 826 * 827 * The SETSUSPENDOPT driver command overrides the filtering rules 828 */ 829 public boolean startFilteringMulticastV4Packets() { 830 return doBooleanCommand("DRIVER RXFILTER-STOP") 831 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 832 && doBooleanCommand("DRIVER RXFILTER-START"); 833 } 834 835 /** 836 * Stop filtering out Multicast V4 packets. 837 * @return {@code true} if the operation succeeded, {@code false} otherwise 838 */ 839 public boolean stopFilteringMulticastV4Packets() { 840 return doBooleanCommand("DRIVER RXFILTER-STOP") 841 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 842 && doBooleanCommand("DRIVER RXFILTER-START"); 843 } 844 845 /** 846 * Start filtering out Multicast V6 packets 847 * @return {@code true} if the operation succeeded, {@code false} otherwise 848 */ 849 public boolean startFilteringMulticastV6Packets() { 850 return doBooleanCommand("DRIVER RXFILTER-STOP") 851 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 852 && doBooleanCommand("DRIVER RXFILTER-START"); 853 } 854 855 /** 856 * Stop filtering out Multicast V6 packets. 857 * @return {@code true} if the operation succeeded, {@code false} otherwise 858 */ 859 public boolean stopFilteringMulticastV6Packets() { 860 return doBooleanCommand("DRIVER RXFILTER-STOP") 861 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 862 && doBooleanCommand("DRIVER RXFILTER-START"); 863 } 864 865 public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 866 public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 867 public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 868 /** 869 * Sets the bluetooth coexistence mode. 870 * 871 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 872 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 873 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 874 * @return Whether the mode was successfully set. 875 */ 876 public boolean setBluetoothCoexistenceMode(int mode) { 877 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 878 } 879 880 /** 881 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 882 * some of the low-level scan parameters used by the driver are changed to 883 * reduce interference with A2DP streaming. 884 * 885 * @param setCoexScanMode whether to enable or disable this mode 886 * @return {@code true} if the command succeeded, {@code false} otherwise. 887 */ 888 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 889 if (setCoexScanMode) { 890 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 891 } else { 892 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 893 } 894 } 895 896 public void enableSaveConfig() { 897 doBooleanCommand("SET update_config 1"); 898 } 899 900 public boolean saveConfig() { 901 return doBooleanCommand("SAVE_CONFIG"); 902 } 903 904 public boolean addToBlacklist(String bssid) { 905 if (TextUtils.isEmpty(bssid)) return false; 906 return doBooleanCommand("BLACKLIST " + bssid); 907 } 908 909 public boolean clearBlacklist() { 910 return doBooleanCommand("BLACKLIST clear"); 911 } 912 913 public boolean setSuspendOptimizations(boolean enabled) { 914 if (enabled) { 915 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 916 } else { 917 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 918 } 919 } 920 921 public boolean setCountryCode(String countryCode) { 922 if (countryCode != null) 923 return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT)); 924 else 925 return doBooleanCommand("DRIVER COUNTRY"); 926 } 927 928 /** 929 * Start/Stop PNO scan. 930 * @param enable boolean indicating whether PNO is being enabled or disabled. 931 */ 932 public boolean setPnoScan(boolean enable) { 933 String cmd = enable ? "SET pno 1" : "SET pno 0"; 934 return doBooleanCommand(cmd); 935 } 936 937 public void enableAutoConnect(boolean enable) { 938 if (enable) { 939 doBooleanCommand("STA_AUTOCONNECT 1"); 940 } else { 941 doBooleanCommand("STA_AUTOCONNECT 0"); 942 } 943 } 944 945 public void setScanInterval(int scanInterval) { 946 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 947 } 948 949 public void setHs20(boolean hs20) { 950 if (hs20) { 951 doBooleanCommand("SET HS20 1"); 952 } else { 953 doBooleanCommand("SET HS20 0"); 954 } 955 } 956 957 public void startTdls(String macAddr, boolean enable) { 958 if (enable) { 959 synchronized (sLock) { 960 doBooleanCommand("TDLS_DISCOVER " + macAddr); 961 doBooleanCommand("TDLS_SETUP " + macAddr); 962 } 963 } else { 964 doBooleanCommand("TDLS_TEARDOWN " + macAddr); 965 } 966 } 967 968 public boolean startWpsPbc(String bssid) { 969 if (TextUtils.isEmpty(bssid)) { 970 return doBooleanCommand("WPS_PBC"); 971 } else { 972 return doBooleanCommand("WPS_PBC " + bssid); 973 } 974 } 975 976 public boolean startWpsPbc(String iface, String bssid) { 977 synchronized (sLock) { 978 if (TextUtils.isEmpty(bssid)) { 979 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); 980 } else { 981 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); 982 } 983 } 984 } 985 986 public boolean startWpsPinKeypad(String pin) { 987 if (TextUtils.isEmpty(pin)) return false; 988 return doBooleanCommand("WPS_PIN any " + pin); 989 } 990 991 public boolean startWpsPinKeypad(String iface, String pin) { 992 if (TextUtils.isEmpty(pin)) return false; 993 synchronized (sLock) { 994 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); 995 } 996 } 997 998 999 public String startWpsPinDisplay(String bssid) { 1000 if (TextUtils.isEmpty(bssid)) { 1001 return doStringCommand("WPS_PIN any"); 1002 } else { 1003 return doStringCommand("WPS_PIN " + bssid); 1004 } 1005 } 1006 1007 public String startWpsPinDisplay(String iface, String bssid) { 1008 synchronized (sLock) { 1009 if (TextUtils.isEmpty(bssid)) { 1010 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); 1011 } else { 1012 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); 1013 } 1014 } 1015 } 1016 1017 public boolean setExternalSim(boolean external) { 1018 String value = external ? "1" : "0"; 1019 Log.d(TAG, "Setting external_sim to " + value); 1020 return doBooleanCommand("SET external_sim " + value); 1021 } 1022 1023 public boolean simAuthResponse(int id, String type, String response) { 1024 // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS 1025 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response); 1026 } 1027 1028 public boolean simAuthFailedResponse(int id) { 1029 // should be used with type GSM-AUTH 1030 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL"); 1031 } 1032 1033 public boolean umtsAuthFailedResponse(int id) { 1034 // should be used with type UMTS-AUTH 1035 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL"); 1036 } 1037 1038 public boolean simIdentityResponse(int id, String response) { 1039 return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response); 1040 } 1041 1042 /* Configures an access point connection */ 1043 public boolean startWpsRegistrar(String bssid, String pin) { 1044 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 1045 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 1046 } 1047 1048 public boolean cancelWps() { 1049 return doBooleanCommand("WPS_CANCEL"); 1050 } 1051 1052 public boolean setPersistentReconnect(boolean enabled) { 1053 int value = (enabled == true) ? 1 : 0; 1054 return doBooleanCommand("SET persistent_reconnect " + value); 1055 } 1056 1057 public boolean setDeviceName(String name) { 1058 return doBooleanCommand("SET device_name " + name); 1059 } 1060 1061 public boolean setDeviceType(String type) { 1062 return doBooleanCommand("SET device_type " + type); 1063 } 1064 1065 public boolean setConfigMethods(String cfg) { 1066 return doBooleanCommand("SET config_methods " + cfg); 1067 } 1068 1069 public boolean setManufacturer(String value) { 1070 return doBooleanCommand("SET manufacturer " + value); 1071 } 1072 1073 public boolean setModelName(String value) { 1074 return doBooleanCommand("SET model_name " + value); 1075 } 1076 1077 public boolean setModelNumber(String value) { 1078 return doBooleanCommand("SET model_number " + value); 1079 } 1080 1081 public boolean setSerialNumber(String value) { 1082 return doBooleanCommand("SET serial_number " + value); 1083 } 1084 1085 public boolean setP2pSsidPostfix(String postfix) { 1086 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 1087 } 1088 1089 public boolean setP2pGroupIdle(String iface, int time) { 1090 synchronized (sLock) { 1091 return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); 1092 } 1093 } 1094 1095 public void setPowerSave(boolean enabled) { 1096 if (enabled) { 1097 doBooleanCommand("SET ps 1"); 1098 } else { 1099 doBooleanCommand("SET ps 0"); 1100 } 1101 } 1102 1103 public boolean setP2pPowerSave(String iface, boolean enabled) { 1104 synchronized (sLock) { 1105 if (enabled) { 1106 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); 1107 } else { 1108 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); 1109 } 1110 } 1111 } 1112 1113 public boolean setWfdEnable(boolean enable) { 1114 return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); 1115 } 1116 1117 public boolean setWfdDeviceInfo(String hex) { 1118 return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); 1119 } 1120 1121 /** 1122 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 1123 * P2P connection over STA 1124 */ 1125 public boolean setConcurrencyPriority(String s) { 1126 return doBooleanCommand("P2P_SET conc_pref " + s); 1127 } 1128 1129 public boolean p2pFind() { 1130 return doBooleanCommand("P2P_FIND"); 1131 } 1132 1133 public boolean p2pFind(int timeout) { 1134 if (timeout <= 0) { 1135 return p2pFind(); 1136 } 1137 return doBooleanCommand("P2P_FIND " + timeout); 1138 } 1139 1140 public boolean p2pStopFind() { 1141 return doBooleanCommand("P2P_STOP_FIND"); 1142 } 1143 1144 public boolean p2pListen() { 1145 return doBooleanCommand("P2P_LISTEN"); 1146 } 1147 1148 public boolean p2pListen(int timeout) { 1149 if (timeout <= 0) { 1150 return p2pListen(); 1151 } 1152 return doBooleanCommand("P2P_LISTEN " + timeout); 1153 } 1154 1155 public boolean p2pExtListen(boolean enable, int period, int interval) { 1156 if (enable && interval < period) { 1157 return false; 1158 } 1159 return doBooleanCommand("P2P_EXT_LISTEN" 1160 + (enable ? (" " + period + " " + interval) : "")); 1161 } 1162 1163 public boolean p2pSetChannel(int lc, int oc) { 1164 if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc); 1165 1166 synchronized (sLock) { 1167 if (lc >=1 && lc <= 11) { 1168 if (!doBooleanCommand("P2P_SET listen_channel " + lc)) { 1169 return false; 1170 } 1171 } else if (lc != 0) { 1172 return false; 1173 } 1174 1175 if (oc >= 1 && oc <= 165 ) { 1176 int freq = (oc <= 14 ? 2407 : 5000) + oc * 5; 1177 return doBooleanCommand("P2P_SET disallow_freq 1000-" 1178 + (freq - 5) + "," + (freq + 5) + "-6000"); 1179 } else if (oc == 0) { 1180 /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */ 1181 return doBooleanCommand("P2P_SET disallow_freq \"\""); 1182 } 1183 } 1184 return false; 1185 } 1186 1187 public boolean p2pFlush() { 1188 return doBooleanCommand("P2P_FLUSH"); 1189 } 1190 1191 private static final int DEFAULT_GROUP_OWNER_INTENT = 6; 1192 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 1193 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 1194 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 1195 if (config == null) return null; 1196 List<String> args = new ArrayList<>(); 1197 WpsInfo wps = config.wps; 1198 args.add(config.deviceAddress); 1199 1200 switch (wps.setup) { 1201 case WpsInfo.PBC: 1202 args.add("pbc"); 1203 break; 1204 case WpsInfo.DISPLAY: 1205 if (TextUtils.isEmpty(wps.pin)) { 1206 args.add("pin"); 1207 } else { 1208 args.add(wps.pin); 1209 } 1210 args.add("display"); 1211 break; 1212 case WpsInfo.KEYPAD: 1213 args.add(wps.pin); 1214 args.add("keypad"); 1215 break; 1216 case WpsInfo.LABEL: 1217 args.add(wps.pin); 1218 args.add("label"); 1219 default: 1220 break; 1221 } 1222 1223 if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { 1224 args.add("persistent"); 1225 } 1226 1227 if (joinExistingGroup) { 1228 args.add("join"); 1229 } else { 1230 //TODO: This can be adapted based on device plugged in state and 1231 //device battery state 1232 int groupOwnerIntent = config.groupOwnerIntent; 1233 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 1234 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 1235 } 1236 args.add("go_intent=" + groupOwnerIntent); 1237 } 1238 1239 String command = "P2P_CONNECT "; 1240 for (String s : args) command += s + " "; 1241 1242 return doStringCommand(command); 1243 } 1244 1245 public boolean p2pCancelConnect() { 1246 return doBooleanCommand("P2P_CANCEL"); 1247 } 1248 1249 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 1250 if (config == null) return false; 1251 1252 switch (config.wps.setup) { 1253 case WpsInfo.PBC: 1254 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 1255 case WpsInfo.DISPLAY: 1256 //We are doing display, so provision discovery is keypad 1257 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 1258 case WpsInfo.KEYPAD: 1259 //We are doing keypad, so provision discovery is display 1260 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 1261 default: 1262 break; 1263 } 1264 return false; 1265 } 1266 1267 public boolean p2pGroupAdd(boolean persistent) { 1268 if (persistent) { 1269 return doBooleanCommand("P2P_GROUP_ADD persistent"); 1270 } 1271 return doBooleanCommand("P2P_GROUP_ADD"); 1272 } 1273 1274 public boolean p2pGroupAdd(int netId) { 1275 return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); 1276 } 1277 1278 public boolean p2pGroupRemove(String iface) { 1279 if (TextUtils.isEmpty(iface)) return false; 1280 synchronized (sLock) { 1281 return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); 1282 } 1283 } 1284 1285 public boolean p2pReject(String deviceAddress) { 1286 return doBooleanCommand("P2P_REJECT " + deviceAddress); 1287 } 1288 1289 /* Invite a peer to a group */ 1290 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 1291 if (TextUtils.isEmpty(deviceAddress)) return false; 1292 1293 if (group == null) { 1294 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 1295 } else { 1296 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 1297 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 1298 } 1299 } 1300 1301 /* Reinvoke a persistent connection */ 1302 public boolean p2pReinvoke(int netId, String deviceAddress) { 1303 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 1304 1305 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 1306 } 1307 1308 public String p2pGetSsid(String deviceAddress) { 1309 return p2pGetParam(deviceAddress, "oper_ssid"); 1310 } 1311 1312 public String p2pGetDeviceAddress() { 1313 Log.d(TAG, "p2pGetDeviceAddress"); 1314 1315 String status = null; 1316 1317 /* Explicitly calling the API without IFNAME= prefix to take care of the devices that 1318 don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */ 1319 1320 synchronized (sLock) { 1321 status = doStringCommandNative("STATUS"); 1322 } 1323 1324 String result = ""; 1325 if (status != null) { 1326 String[] tokens = status.split("\n"); 1327 for (String token : tokens) { 1328 if (token.startsWith("p2p_device_address=")) { 1329 String[] nameValue = token.split("="); 1330 if (nameValue.length != 2) 1331 break; 1332 result = nameValue[1]; 1333 } 1334 } 1335 } 1336 1337 Log.d(TAG, "p2pGetDeviceAddress returning " + result); 1338 return result; 1339 } 1340 1341 public int getGroupCapability(String deviceAddress) { 1342 int gc = 0; 1343 if (TextUtils.isEmpty(deviceAddress)) return gc; 1344 String peerInfo = p2pPeer(deviceAddress); 1345 if (TextUtils.isEmpty(peerInfo)) return gc; 1346 1347 String[] tokens = peerInfo.split("\n"); 1348 for (String token : tokens) { 1349 if (token.startsWith("group_capab=")) { 1350 String[] nameValue = token.split("="); 1351 if (nameValue.length != 2) break; 1352 try { 1353 return Integer.decode(nameValue[1]); 1354 } catch(NumberFormatException e) { 1355 return gc; 1356 } 1357 } 1358 } 1359 return gc; 1360 } 1361 1362 public String p2pPeer(String deviceAddress) { 1363 return doStringCommand("P2P_PEER " + deviceAddress); 1364 } 1365 1366 private String p2pGetParam(String deviceAddress, String key) { 1367 if (deviceAddress == null) return null; 1368 1369 String peerInfo = p2pPeer(deviceAddress); 1370 if (peerInfo == null) return null; 1371 String[] tokens= peerInfo.split("\n"); 1372 1373 key += "="; 1374 for (String token : tokens) { 1375 if (token.startsWith(key)) { 1376 String[] nameValue = token.split("="); 1377 if (nameValue.length != 2) break; 1378 return nameValue[1]; 1379 } 1380 } 1381 return null; 1382 } 1383 1384 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 1385 /* 1386 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 1387 * P2P_SERVICE_ADD upnp <version hex> <service> 1388 * 1389 * e.g) 1390 * [Bonjour] 1391 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 1392 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 1393 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 1394 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 1395 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 1396 * 1397 * [UPnP] 1398 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 1399 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 1400 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 1401 * -org:device:InternetGatewayDevice:1 1402 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 1403 * -org:service:ContentDirectory:2 1404 */ 1405 synchronized (sLock) { 1406 for (String s : servInfo.getSupplicantQueryList()) { 1407 String command = "P2P_SERVICE_ADD"; 1408 command += (" " + s); 1409 if (!doBooleanCommand(command)) { 1410 return false; 1411 } 1412 } 1413 } 1414 return true; 1415 } 1416 1417 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 1418 /* 1419 * P2P_SERVICE_DEL bonjour <query hexdump> 1420 * P2P_SERVICE_DEL upnp <version hex> <service> 1421 */ 1422 synchronized (sLock) { 1423 for (String s : servInfo.getSupplicantQueryList()) { 1424 String command = "P2P_SERVICE_DEL "; 1425 1426 String[] data = s.split(" "); 1427 if (data.length < 2) { 1428 return false; 1429 } 1430 if ("upnp".equals(data[0])) { 1431 command += s; 1432 } else if ("bonjour".equals(data[0])) { 1433 command += data[0]; 1434 command += (" " + data[1]); 1435 } else { 1436 return false; 1437 } 1438 if (!doBooleanCommand(command)) { 1439 return false; 1440 } 1441 } 1442 } 1443 return true; 1444 } 1445 1446 public boolean p2pServiceFlush() { 1447 return doBooleanCommand("P2P_SERVICE_FLUSH"); 1448 } 1449 1450 public String p2pServDiscReq(String addr, String query) { 1451 String command = "P2P_SERV_DISC_REQ"; 1452 command += (" " + addr); 1453 command += (" " + query); 1454 1455 return doStringCommand(command); 1456 } 1457 1458 public boolean p2pServDiscCancelReq(String id) { 1459 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 1460 } 1461 1462 /* Set the current mode of miracast operation. 1463 * 0 = disabled 1464 * 1 = operating as source 1465 * 2 = operating as sink 1466 */ 1467 public void setMiracastMode(int mode) { 1468 // Note: optional feature on the driver. It is ok for this to fail. 1469 doBooleanCommand("DRIVER MIRACAST " + mode); 1470 } 1471 1472 /* 1473 * NFC-related calls 1474 */ 1475 public String getNfcWpsConfigurationToken(int netId) { 1476 return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId); 1477 } 1478 1479 public String getNfcHandoverRequest() { 1480 return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR"); 1481 } 1482 1483 public String getNfcHandoverSelect() { 1484 return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR"); 1485 } 1486 1487 public boolean initiatorReportNfcHandover(String selectMessage) { 1488 return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage); 1489 } 1490 1491 public boolean responderReportNfcHandover(String requestMessage) { 1492 return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00"); 1493 } 1494 1495 1496 /* kernel logging support */ 1497 private static native byte[] readKernelLogNative(); 1498 1499 synchronized public String readKernelLog() { 1500 byte[] bytes = readKernelLogNative(); 1501 if (bytes != null) { 1502 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 1503 try { 1504 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); 1505 return decoded.toString(); 1506 } catch (CharacterCodingException cce) { 1507 return new String(bytes, StandardCharsets.ISO_8859_1); 1508 } 1509 } else { 1510 return "*** failed to read kernel log ***"; 1511 } 1512 } 1513 1514 /* WIFI HAL support */ 1515 1516 // HAL command ids 1517 private static int sCmdId = 1; 1518 private static int getNewCmdIdLocked() { 1519 return sCmdId++; 1520 } 1521 1522 private static final String TAG = "WifiNative-HAL"; 1523 private static long sWifiHalHandle = 0; /* used by JNI to save wifi_handle */ 1524 private static long[] sWifiIfaceHandles = null; /* used by JNI to save interface handles */ 1525 public static int sWlan0Index = -1; 1526 private static MonitorThread sThread; 1527 private static final int STOP_HAL_TIMEOUT_MS = 1000; 1528 1529 private static native boolean startHalNative(); 1530 private static native void stopHalNative(); 1531 private static native void waitForHalEventNative(); 1532 1533 private static class MonitorThread extends Thread { 1534 @Override 1535 public void run() { 1536 Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle)); 1537 waitForHalEventNative(); 1538 } 1539 } 1540 1541 public boolean startHal() { 1542 String debugLog = "startHal stack: "; 1543 java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 1544 for (int i = 2; i < elements.length && i <= 7; i++ ) { 1545 debugLog = debugLog + " - " + elements[i].getMethodName(); 1546 } 1547 1548 sLocalLog.log(debugLog); 1549 1550 synchronized (sLock) { 1551 if (startHalNative()) { 1552 int wlan0Index = queryInterfaceIndex(mInterfaceName); 1553 if (wlan0Index == -1) { 1554 if (DBG) sLocalLog.log("Could not find interface with name: " + mInterfaceName); 1555 return false; 1556 } 1557 sWlan0Index = wlan0Index; 1558 sThread = new MonitorThread(); 1559 sThread.start(); 1560 return true; 1561 } else { 1562 if (DBG) sLocalLog.log("Could not start hal"); 1563 Log.e(TAG, "Could not start hal"); 1564 return false; 1565 } 1566 } 1567 } 1568 1569 public void stopHal() { 1570 synchronized (sLock) { 1571 if (isHalStarted()) { 1572 stopHalNative(); 1573 try { 1574 sThread.join(STOP_HAL_TIMEOUT_MS); 1575 Log.d(TAG, "HAL event thread stopped successfully"); 1576 } catch (InterruptedException e) { 1577 Log.e(TAG, "Could not stop HAL cleanly"); 1578 } 1579 sThread = null; 1580 sWifiHalHandle = 0; 1581 sWifiIfaceHandles = null; 1582 sWlan0Index = -1; 1583 } 1584 } 1585 } 1586 1587 public boolean isHalStarted() { 1588 return (sWifiHalHandle != 0); 1589 } 1590 private static native int getInterfacesNative(); 1591 1592 public int queryInterfaceIndex(String interfaceName) { 1593 synchronized (sLock) { 1594 if (isHalStarted()) { 1595 int num = getInterfacesNative(); 1596 for (int i = 0; i < num; i++) { 1597 String name = getInterfaceNameNative(i); 1598 if (name.equals(interfaceName)) { 1599 return i; 1600 } 1601 } 1602 } 1603 } 1604 return -1; 1605 } 1606 1607 private static native String getInterfaceNameNative(int index); 1608 public String getInterfaceName(int index) { 1609 synchronized (sLock) { 1610 return getInterfaceNameNative(index); 1611 } 1612 } 1613 1614 // TODO: Change variable names to camel style. 1615 public static class ScanCapabilities { 1616 public int max_scan_cache_size; 1617 public int max_scan_buckets; 1618 public int max_ap_cache_per_scan; 1619 public int max_rssi_sample_size; 1620 public int max_scan_reporting_threshold; 1621 public int max_hotlist_bssids; 1622 public int max_significant_wifi_change_aps; 1623 public int max_bssid_history_entries; 1624 public int max_number_epno_networks; 1625 public int max_number_epno_networks_by_ssid; 1626 public int max_number_of_white_listed_ssid; 1627 } 1628 1629 public boolean getScanCapabilities(ScanCapabilities capabilities) { 1630 synchronized (sLock) { 1631 return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities); 1632 } 1633 } 1634 1635 private static native boolean getScanCapabilitiesNative( 1636 int iface, ScanCapabilities capabilities); 1637 1638 private static native boolean startScanNative(int iface, int id, ScanSettings settings); 1639 private static native boolean stopScanNative(int iface, int id); 1640 private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush); 1641 private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface); 1642 private static native void setWifiLinkLayerStatsNative(int iface, int enable); 1643 1644 public static class ChannelSettings { 1645 public int frequency; 1646 public int dwell_time_ms; 1647 public boolean passive; 1648 } 1649 1650 public static class BucketSettings { 1651 public int bucket; 1652 public int band; 1653 public int period_ms; 1654 public int max_period_ms; 1655 public int step_count; 1656 public int report_events; 1657 public int num_channels; 1658 public ChannelSettings[] channels; 1659 } 1660 1661 /** 1662 * Network parameters for hidden networks to be scanned for. 1663 */ 1664 public static class HiddenNetwork { 1665 public String ssid; 1666 1667 @Override 1668 public boolean equals(Object otherObj) { 1669 if (this == otherObj) { 1670 return true; 1671 } else if (otherObj == null || getClass() != otherObj.getClass()) { 1672 return false; 1673 } 1674 HiddenNetwork other = (HiddenNetwork) otherObj; 1675 return Objects.equals(ssid, other.ssid); 1676 } 1677 } 1678 1679 public static class ScanSettings { 1680 public int base_period_ms; 1681 public int max_ap_per_scan; 1682 public int report_threshold_percent; 1683 public int report_threshold_num_scans; 1684 public int num_buckets; 1685 /* Not used for bg scans. Only works for single scans. */ 1686 public HiddenNetwork[] hiddenNetworks; 1687 public BucketSettings[] buckets; 1688 } 1689 1690 /** 1691 * Network parameters to start PNO scan. 1692 */ 1693 public static class PnoNetwork { 1694 public String ssid; 1695 public byte flags; 1696 public byte auth_bit_field; 1697 1698 @Override 1699 public boolean equals(Object otherObj) { 1700 if (this == otherObj) { 1701 return true; 1702 } else if (otherObj == null || getClass() != otherObj.getClass()) { 1703 return false; 1704 } 1705 PnoNetwork other = (PnoNetwork) otherObj; 1706 return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags) 1707 && (auth_bit_field == other.auth_bit_field)); 1708 } 1709 } 1710 1711 /** 1712 * Parameters to start PNO scan. This holds the list of networks which are going to used for 1713 * PNO scan. 1714 */ 1715 public static class PnoSettings { 1716 public int min5GHzRssi; 1717 public int min24GHzRssi; 1718 public int initialScoreMax; 1719 public int currentConnectionBonus; 1720 public int sameNetworkBonus; 1721 public int secureBonus; 1722 public int band5GHzBonus; 1723 public boolean isConnected; 1724 public PnoNetwork[] networkList; 1725 } 1726 1727 /** 1728 * Wi-Fi channel information. 1729 */ 1730 public static class WifiChannelInfo { 1731 int mPrimaryFrequency; 1732 int mCenterFrequency0; 1733 int mCenterFrequency1; 1734 int mChannelWidth; 1735 // TODO: add preamble once available in HAL. 1736 } 1737 1738 public static interface ScanEventHandler { 1739 /** 1740 * Called for each AP as it is found with the entire contents of the beacon/probe response. 1741 * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified. 1742 */ 1743 void onFullScanResult(ScanResult fullScanResult, int bucketsScanned); 1744 /** 1745 * Callback on an event during a gscan scan. 1746 * See WifiNative.WIFI_SCAN_* for possible values. 1747 */ 1748 void onScanStatus(int event); 1749 /** 1750 * Called with the current cached scan results when gscan is paused. 1751 */ 1752 void onScanPaused(WifiScanner.ScanData[] data); 1753 /** 1754 * Called with the current cached scan results when gscan is resumed. 1755 */ 1756 void onScanRestarted(); 1757 } 1758 1759 /** 1760 * Handler to notify the occurrence of various events during PNO scan. 1761 */ 1762 public interface PnoEventHandler { 1763 /** 1764 * Callback to notify when one of the shortlisted networks is found during PNO scan. 1765 * @param results List of Scan results received. 1766 */ 1767 void onPnoNetworkFound(ScanResult[] results); 1768 1769 /** 1770 * Callback to notify when the PNO scan schedule fails. 1771 */ 1772 void onPnoScanFailed(); 1773 } 1774 1775 /* scan status, keep these values in sync with gscan.h */ 1776 public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0; 1777 public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1; 1778 public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2; 1779 public static final int WIFI_SCAN_FAILED = 3; 1780 1781 // Callback from native 1782 private static void onScanStatus(int id, int event) { 1783 ScanEventHandler handler = sScanEventHandler; 1784 if (handler != null) { 1785 handler.onScanStatus(event); 1786 } 1787 } 1788 1789 public static WifiSsid createWifiSsid(byte[] rawSsid) { 1790 String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid)); 1791 1792 if (ssidHexString == null) { 1793 return null; 1794 } 1795 1796 WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString); 1797 1798 return wifiSsid; 1799 } 1800 1801 public static String ssidConvert(byte[] rawSsid) { 1802 String ssid; 1803 1804 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 1805 try { 1806 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid)); 1807 ssid = decoded.toString(); 1808 } catch (CharacterCodingException cce) { 1809 ssid = null; 1810 } 1811 1812 if (ssid == null) { 1813 ssid = new String(rawSsid, StandardCharsets.ISO_8859_1); 1814 } 1815 1816 return ssid; 1817 } 1818 1819 // Called from native 1820 public static boolean setSsid(byte[] rawSsid, ScanResult result) { 1821 if (rawSsid == null || rawSsid.length == 0 || result == null) { 1822 return false; 1823 } 1824 1825 result.SSID = ssidConvert(rawSsid); 1826 result.wifiSsid = createWifiSsid(rawSsid); 1827 return true; 1828 } 1829 1830 private static void populateScanResult(ScanResult result, int beaconCap, String dbg) { 1831 if (dbg == null) dbg = ""; 1832 1833 InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation(); 1834 InformationElementUtil.VhtOperation vhtOperation = 1835 new InformationElementUtil.VhtOperation(); 1836 InformationElementUtil.ExtendedCapabilities extendedCaps = 1837 new InformationElementUtil.ExtendedCapabilities(); 1838 1839 ScanResult.InformationElement elements[] = 1840 InformationElementUtil.parseInformationElements(result.bytes); 1841 for (ScanResult.InformationElement ie : elements) { 1842 if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) { 1843 htOperation.from(ie); 1844 } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) { 1845 vhtOperation.from(ie); 1846 } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) { 1847 extendedCaps.from(ie); 1848 } 1849 } 1850 1851 if (extendedCaps.is80211McRTTResponder()) { 1852 result.setFlag(ScanResult.FLAG_80211mc_RESPONDER); 1853 } else { 1854 result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER); 1855 } 1856 1857 //handle RTT related information 1858 if (vhtOperation.isValid()) { 1859 result.channelWidth = vhtOperation.getChannelWidth(); 1860 result.centerFreq0 = vhtOperation.getCenterFreq0(); 1861 result.centerFreq1 = vhtOperation.getCenterFreq1(); 1862 } else { 1863 result.channelWidth = htOperation.getChannelWidth(); 1864 result.centerFreq0 = htOperation.getCenterFreq0(result.frequency); 1865 result.centerFreq1 = 0; 1866 } 1867 1868 // build capabilities string 1869 BitSet beaconCapBits = new BitSet(16); 1870 for (int i = 0; i < 16; i++) { 1871 if ((beaconCap & (1 << i)) != 0) { 1872 beaconCapBits.set(i); 1873 } 1874 } 1875 InformationElementUtil.Capabilities capabilities = 1876 new InformationElementUtil.Capabilities(); 1877 capabilities.from(elements, beaconCapBits); 1878 result.capabilities = capabilities.generateCapabilitiesString(); 1879 1880 if(DBG) { 1881 Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth 1882 + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0 1883 + " mCenterfreq1: " + result.centerFreq1 1884 + (extendedCaps.is80211McRTTResponder() ? "Support RTT reponder: " 1885 : "Do not support RTT responder") 1886 + " Capabilities: " + result.capabilities); 1887 } 1888 1889 result.informationElements = elements; 1890 } 1891 1892 // Callback from native 1893 private static void onFullScanResult(int id, ScanResult result, 1894 int bucketsScanned, int beaconCap) { 1895 if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID); 1896 1897 ScanEventHandler handler = sScanEventHandler; 1898 if (handler != null) { 1899 populateScanResult(result, beaconCap, " onFullScanResult "); 1900 handler.onFullScanResult(result, bucketsScanned); 1901 } 1902 } 1903 1904 private static int sScanCmdId = 0; 1905 private static ScanEventHandler sScanEventHandler; 1906 private static ScanSettings sScanSettings; 1907 1908 public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) { 1909 synchronized (sLock) { 1910 if (isHalStarted()) { 1911 if (sScanCmdId != 0) { 1912 stopScan(); 1913 } else if (sScanSettings != null || sScanEventHandler != null) { 1914 /* current scan is paused; no need to stop it */ 1915 } 1916 1917 sScanCmdId = getNewCmdIdLocked(); 1918 1919 sScanSettings = settings; 1920 sScanEventHandler = eventHandler; 1921 1922 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) { 1923 sScanEventHandler = null; 1924 sScanSettings = null; 1925 sScanCmdId = 0; 1926 return false; 1927 } 1928 1929 return true; 1930 } else { 1931 return false; 1932 } 1933 } 1934 } 1935 1936 public void stopScan() { 1937 synchronized (sLock) { 1938 if (isHalStarted()) { 1939 if (sScanCmdId != 0) { 1940 stopScanNative(sWlan0Index, sScanCmdId); 1941 } 1942 sScanSettings = null; 1943 sScanEventHandler = null; 1944 sScanCmdId = 0; 1945 } 1946 } 1947 } 1948 1949 public void pauseScan() { 1950 synchronized (sLock) { 1951 if (isHalStarted()) { 1952 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) { 1953 Log.d(TAG, "Pausing scan"); 1954 WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true); 1955 stopScanNative(sWlan0Index, sScanCmdId); 1956 sScanCmdId = 0; 1957 sScanEventHandler.onScanPaused(scanData); 1958 } 1959 } 1960 } 1961 } 1962 1963 public void restartScan() { 1964 synchronized (sLock) { 1965 if (isHalStarted()) { 1966 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) { 1967 Log.d(TAG, "Restarting scan"); 1968 ScanEventHandler handler = sScanEventHandler; 1969 ScanSettings settings = sScanSettings; 1970 if (startScan(sScanSettings, sScanEventHandler)) { 1971 sScanEventHandler.onScanRestarted(); 1972 } else { 1973 /* we are still paused; don't change state */ 1974 sScanEventHandler = handler; 1975 sScanSettings = settings; 1976 } 1977 } 1978 } 1979 } 1980 } 1981 1982 public WifiScanner.ScanData[] getScanResults(boolean flush) { 1983 synchronized (sLock) { 1984 WifiScanner.ScanData[] sd = null; 1985 if (isHalStarted()) { 1986 sd = getScanResultsNative(sWlan0Index, flush); 1987 } 1988 1989 if (sd != null) { 1990 return sd; 1991 } else { 1992 return new WifiScanner.ScanData[0]; 1993 } 1994 } 1995 } 1996 1997 public static interface HotlistEventHandler { 1998 void onHotlistApFound (ScanResult[] result); 1999 void onHotlistApLost (ScanResult[] result); 2000 } 2001 2002 private static int sHotlistCmdId = 0; 2003 private static HotlistEventHandler sHotlistEventHandler; 2004 2005 private native static boolean setHotlistNative(int iface, int id, 2006 WifiScanner.HotlistSettings settings); 2007 private native static boolean resetHotlistNative(int iface, int id); 2008 2009 public boolean setHotlist(WifiScanner.HotlistSettings settings, 2010 HotlistEventHandler eventHandler) { 2011 synchronized (sLock) { 2012 if (isHalStarted()) { 2013 if (sHotlistCmdId != 0) { 2014 return false; 2015 } else { 2016 sHotlistCmdId = getNewCmdIdLocked(); 2017 } 2018 2019 sHotlistEventHandler = eventHandler; 2020 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) { 2021 sHotlistEventHandler = null; 2022 return false; 2023 } 2024 2025 return true; 2026 } else { 2027 return false; 2028 } 2029 } 2030 } 2031 2032 public void resetHotlist() { 2033 synchronized (sLock) { 2034 if (isHalStarted()) { 2035 if (sHotlistCmdId != 0) { 2036 resetHotlistNative(sWlan0Index, sHotlistCmdId); 2037 sHotlistCmdId = 0; 2038 sHotlistEventHandler = null; 2039 } 2040 } 2041 } 2042 } 2043 2044 // Callback from native 2045 private static void onHotlistApFound(int id, ScanResult[] results) { 2046 HotlistEventHandler handler = sHotlistEventHandler; 2047 if (handler != null) { 2048 handler.onHotlistApFound(results); 2049 } else { 2050 /* this can happen because of race conditions */ 2051 Log.d(TAG, "Ignoring hotlist AP found event"); 2052 } 2053 } 2054 2055 // Callback from native 2056 private static void onHotlistApLost(int id, ScanResult[] results) { 2057 HotlistEventHandler handler = sHotlistEventHandler; 2058 if (handler != null) { 2059 handler.onHotlistApLost(results); 2060 } else { 2061 /* this can happen because of race conditions */ 2062 Log.d(TAG, "Ignoring hotlist AP lost event"); 2063 } 2064 } 2065 2066 public static interface SignificantWifiChangeEventHandler { 2067 void onChangesFound(ScanResult[] result); 2068 } 2069 2070 private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler; 2071 private static int sSignificantWifiChangeCmdId; 2072 2073 private static native boolean trackSignificantWifiChangeNative( 2074 int iface, int id, WifiScanner.WifiChangeSettings settings); 2075 private static native boolean untrackSignificantWifiChangeNative(int iface, int id); 2076 2077 public boolean trackSignificantWifiChange( 2078 WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) { 2079 synchronized (sLock) { 2080 if (isHalStarted()) { 2081 if (sSignificantWifiChangeCmdId != 0) { 2082 return false; 2083 } else { 2084 sSignificantWifiChangeCmdId = getNewCmdIdLocked(); 2085 } 2086 2087 sSignificantWifiChangeHandler = handler; 2088 if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId, 2089 settings) == false) { 2090 sSignificantWifiChangeHandler = null; 2091 return false; 2092 } 2093 2094 return true; 2095 } else { 2096 return false; 2097 } 2098 2099 } 2100 } 2101 2102 public void untrackSignificantWifiChange() { 2103 synchronized (sLock) { 2104 if (isHalStarted()) { 2105 if (sSignificantWifiChangeCmdId != 0) { 2106 untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId); 2107 sSignificantWifiChangeCmdId = 0; 2108 sSignificantWifiChangeHandler = null; 2109 } 2110 } 2111 } 2112 } 2113 2114 // Callback from native 2115 private static void onSignificantWifiChange(int id, ScanResult[] results) { 2116 SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler; 2117 if (handler != null) { 2118 handler.onChangesFound(results); 2119 } else { 2120 /* this can happen because of race conditions */ 2121 Log.d(TAG, "Ignoring significant wifi change"); 2122 } 2123 } 2124 2125 public WifiLinkLayerStats getWifiLinkLayerStats(String iface) { 2126 // TODO: use correct iface name to Index translation 2127 if (iface == null) return null; 2128 synchronized (sLock) { 2129 if (isHalStarted()) { 2130 return getWifiLinkLayerStatsNative(sWlan0Index); 2131 } else { 2132 return null; 2133 } 2134 } 2135 } 2136 2137 public void setWifiLinkLayerStats(String iface, int enable) { 2138 if (iface == null) return; 2139 synchronized (sLock) { 2140 if (isHalStarted()) { 2141 setWifiLinkLayerStatsNative(sWlan0Index, enable); 2142 } 2143 } 2144 } 2145 2146 public static native int getSupportedFeatureSetNative(int iface); 2147 public int getSupportedFeatureSet() { 2148 synchronized (sLock) { 2149 if (isHalStarted()) { 2150 return getSupportedFeatureSetNative(sWlan0Index); 2151 } else { 2152 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started"); 2153 return 0; 2154 } 2155 } 2156 } 2157 2158 /* Rtt related commands/events */ 2159 public static interface RttEventHandler { 2160 void onRttResults(RttManager.RttResult[] result); 2161 } 2162 2163 private static RttEventHandler sRttEventHandler; 2164 private static int sRttCmdId; 2165 2166 // Callback from native 2167 private static void onRttResults(int id, RttManager.RttResult[] results) { 2168 RttEventHandler handler = sRttEventHandler; 2169 if (handler != null && id == sRttCmdId) { 2170 Log.d(TAG, "Received " + results.length + " rtt results"); 2171 handler.onRttResults(results); 2172 sRttCmdId = 0; 2173 } else { 2174 Log.d(TAG, "RTT Received event for unknown cmd = " + id + 2175 ", current id = " + sRttCmdId); 2176 } 2177 } 2178 2179 private static native boolean requestRangeNative( 2180 int iface, int id, RttManager.RttParams[] params); 2181 private static native boolean cancelRangeRequestNative( 2182 int iface, int id, RttManager.RttParams[] params); 2183 2184 public boolean requestRtt( 2185 RttManager.RttParams[] params, RttEventHandler handler) { 2186 synchronized (sLock) { 2187 if (isHalStarted()) { 2188 if (sRttCmdId != 0) { 2189 Log.w(TAG, "Last one is still under measurement!"); 2190 return false; 2191 } else { 2192 sRttCmdId = getNewCmdIdLocked(); 2193 } 2194 sRttEventHandler = handler; 2195 return requestRangeNative(sWlan0Index, sRttCmdId, params); 2196 } else { 2197 return false; 2198 } 2199 } 2200 } 2201 2202 public boolean cancelRtt(RttManager.RttParams[] params) { 2203 synchronized (sLock) { 2204 if (isHalStarted()) { 2205 if (sRttCmdId == 0) { 2206 return false; 2207 } 2208 2209 sRttCmdId = 0; 2210 2211 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) { 2212 sRttEventHandler = null; 2213 return true; 2214 } else { 2215 Log.e(TAG, "RTT cancel Request failed"); 2216 return false; 2217 } 2218 } else { 2219 return false; 2220 } 2221 } 2222 } 2223 2224 private static int sRttResponderCmdId = 0; 2225 2226 private static native ResponderConfig enableRttResponderNative(int iface, int commandId, 2227 int timeoutSeconds, WifiChannelInfo channelHint); 2228 /** 2229 * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder 2230 * role is successfully enabled, {@code null} otherwise. 2231 */ 2232 @Nullable 2233 public ResponderConfig enableRttResponder(int timeoutSeconds) { 2234 synchronized (sLock) { 2235 if (!isHalStarted()) return null; 2236 if (sRttResponderCmdId != 0) { 2237 if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen"); 2238 return null; 2239 } 2240 int id = getNewCmdIdLocked(); 2241 ResponderConfig config = enableRttResponderNative( 2242 sWlan0Index, id, timeoutSeconds, null); 2243 if (config != null) sRttResponderCmdId = id; 2244 if (DBG) Log.d(TAG, "enabling rtt " + (config != null)); 2245 return config; 2246 } 2247 } 2248 2249 private static native boolean disableRttResponderNative(int iface, int commandId); 2250 /** 2251 * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled, 2252 * {@code false} otherwise. 2253 */ 2254 public boolean disableRttResponder() { 2255 synchronized (sLock) { 2256 if (!isHalStarted()) return false; 2257 if (sRttResponderCmdId == 0) { 2258 Log.e(mTAG, "responder role not enabled yet"); 2259 return true; 2260 } 2261 sRttResponderCmdId = 0; 2262 return disableRttResponderNative(sWlan0Index, sRttResponderCmdId); 2263 } 2264 } 2265 2266 private static native boolean setScanningMacOuiNative(int iface, byte[] oui); 2267 2268 public boolean setScanningMacOui(byte[] oui) { 2269 synchronized (sLock) { 2270 if (isHalStarted()) { 2271 return setScanningMacOuiNative(sWlan0Index, oui); 2272 } else { 2273 return false; 2274 } 2275 } 2276 } 2277 2278 private static native int[] getChannelsForBandNative( 2279 int iface, int band); 2280 2281 public int [] getChannelsForBand(int band) { 2282 synchronized (sLock) { 2283 if (isHalStarted()) { 2284 return getChannelsForBandNative(sWlan0Index, band); 2285 } else { 2286 return null; 2287 } 2288 } 2289 } 2290 2291 private static native boolean isGetChannelsForBandSupportedNative(); 2292 public boolean isGetChannelsForBandSupported(){ 2293 synchronized (sLock) { 2294 if (isHalStarted()) { 2295 return isGetChannelsForBandSupportedNative(); 2296 } else { 2297 return false; 2298 } 2299 } 2300 } 2301 2302 private static native boolean setDfsFlagNative(int iface, boolean dfsOn); 2303 public boolean setDfsFlag(boolean dfsOn) { 2304 synchronized (sLock) { 2305 if (isHalStarted()) { 2306 return setDfsFlagNative(sWlan0Index, dfsOn); 2307 } else { 2308 return false; 2309 } 2310 } 2311 } 2312 2313 private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface); 2314 public RttManager.RttCapabilities getRttCapabilities() { 2315 synchronized (sLock) { 2316 if (isHalStarted()) { 2317 return getRttCapabilitiesNative(sWlan0Index); 2318 } else { 2319 return null; 2320 } 2321 } 2322 } 2323 2324 private static native ApfCapabilities getApfCapabilitiesNative(int iface); 2325 public ApfCapabilities getApfCapabilities() { 2326 synchronized (sLock) { 2327 if (isHalStarted()) { 2328 return getApfCapabilitiesNative(sWlan0Index); 2329 } else { 2330 return null; 2331 } 2332 } 2333 } 2334 2335 private static native boolean installPacketFilterNative(int iface, byte[] filter); 2336 public boolean installPacketFilter(byte[] filter) { 2337 synchronized (sLock) { 2338 if (isHalStarted()) { 2339 return installPacketFilterNative(sWlan0Index, filter); 2340 } else { 2341 return false; 2342 } 2343 } 2344 } 2345 2346 private static native boolean setCountryCodeHalNative(int iface, String CountryCode); 2347 public boolean setCountryCodeHal(String CountryCode) { 2348 synchronized (sLock) { 2349 if (isHalStarted()) { 2350 return setCountryCodeHalNative(sWlan0Index, CountryCode); 2351 } else { 2352 return false; 2353 } 2354 } 2355 } 2356 2357 /* Rtt related commands/events */ 2358 public abstract class TdlsEventHandler { 2359 abstract public void onTdlsStatus(String macAddr, int status, int reason); 2360 } 2361 2362 private static TdlsEventHandler sTdlsEventHandler; 2363 2364 private static native boolean enableDisableTdlsNative(int iface, boolean enable, 2365 String macAddr); 2366 public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) { 2367 synchronized (sLock) { 2368 sTdlsEventHandler = tdlsCallBack; 2369 return enableDisableTdlsNative(sWlan0Index, enable, macAdd); 2370 } 2371 } 2372 2373 // Once TDLS per mac and event feature is implemented, this class definition should be 2374 // moved to the right place, like WifiManager etc 2375 public static class TdlsStatus { 2376 int channel; 2377 int global_operating_class; 2378 int state; 2379 int reason; 2380 } 2381 private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr); 2382 public TdlsStatus getTdlsStatus(String macAdd) { 2383 synchronized (sLock) { 2384 if (isHalStarted()) { 2385 return getTdlsStatusNative(sWlan0Index, macAdd); 2386 } else { 2387 return null; 2388 } 2389 } 2390 } 2391 2392 //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be 2393 // moved to the right place, like WifiStateMachine etc 2394 public static class TdlsCapabilities { 2395 /* Maximum TDLS session number can be supported by the Firmware and hardware */ 2396 int maxConcurrentTdlsSessionNumber; 2397 boolean isGlobalTdlsSupported; 2398 boolean isPerMacTdlsSupported; 2399 boolean isOffChannelTdlsSupported; 2400 } 2401 2402 2403 2404 private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface); 2405 public TdlsCapabilities getTdlsCapabilities () { 2406 synchronized (sLock) { 2407 if (isHalStarted()) { 2408 return getTdlsCapabilitiesNative(sWlan0Index); 2409 } else { 2410 return null; 2411 } 2412 } 2413 } 2414 2415 private static boolean onTdlsStatus(String macAddr, int status, int reason) { 2416 TdlsEventHandler handler = sTdlsEventHandler; 2417 if (handler == null) { 2418 return false; 2419 } else { 2420 handler.onTdlsStatus(macAddr, status, reason); 2421 return true; 2422 } 2423 } 2424 2425 //--------------------------------------------------------------------------------- 2426 2427 /* Wifi Logger commands/events */ 2428 2429 public static interface WifiLoggerEventHandler { 2430 void onRingBufferData(RingBufferStatus status, byte[] buffer); 2431 void onWifiAlert(int errorCode, byte[] buffer); 2432 } 2433 2434 private static WifiLoggerEventHandler sWifiLoggerEventHandler = null; 2435 2436 // Callback from native 2437 private static void onRingBufferData(RingBufferStatus status, byte[] buffer) { 2438 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2439 if (handler != null) 2440 handler.onRingBufferData(status, buffer); 2441 } 2442 2443 // Callback from native 2444 private static void onWifiAlert(byte[] buffer, int errorCode) { 2445 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2446 if (handler != null) 2447 handler.onWifiAlert(errorCode, buffer); 2448 } 2449 2450 private static int sLogCmdId = -1; 2451 private static native boolean setLoggingEventHandlerNative(int iface, int id); 2452 public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 2453 synchronized (sLock) { 2454 if (isHalStarted()) { 2455 int oldId = sLogCmdId; 2456 sLogCmdId = getNewCmdIdLocked(); 2457 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) { 2458 sLogCmdId = oldId; 2459 return false; 2460 } 2461 sWifiLoggerEventHandler = handler; 2462 return true; 2463 } else { 2464 return false; 2465 } 2466 } 2467 } 2468 2469 private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel, 2470 int flags, int minIntervalSec ,int minDataSize, String ringName); 2471 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 2472 int minDataSize, String ringName){ 2473 synchronized (sLock) { 2474 if (isHalStarted()) { 2475 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval, 2476 minDataSize, ringName); 2477 } else { 2478 return false; 2479 } 2480 } 2481 } 2482 2483 private static native int getSupportedLoggerFeatureSetNative(int iface); 2484 public int getSupportedLoggerFeatureSet() { 2485 synchronized (sLock) { 2486 if (isHalStarted()) { 2487 return getSupportedLoggerFeatureSetNative(sWlan0Index); 2488 } else { 2489 return 0; 2490 } 2491 } 2492 } 2493 2494 private static native boolean resetLogHandlerNative(int iface, int id); 2495 public boolean resetLogHandler() { 2496 synchronized (sLock) { 2497 if (isHalStarted()) { 2498 if (sLogCmdId == -1) { 2499 Log.e(TAG,"Can not reset handler Before set any handler"); 2500 return false; 2501 } 2502 sWifiLoggerEventHandler = null; 2503 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) { 2504 sLogCmdId = -1; 2505 return true; 2506 } else { 2507 return false; 2508 } 2509 } else { 2510 return false; 2511 } 2512 } 2513 } 2514 2515 private static native String getDriverVersionNative(int iface); 2516 public String getDriverVersion() { 2517 synchronized (sLock) { 2518 if (isHalStarted()) { 2519 return getDriverVersionNative(sWlan0Index); 2520 } else { 2521 return ""; 2522 } 2523 } 2524 } 2525 2526 2527 private static native String getFirmwareVersionNative(int iface); 2528 public String getFirmwareVersion() { 2529 synchronized (sLock) { 2530 if (isHalStarted()) { 2531 return getFirmwareVersionNative(sWlan0Index); 2532 } else { 2533 return ""; 2534 } 2535 } 2536 } 2537 2538 public static class RingBufferStatus{ 2539 String name; 2540 int flag; 2541 int ringBufferId; 2542 int ringBufferByteSize; 2543 int verboseLevel; 2544 int writtenBytes; 2545 int readBytes; 2546 int writtenRecords; 2547 2548 @Override 2549 public String toString() { 2550 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 2551 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 2552 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 2553 " writtenRecords: " + writtenRecords; 2554 } 2555 } 2556 2557 private static native RingBufferStatus[] getRingBufferStatusNative(int iface); 2558 public RingBufferStatus[] getRingBufferStatus() { 2559 synchronized (sLock) { 2560 if (isHalStarted()) { 2561 return getRingBufferStatusNative(sWlan0Index); 2562 } else { 2563 return null; 2564 } 2565 } 2566 } 2567 2568 private static native boolean getRingBufferDataNative(int iface, String ringName); 2569 public boolean getRingBufferData(String ringName) { 2570 synchronized (sLock) { 2571 if (isHalStarted()) { 2572 return getRingBufferDataNative(sWlan0Index, ringName); 2573 } else { 2574 return false; 2575 } 2576 } 2577 } 2578 2579 private static byte[] mFwMemoryDump; 2580 // Callback from native 2581 private static void onWifiFwMemoryAvailable(byte[] buffer) { 2582 mFwMemoryDump = buffer; 2583 if (DBG) { 2584 Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " + 2585 (buffer == null ? 0 : buffer.length)); 2586 } 2587 } 2588 2589 private static native boolean getFwMemoryDumpNative(int iface); 2590 public byte[] getFwMemoryDump() { 2591 synchronized (sLock) { 2592 if (isHalStarted()) { 2593 if(getFwMemoryDumpNative(sWlan0Index)) { 2594 byte[] fwMemoryDump = mFwMemoryDump; 2595 mFwMemoryDump = null; 2596 return fwMemoryDump; 2597 } else { 2598 return null; 2599 } 2600 } 2601 return null; 2602 } 2603 } 2604 2605 private static native byte[] getDriverStateDumpNative(int iface); 2606 /** Fetch the driver state, for driver debugging. */ 2607 public byte[] getDriverStateDump() { 2608 synchronized (sLock) { 2609 if (isHalStarted()) { 2610 return getDriverStateDumpNative(sWlan0Index); 2611 } else { 2612 return null; 2613 } 2614 } 2615 } 2616 2617 //--------------------------------------------------------------------------------- 2618 /* Packet fate API */ 2619 2620 @Immutable 2621 abstract static class FateReport { 2622 final static int USEC_PER_MSEC = 1000; 2623 // The driver timestamp is a 32-bit counter, in microseconds. This field holds the 2624 // maximal value of a driver timestamp in milliseconds. 2625 final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000); 2626 final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); 2627 2628 final byte mFate; 2629 final long mDriverTimestampUSec; 2630 final byte mFrameType; 2631 final byte[] mFrameBytes; 2632 final long mEstimatedWallclockMSec; 2633 2634 FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2635 mFate = fate; 2636 mDriverTimestampUSec = driverTimestampUSec; 2637 mEstimatedWallclockMSec = 2638 convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec); 2639 mFrameType = frameType; 2640 mFrameBytes = frameBytes; 2641 } 2642 2643 public String toTableRowString() { 2644 StringWriter sw = new StringWriter(); 2645 PrintWriter pw = new PrintWriter(sw); 2646 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2647 dateFormatter.setTimeZone(TimeZone.getDefault()); 2648 pw.format("%-15s %12s %-9s %-32s %-12s %-23s %s\n", 2649 mDriverTimestampUSec, 2650 dateFormatter.format(new Date(mEstimatedWallclockMSec)), 2651 directionToString(), fateToString(), parser.mMostSpecificProtocolString, 2652 parser.mTypeString, parser.mResultString); 2653 return sw.toString(); 2654 } 2655 2656 public String toVerboseStringWithPiiAllowed() { 2657 StringWriter sw = new StringWriter(); 2658 PrintWriter pw = new PrintWriter(sw); 2659 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2660 pw.format("Frame direction: %s\n", directionToString()); 2661 pw.format("Frame timestamp: %d\n", mDriverTimestampUSec); 2662 pw.format("Frame fate: %s\n", fateToString()); 2663 pw.format("Frame type: %s\n", frameTypeToString(mFrameType)); 2664 pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString); 2665 pw.format("Frame protocol type: %s\n", parser.mTypeString); 2666 pw.format("Frame length: %d\n", mFrameBytes.length); 2667 pw.append("Frame bytes"); 2668 pw.append(HexDump.dumpHexString(mFrameBytes)); // potentially contains PII 2669 pw.append("\n"); 2670 return sw.toString(); 2671 } 2672 2673 /* Returns a header to match the output of toTableRowString(). */ 2674 public static String getTableHeader() { 2675 StringWriter sw = new StringWriter(); 2676 PrintWriter pw = new PrintWriter(sw); 2677 pw.format("\n%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2678 "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result"); 2679 pw.format("%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2680 "---------", "--------", "---------", "----", "--------", "----", "------"); 2681 return sw.toString(); 2682 } 2683 2684 protected abstract String directionToString(); 2685 2686 protected abstract String fateToString(); 2687 2688 private static String frameTypeToString(byte frameType) { 2689 switch (frameType) { 2690 case WifiLoggerHal.FRAME_TYPE_UNKNOWN: 2691 return "unknown"; 2692 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II: 2693 return "data"; 2694 case WifiLoggerHal.FRAME_TYPE_80211_MGMT: 2695 return "802.11 management"; 2696 default: 2697 return Byte.toString(frameType); 2698 } 2699 } 2700 2701 /** 2702 * Converts a driver timestamp to a wallclock time, based on the current 2703 * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of 2704 * microseconds, with the same base as BOOTTIME. 2705 */ 2706 private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) { 2707 final long wallclockMillisNow = System.currentTimeMillis(); 2708 final long boottimeMillisNow = SystemClock.elapsedRealtime(); 2709 final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC; 2710 2711 long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC; 2712 if (boottimeTimestampMillis < driverTimestampMillis) { 2713 // The 32-bit microsecond count has wrapped between the time that the driver 2714 // recorded the packet, and the call to this function. Adjust the BOOTTIME 2715 // timestamp, to compensate. 2716 // 2717 // Note that overflow is not a concern here, since the result is less than 2718 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above, 2719 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since 2720 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit 2721 // within a long. 2722 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC; 2723 } 2724 2725 final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis; 2726 return wallclockMillisNow - millisSincePacketTimestamp; 2727 } 2728 } 2729 2730 /** 2731 * Represents the fate information for one outbound packet. 2732 */ 2733 @Immutable 2734 public static final class TxFateReport extends FateReport { 2735 TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2736 super(fate, driverTimestampUSec, frameType, frameBytes); 2737 } 2738 2739 @Override 2740 protected String directionToString() { 2741 return "TX"; 2742 } 2743 2744 @Override 2745 protected String fateToString() { 2746 switch (mFate) { 2747 case WifiLoggerHal.TX_PKT_FATE_ACKED: 2748 return "acked"; 2749 case WifiLoggerHal.TX_PKT_FATE_SENT: 2750 return "sent"; 2751 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED: 2752 return "firmware queued"; 2753 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID: 2754 return "firmware dropped (invalid frame)"; 2755 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS: 2756 return "firmware dropped (no bufs)"; 2757 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER: 2758 return "firmware dropped (other)"; 2759 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED: 2760 return "driver queued"; 2761 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID: 2762 return "driver dropped (invalid frame)"; 2763 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS: 2764 return "driver dropped (no bufs)"; 2765 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER: 2766 return "driver dropped (other)"; 2767 default: 2768 return Byte.toString(mFate); 2769 } 2770 } 2771 } 2772 2773 /** 2774 * Represents the fate information for one inbound packet. 2775 */ 2776 @Immutable 2777 public static final class RxFateReport extends FateReport { 2778 RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2779 super(fate, driverTimestampUSec, frameType, frameBytes); 2780 } 2781 2782 @Override 2783 protected String directionToString() { 2784 return "RX"; 2785 } 2786 2787 @Override 2788 protected String fateToString() { 2789 switch (mFate) { 2790 case WifiLoggerHal.RX_PKT_FATE_SUCCESS: 2791 return "success"; 2792 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED: 2793 return "firmware queued"; 2794 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER: 2795 return "firmware dropped (filter)"; 2796 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID: 2797 return "firmware dropped (invalid frame)"; 2798 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS: 2799 return "firmware dropped (no bufs)"; 2800 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER: 2801 return "firmware dropped (other)"; 2802 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED: 2803 return "driver queued"; 2804 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER: 2805 return "driver dropped (filter)"; 2806 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID: 2807 return "driver dropped (invalid frame)"; 2808 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS: 2809 return "driver dropped (no bufs)"; 2810 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER: 2811 return "driver dropped (other)"; 2812 default: 2813 return Byte.toString(mFate); 2814 } 2815 } 2816 } 2817 2818 private static native int startPktFateMonitoringNative(int iface); 2819 /** 2820 * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started. 2821 */ 2822 public boolean startPktFateMonitoring() { 2823 synchronized (sLock) { 2824 if (isHalStarted()) { 2825 return startPktFateMonitoringNative(sWlan0Index) == WIFI_SUCCESS; 2826 } else { 2827 return false; 2828 } 2829 } 2830 } 2831 2832 private static native int getTxPktFatesNative(int iface, TxFateReport[] reportBufs); 2833 /** 2834 * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started. 2835 */ 2836 public boolean getTxPktFates(TxFateReport[] reportBufs) { 2837 synchronized (sLock) { 2838 if (isHalStarted()) { 2839 int res = getTxPktFatesNative(sWlan0Index, reportBufs); 2840 if (res != WIFI_SUCCESS) { 2841 Log.e(TAG, "getTxPktFatesNative returned " + res); 2842 return false; 2843 } else { 2844 return true; 2845 } 2846 } else { 2847 return false; 2848 } 2849 } 2850 } 2851 2852 private static native int getRxPktFatesNative(int iface, RxFateReport[] reportBufs); 2853 /** 2854 * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started. 2855 */ 2856 public boolean getRxPktFates(RxFateReport[] reportBufs) { 2857 synchronized (sLock) { 2858 if (isHalStarted()) { 2859 int res = getRxPktFatesNative(sWlan0Index, reportBufs); 2860 if (res != WIFI_SUCCESS) { 2861 Log.e(TAG, "getRxPktFatesNative returned " + res); 2862 return false; 2863 } else { 2864 return true; 2865 } 2866 } else { 2867 return false; 2868 } 2869 } 2870 } 2871 2872 //--------------------------------------------------------------------------------- 2873 /* Configure ePNO/PNO */ 2874 private static PnoEventHandler sPnoEventHandler; 2875 private static int sPnoCmdId = 0; 2876 2877 private static native boolean setPnoListNative(int iface, int id, PnoSettings settings); 2878 2879 /** 2880 * Set the PNO settings & the network list in HAL to start PNO. 2881 * @param settings PNO settings and network list. 2882 * @param eventHandler Handler to receive notifications back during PNO scan. 2883 * @return true if success, false otherwise 2884 */ 2885 public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) { 2886 Log.e(TAG, "setPnoList cmd " + sPnoCmdId); 2887 2888 synchronized (sLock) { 2889 if (isHalStarted()) { 2890 sPnoCmdId = getNewCmdIdLocked(); 2891 sPnoEventHandler = eventHandler; 2892 if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) { 2893 return true; 2894 } 2895 } 2896 sPnoEventHandler = null; 2897 return false; 2898 } 2899 } 2900 2901 /** 2902 * Set the PNO network list in HAL to start PNO. 2903 * @param list PNO network list. 2904 * @param eventHandler Handler to receive notifications back during PNO scan. 2905 * @return true if success, false otherwise 2906 */ 2907 public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) { 2908 PnoSettings settings = new PnoSettings(); 2909 settings.networkList = list; 2910 return setPnoList(settings, eventHandler); 2911 } 2912 2913 private static native boolean resetPnoListNative(int iface, int id); 2914 2915 /** 2916 * Reset the PNO settings in HAL to stop PNO. 2917 * @return true if success, false otherwise 2918 */ 2919 public boolean resetPnoList() { 2920 Log.e(TAG, "resetPnoList cmd " + sPnoCmdId); 2921 2922 synchronized (sLock) { 2923 if (isHalStarted()) { 2924 sPnoCmdId = getNewCmdIdLocked(); 2925 sPnoEventHandler = null; 2926 if (resetPnoListNative(sWlan0Index, sPnoCmdId)) { 2927 return true; 2928 } 2929 } 2930 return false; 2931 } 2932 } 2933 2934 // Callback from native 2935 private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) { 2936 if (results == null) { 2937 Log.e(TAG, "onPnoNetworkFound null results"); 2938 return; 2939 2940 } 2941 Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length); 2942 2943 PnoEventHandler handler = sPnoEventHandler; 2944 if (sPnoCmdId != 0 && handler != null) { 2945 for (int i=0; i<results.length; i++) { 2946 Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID 2947 + " " + results[i].level + " " + results[i].frequency); 2948 2949 populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound "); 2950 results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID); 2951 } 2952 2953 handler.onPnoNetworkFound(results); 2954 } else { 2955 /* this can happen because of race conditions */ 2956 Log.d(TAG, "Ignoring Pno Network found event"); 2957 } 2958 } 2959 2960 private native static int startSendingOffloadedPacketNative(int iface, int idx, 2961 byte[] srcMac, byte[] dstMac, byte[] pktData, int period); 2962 2963 public int 2964 startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) { 2965 Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period); 2966 2967 String[] macAddrStr = getMacAddress().split(":"); 2968 byte[] srcMac = new byte[6]; 2969 for(int i = 0; i < 6; i++) { 2970 Integer hexVal = Integer.parseInt(macAddrStr[i], 16); 2971 srcMac[i] = hexVal.byteValue(); 2972 } 2973 synchronized (sLock) { 2974 if (isHalStarted()) { 2975 return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac, 2976 keepAlivePacket.dstMac, keepAlivePacket.data, period); 2977 } else { 2978 return -1; 2979 } 2980 } 2981 } 2982 2983 private native static int stopSendingOffloadedPacketNative(int iface, int idx); 2984 2985 public int 2986 stopSendingOffloadedPacket(int slot) { 2987 Log.d(TAG, "stopSendingOffloadedPacket " + slot); 2988 synchronized (sLock) { 2989 if (isHalStarted()) { 2990 return stopSendingOffloadedPacketNative(sWlan0Index, slot); 2991 } else { 2992 return -1; 2993 } 2994 } 2995 } 2996 2997 public static interface WifiRssiEventHandler { 2998 void onRssiThresholdBreached(byte curRssi); 2999 } 3000 3001 private static WifiRssiEventHandler sWifiRssiEventHandler; 3002 3003 // Callback from native 3004 private static void onRssiThresholdBreached(int id, byte curRssi) { 3005 WifiRssiEventHandler handler = sWifiRssiEventHandler; 3006 if (handler != null) { 3007 handler.onRssiThresholdBreached(curRssi); 3008 } 3009 } 3010 3011 private native static int startRssiMonitoringNative(int iface, int id, 3012 byte maxRssi, byte minRssi); 3013 3014 private static int sRssiMonitorCmdId = 0; 3015 3016 public int startRssiMonitoring(byte maxRssi, byte minRssi, 3017 WifiRssiEventHandler rssiEventHandler) { 3018 Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi); 3019 synchronized (sLock) { 3020 sWifiRssiEventHandler = rssiEventHandler; 3021 if (isHalStarted()) { 3022 if (sRssiMonitorCmdId != 0) { 3023 stopRssiMonitoring(); 3024 } 3025 3026 sRssiMonitorCmdId = getNewCmdIdLocked(); 3027 Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); 3028 int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, 3029 maxRssi, minRssi); 3030 if (ret != 0) { // if not success 3031 sRssiMonitorCmdId = 0; 3032 } 3033 return ret; 3034 } else { 3035 return -1; 3036 } 3037 } 3038 } 3039 3040 private native static int stopRssiMonitoringNative(int iface, int idx); 3041 3042 public int stopRssiMonitoring() { 3043 Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId); 3044 synchronized (sLock) { 3045 if (isHalStarted()) { 3046 int ret = 0; 3047 if (sRssiMonitorCmdId != 0) { 3048 ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); 3049 } 3050 sRssiMonitorCmdId = 0; 3051 return ret; 3052 } else { 3053 return -1; 3054 } 3055 } 3056 } 3057 3058 private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface); 3059 3060 /** 3061 * Fetch the host wakeup reasons stats from wlan driver. 3062 * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver. 3063 */ 3064 public WifiWakeReasonAndCounts getWlanWakeReasonCount() { 3065 Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index); 3066 synchronized (sLock) { 3067 if (isHalStarted()) { 3068 return getWlanWakeReasonCountNative(sWlan0Index); 3069 } else { 3070 return null; 3071 } 3072 } 3073 } 3074 3075 private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled); 3076 3077 public boolean configureNeighborDiscoveryOffload(boolean enabled) { 3078 final String logMsg = "configureNeighborDiscoveryOffload(" + enabled + ")"; 3079 Log.d(mTAG, logMsg); 3080 synchronized (sLock) { 3081 if (isHalStarted()) { 3082 final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled); 3083 if (ret != 0) { 3084 Log.d(mTAG, logMsg + " returned: " + ret); 3085 } 3086 return (ret == 0); 3087 } 3088 } 3089 return false; 3090 } 3091 3092 // Firmware roaming control. 3093 3094 /** 3095 * Class to retrieve firmware roaming capability parameters. 3096 */ 3097 public static class RoamingCapabilities { 3098 public int maxBlacklistSize; 3099 public int maxWhitelistSize; 3100 } 3101 3102 /** 3103 * Query the firmware roaming capabilities. 3104 */ 3105 public boolean getRoamingCapabilities(RoamingCapabilities capabilities) { 3106 Log.d(TAG, "getRoamingCapabilities "); 3107 try { 3108 if (mWifiVendorHal != null) { 3109 return mWifiVendorHal.getRoamingCapabilities(capabilities); 3110 } 3111 } catch (UnsupportedOperationException e) { 3112 } 3113 3114 return false; 3115 } 3116 3117 /** 3118 * Macros for controlling firmware roaming. 3119 */ 3120 public static final int DISABLE_FIRMWARE_ROAMING = 0; 3121 public static final int ENABLE_FIRMWARE_ROAMING = 1; 3122 3123 /** 3124 * Enable/disable firmware roaming. 3125 */ 3126 public int enableFirmwareRoaming(int state) { 3127 Log.d(TAG, "enableFirmwareRoaming: state =" + state); 3128 try { 3129 if (mWifiVendorHal != null) { 3130 return mWifiVendorHal.enableFirmwareRoaming(state); 3131 } 3132 } catch (UnsupportedOperationException e) { 3133 } 3134 3135 return -1; 3136 } 3137 3138 /** 3139 * Class for specifying the roaming configurations. 3140 */ 3141 public static class RoamingConfig { 3142 public ArrayList<String> blacklistBssids; 3143 public ArrayList<String> whitelistSsids; 3144 } 3145 3146 /** 3147 * Set firmware roaming configurations. 3148 */ 3149 public boolean configureRoaming(RoamingConfig config) { 3150 Log.d(TAG, "configureRoaming "); 3151 try { 3152 if (mWifiVendorHal != null) { 3153 return mWifiVendorHal.configureRoaming(config); 3154 } 3155 } catch (UnsupportedOperationException e) { 3156 } 3157 3158 return false; 3159 } 3160 3161 3162 StackTraceElement[] mTrace; 3163 void legacyHalWarning() { 3164 Thread cur = Thread.currentThread(); 3165 mTrace = cur.getStackTrace(); 3166 StackTraceElement s = mTrace[3]; 3167 Log.e(TAG, "LEGACY HAL th " + cur.getId() 3168 + " line " + s.getLineNumber() + " " + s.getMethodName()); 3169 } 3170 3171} 3172