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