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