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