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