WifiNative.java revision ef1606e936204c56ffdae305f2f423ee3503fecd
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 @Override 1942 public int hashCode() { 1943 return (ssid == null ? 0 : ssid.hashCode()); 1944 } 1945 } 1946 1947 public static class ScanSettings { 1948 public int base_period_ms; 1949 public int max_ap_per_scan; 1950 public int report_threshold_percent; 1951 public int report_threshold_num_scans; 1952 public int num_buckets; 1953 /* Not used for bg scans. Only works for single scans. */ 1954 public HiddenNetwork[] hiddenNetworks; 1955 public BucketSettings[] buckets; 1956 } 1957 1958 /** 1959 * Network parameters to start PNO scan. 1960 */ 1961 public static class PnoNetwork { 1962 public String ssid; 1963 public byte flags; 1964 public byte auth_bit_field; 1965 1966 @Override 1967 public boolean equals(Object otherObj) { 1968 if (this == otherObj) { 1969 return true; 1970 } else if (otherObj == null || getClass() != otherObj.getClass()) { 1971 return false; 1972 } 1973 PnoNetwork other = (PnoNetwork) otherObj; 1974 return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags) 1975 && (auth_bit_field == other.auth_bit_field)); 1976 } 1977 1978 @Override 1979 public int hashCode() { 1980 int result = (ssid == null ? 0 : ssid.hashCode()); 1981 result ^= ((int) flags * 31) + ((int) auth_bit_field << 8); 1982 return result; 1983 } 1984 } 1985 1986 /** 1987 * Parameters to start PNO scan. This holds the list of networks which are going to used for 1988 * PNO scan. 1989 */ 1990 public static class PnoSettings { 1991 public int min5GHzRssi; 1992 public int min24GHzRssi; 1993 public int initialScoreMax; 1994 public int currentConnectionBonus; 1995 public int sameNetworkBonus; 1996 public int secureBonus; 1997 public int band5GHzBonus; 1998 public boolean isConnected; 1999 public PnoNetwork[] networkList; 2000 } 2001 2002 /** 2003 * Wi-Fi channel information. 2004 */ 2005 public static class WifiChannelInfo { 2006 int mPrimaryFrequency; 2007 int mCenterFrequency0; 2008 int mCenterFrequency1; 2009 int mChannelWidth; 2010 // TODO: add preamble once available in HAL. 2011 } 2012 2013 /** 2014 * Result of a signal poll. 2015 */ 2016 public static class SignalPollResult { 2017 // RSSI value in dBM. 2018 public int currentRssi; 2019 //Transmission bit rate in Mbps. 2020 public int txBitrate; 2021 // Association frequency in MHz. 2022 public int associationFrequency; 2023 } 2024 2025 /** 2026 * WiFi interface transimission counters. 2027 */ 2028 public static class TxPacketCounters { 2029 // Number of successfully transmitted packets. 2030 public int txSucceeded; 2031 // Number of tramsmission failures. 2032 public int txFailed; 2033 } 2034 2035 public static interface ScanEventHandler { 2036 /** 2037 * Called for each AP as it is found with the entire contents of the beacon/probe response. 2038 * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified. 2039 */ 2040 void onFullScanResult(ScanResult fullScanResult, int bucketsScanned); 2041 /** 2042 * Callback on an event during a gscan scan. 2043 * See WifiNative.WIFI_SCAN_* for possible values. 2044 */ 2045 void onScanStatus(int event); 2046 /** 2047 * Called with the current cached scan results when gscan is paused. 2048 */ 2049 void onScanPaused(WifiScanner.ScanData[] data); 2050 /** 2051 * Called with the current cached scan results when gscan is resumed. 2052 */ 2053 void onScanRestarted(); 2054 } 2055 2056 /** 2057 * Handler to notify the occurrence of various events during PNO scan. 2058 */ 2059 public interface PnoEventHandler { 2060 /** 2061 * Callback to notify when one of the shortlisted networks is found during PNO scan. 2062 * @param results List of Scan results received. 2063 */ 2064 void onPnoNetworkFound(ScanResult[] results); 2065 2066 /** 2067 * Callback to notify when the PNO scan schedule fails. 2068 */ 2069 void onPnoScanFailed(); 2070 } 2071 2072 /* scan status, keep these values in sync with gscan.h */ 2073 public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0; 2074 public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1; 2075 public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2; 2076 public static final int WIFI_SCAN_FAILED = 3; 2077 2078 // Callback from native 2079 private static void onScanStatus(int id, int event) { 2080 ScanEventHandler handler = sScanEventHandler; 2081 if (handler != null) { 2082 handler.onScanStatus(event); 2083 } 2084 } 2085 2086 public static WifiSsid createWifiSsid(byte[] rawSsid) { 2087 String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid)); 2088 2089 if (ssidHexString == null) { 2090 return null; 2091 } 2092 2093 WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString); 2094 2095 return wifiSsid; 2096 } 2097 2098 public static String ssidConvert(byte[] rawSsid) { 2099 String ssid; 2100 2101 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 2102 try { 2103 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid)); 2104 ssid = decoded.toString(); 2105 } catch (CharacterCodingException cce) { 2106 ssid = null; 2107 } 2108 2109 if (ssid == null) { 2110 ssid = new String(rawSsid, StandardCharsets.ISO_8859_1); 2111 } 2112 2113 return ssid; 2114 } 2115 2116 // Called from native 2117 public static boolean setSsid(byte[] rawSsid, ScanResult result) { 2118 if (rawSsid == null || rawSsid.length == 0 || result == null) { 2119 return false; 2120 } 2121 2122 result.SSID = ssidConvert(rawSsid); 2123 result.wifiSsid = createWifiSsid(rawSsid); 2124 return true; 2125 } 2126 2127 private static void populateScanResult(ScanResult result, int beaconCap, String dbg) { 2128 if (dbg == null) dbg = ""; 2129 2130 InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation(); 2131 InformationElementUtil.VhtOperation vhtOperation = 2132 new InformationElementUtil.VhtOperation(); 2133 InformationElementUtil.ExtendedCapabilities extendedCaps = 2134 new InformationElementUtil.ExtendedCapabilities(); 2135 2136 ScanResult.InformationElement elements[] = 2137 InformationElementUtil.parseInformationElements(result.bytes); 2138 for (ScanResult.InformationElement ie : elements) { 2139 if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) { 2140 htOperation.from(ie); 2141 } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) { 2142 vhtOperation.from(ie); 2143 } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) { 2144 extendedCaps.from(ie); 2145 } 2146 } 2147 2148 if (extendedCaps.is80211McRTTResponder()) { 2149 result.setFlag(ScanResult.FLAG_80211mc_RESPONDER); 2150 } else { 2151 result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER); 2152 } 2153 2154 //handle RTT related information 2155 if (vhtOperation.isValid()) { 2156 result.channelWidth = vhtOperation.getChannelWidth(); 2157 result.centerFreq0 = vhtOperation.getCenterFreq0(); 2158 result.centerFreq1 = vhtOperation.getCenterFreq1(); 2159 } else { 2160 result.channelWidth = htOperation.getChannelWidth(); 2161 result.centerFreq0 = htOperation.getCenterFreq0(result.frequency); 2162 result.centerFreq1 = 0; 2163 } 2164 2165 // build capabilities string 2166 BitSet beaconCapBits = new BitSet(16); 2167 for (int i = 0; i < 16; i++) { 2168 if ((beaconCap & (1 << i)) != 0) { 2169 beaconCapBits.set(i); 2170 } 2171 } 2172 InformationElementUtil.Capabilities capabilities = 2173 new InformationElementUtil.Capabilities(); 2174 capabilities.from(elements, beaconCapBits); 2175 result.capabilities = capabilities.generateCapabilitiesString(); 2176 2177 if(DBG) { 2178 Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth 2179 + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0 2180 + " mCenterfreq1: " + result.centerFreq1 2181 + (extendedCaps.is80211McRTTResponder() ? "Support RTT reponder: " 2182 : "Do not support RTT responder") 2183 + " Capabilities: " + result.capabilities); 2184 } 2185 2186 result.informationElements = elements; 2187 } 2188 2189 // Callback from native 2190 private static void onFullScanResult(int id, ScanResult result, 2191 int bucketsScanned, int beaconCap) { 2192 if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID); 2193 2194 ScanEventHandler handler = sScanEventHandler; 2195 if (handler != null) { 2196 populateScanResult(result, beaconCap, " onFullScanResult "); 2197 handler.onFullScanResult(result, bucketsScanned); 2198 } 2199 } 2200 2201 private static int sScanCmdId = 0; 2202 private static ScanEventHandler sScanEventHandler; 2203 private static ScanSettings sScanSettings; 2204 2205 public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) { 2206 synchronized (sLock) { 2207 if (isHalStarted()) { 2208 if (sScanCmdId != 0) { 2209 stopScan(); 2210 } else if (sScanSettings != null || sScanEventHandler != null) { 2211 /* current scan is paused; no need to stop it */ 2212 } 2213 2214 sScanCmdId = getNewCmdIdLocked(); 2215 2216 sScanSettings = settings; 2217 sScanEventHandler = eventHandler; 2218 2219 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) { 2220 sScanEventHandler = null; 2221 sScanSettings = null; 2222 sScanCmdId = 0; 2223 return false; 2224 } 2225 2226 return true; 2227 } else { 2228 return false; 2229 } 2230 } 2231 } 2232 2233 public void stopScan() { 2234 synchronized (sLock) { 2235 if (isHalStarted()) { 2236 if (sScanCmdId != 0) { 2237 stopScanNative(sWlan0Index, sScanCmdId); 2238 } 2239 sScanSettings = null; 2240 sScanEventHandler = null; 2241 sScanCmdId = 0; 2242 } 2243 } 2244 } 2245 2246 public void pauseScan() { 2247 synchronized (sLock) { 2248 if (isHalStarted()) { 2249 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) { 2250 Log.d(TAG, "Pausing scan"); 2251 WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true); 2252 stopScanNative(sWlan0Index, sScanCmdId); 2253 sScanCmdId = 0; 2254 sScanEventHandler.onScanPaused(scanData); 2255 } 2256 } 2257 } 2258 } 2259 2260 public void restartScan() { 2261 synchronized (sLock) { 2262 if (isHalStarted()) { 2263 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) { 2264 Log.d(TAG, "Restarting scan"); 2265 ScanEventHandler handler = sScanEventHandler; 2266 ScanSettings settings = sScanSettings; 2267 if (startScan(sScanSettings, sScanEventHandler)) { 2268 sScanEventHandler.onScanRestarted(); 2269 } else { 2270 /* we are still paused; don't change state */ 2271 sScanEventHandler = handler; 2272 sScanSettings = settings; 2273 } 2274 } 2275 } 2276 } 2277 } 2278 2279 public WifiScanner.ScanData[] getScanResults(boolean flush) { 2280 synchronized (sLock) { 2281 WifiScanner.ScanData[] sd = null; 2282 if (isHalStarted()) { 2283 sd = getScanResultsNative(sWlan0Index, flush); 2284 } 2285 2286 if (sd != null) { 2287 return sd; 2288 } else { 2289 return new WifiScanner.ScanData[0]; 2290 } 2291 } 2292 } 2293 2294 public static interface HotlistEventHandler { 2295 void onHotlistApFound (ScanResult[] result); 2296 void onHotlistApLost (ScanResult[] result); 2297 } 2298 2299 private static int sHotlistCmdId = 0; 2300 private static HotlistEventHandler sHotlistEventHandler; 2301 2302 private native static boolean setHotlistNative(int iface, int id, 2303 WifiScanner.HotlistSettings settings); 2304 private native static boolean resetHotlistNative(int iface, int id); 2305 2306 public boolean setHotlist(WifiScanner.HotlistSettings settings, 2307 HotlistEventHandler eventHandler) { 2308 synchronized (sLock) { 2309 if (isHalStarted()) { 2310 if (sHotlistCmdId != 0) { 2311 return false; 2312 } else { 2313 sHotlistCmdId = getNewCmdIdLocked(); 2314 } 2315 2316 sHotlistEventHandler = eventHandler; 2317 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) { 2318 sHotlistEventHandler = null; 2319 return false; 2320 } 2321 2322 return true; 2323 } else { 2324 return false; 2325 } 2326 } 2327 } 2328 2329 public void resetHotlist() { 2330 synchronized (sLock) { 2331 if (isHalStarted()) { 2332 if (sHotlistCmdId != 0) { 2333 resetHotlistNative(sWlan0Index, sHotlistCmdId); 2334 sHotlistCmdId = 0; 2335 sHotlistEventHandler = null; 2336 } 2337 } 2338 } 2339 } 2340 2341 // Callback from native 2342 private static void onHotlistApFound(int id, ScanResult[] results) { 2343 HotlistEventHandler handler = sHotlistEventHandler; 2344 if (handler != null) { 2345 handler.onHotlistApFound(results); 2346 } else { 2347 /* this can happen because of race conditions */ 2348 Log.d(TAG, "Ignoring hotlist AP found event"); 2349 } 2350 } 2351 2352 // Callback from native 2353 private static void onHotlistApLost(int id, ScanResult[] results) { 2354 HotlistEventHandler handler = sHotlistEventHandler; 2355 if (handler != null) { 2356 handler.onHotlistApLost(results); 2357 } else { 2358 /* this can happen because of race conditions */ 2359 Log.d(TAG, "Ignoring hotlist AP lost event"); 2360 } 2361 } 2362 2363 public static interface SignificantWifiChangeEventHandler { 2364 void onChangesFound(ScanResult[] result); 2365 } 2366 2367 private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler; 2368 private static int sSignificantWifiChangeCmdId; 2369 2370 private static native boolean trackSignificantWifiChangeNative( 2371 int iface, int id, WifiScanner.WifiChangeSettings settings); 2372 private static native boolean untrackSignificantWifiChangeNative(int iface, int id); 2373 2374 public boolean trackSignificantWifiChange( 2375 WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) { 2376 synchronized (sLock) { 2377 if (isHalStarted()) { 2378 if (sSignificantWifiChangeCmdId != 0) { 2379 return false; 2380 } else { 2381 sSignificantWifiChangeCmdId = getNewCmdIdLocked(); 2382 } 2383 2384 sSignificantWifiChangeHandler = handler; 2385 if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId, 2386 settings) == false) { 2387 sSignificantWifiChangeHandler = null; 2388 return false; 2389 } 2390 2391 return true; 2392 } else { 2393 return false; 2394 } 2395 2396 } 2397 } 2398 2399 public void untrackSignificantWifiChange() { 2400 synchronized (sLock) { 2401 if (isHalStarted()) { 2402 if (sSignificantWifiChangeCmdId != 0) { 2403 untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId); 2404 sSignificantWifiChangeCmdId = 0; 2405 sSignificantWifiChangeHandler = null; 2406 } 2407 } 2408 } 2409 } 2410 2411 // Callback from native 2412 private static void onSignificantWifiChange(int id, ScanResult[] results) { 2413 SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler; 2414 if (handler != null) { 2415 handler.onChangesFound(results); 2416 } else { 2417 /* this can happen because of race conditions */ 2418 Log.d(TAG, "Ignoring significant wifi change"); 2419 } 2420 } 2421 2422 public WifiLinkLayerStats getWifiLinkLayerStats(String iface) { 2423 // TODO: use correct iface name to Index translation 2424 if (iface == null) return null; 2425 synchronized (sLock) { 2426 if (isHalStarted()) { 2427 return getWifiLinkLayerStatsNative(sWlan0Index); 2428 } else { 2429 return null; 2430 } 2431 } 2432 } 2433 2434 public void setWifiLinkLayerStats(String iface, int enable) { 2435 if (iface == null) return; 2436 synchronized (sLock) { 2437 if (isHalStarted()) { 2438 setWifiLinkLayerStatsNative(sWlan0Index, enable); 2439 } 2440 } 2441 } 2442 2443 public static native int getSupportedFeatureSetNative(int iface); 2444 public int getSupportedFeatureSet() { 2445 synchronized (sLock) { 2446 if (isHalStarted()) { 2447 return getSupportedFeatureSetNative(sWlan0Index); 2448 } else { 2449 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started"); 2450 return 0; 2451 } 2452 } 2453 } 2454 2455 /* Rtt related commands/events */ 2456 public static interface RttEventHandler { 2457 void onRttResults(RttManager.RttResult[] result); 2458 } 2459 2460 private static RttEventHandler sRttEventHandler; 2461 private static int sRttCmdId; 2462 2463 // Callback from native 2464 private static void onRttResults(int id, RttManager.RttResult[] results) { 2465 RttEventHandler handler = sRttEventHandler; 2466 if (handler != null && id == sRttCmdId) { 2467 Log.d(TAG, "Received " + results.length + " rtt results"); 2468 handler.onRttResults(results); 2469 sRttCmdId = 0; 2470 } else { 2471 Log.d(TAG, "RTT Received event for unknown cmd = " + id + 2472 ", current id = " + sRttCmdId); 2473 } 2474 } 2475 2476 private static native boolean requestRangeNative( 2477 int iface, int id, RttManager.RttParams[] params); 2478 private static native boolean cancelRangeRequestNative( 2479 int iface, int id, RttManager.RttParams[] params); 2480 2481 public boolean requestRtt( 2482 RttManager.RttParams[] params, RttEventHandler handler) { 2483 synchronized (sLock) { 2484 if (isHalStarted()) { 2485 if (sRttCmdId != 0) { 2486 Log.w(TAG, "Last one is still under measurement!"); 2487 return false; 2488 } else { 2489 sRttCmdId = getNewCmdIdLocked(); 2490 } 2491 sRttEventHandler = handler; 2492 return requestRangeNative(sWlan0Index, sRttCmdId, params); 2493 } else { 2494 return false; 2495 } 2496 } 2497 } 2498 2499 public boolean cancelRtt(RttManager.RttParams[] params) { 2500 synchronized (sLock) { 2501 if (isHalStarted()) { 2502 if (sRttCmdId == 0) { 2503 return false; 2504 } 2505 2506 sRttCmdId = 0; 2507 2508 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) { 2509 sRttEventHandler = null; 2510 return true; 2511 } else { 2512 Log.e(TAG, "RTT cancel Request failed"); 2513 return false; 2514 } 2515 } else { 2516 return false; 2517 } 2518 } 2519 } 2520 2521 private static int sRttResponderCmdId = 0; 2522 2523 private static native ResponderConfig enableRttResponderNative(int iface, int commandId, 2524 int timeoutSeconds, WifiChannelInfo channelHint); 2525 /** 2526 * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder 2527 * role is successfully enabled, {@code null} otherwise. 2528 */ 2529 @Nullable 2530 public ResponderConfig enableRttResponder(int timeoutSeconds) { 2531 synchronized (sLock) { 2532 if (!isHalStarted()) return null; 2533 if (sRttResponderCmdId != 0) { 2534 if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen"); 2535 return null; 2536 } 2537 int id = getNewCmdIdLocked(); 2538 ResponderConfig config = enableRttResponderNative( 2539 sWlan0Index, id, timeoutSeconds, null); 2540 if (config != null) sRttResponderCmdId = id; 2541 if (DBG) Log.d(TAG, "enabling rtt " + (config != null)); 2542 return config; 2543 } 2544 } 2545 2546 private static native boolean disableRttResponderNative(int iface, int commandId); 2547 /** 2548 * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled, 2549 * {@code false} otherwise. 2550 */ 2551 public boolean disableRttResponder() { 2552 synchronized (sLock) { 2553 if (!isHalStarted()) return false; 2554 if (sRttResponderCmdId == 0) { 2555 Log.e(mTAG, "responder role not enabled yet"); 2556 return true; 2557 } 2558 sRttResponderCmdId = 0; 2559 return disableRttResponderNative(sWlan0Index, sRttResponderCmdId); 2560 } 2561 } 2562 2563 private static native boolean setScanningMacOuiNative(int iface, byte[] oui); 2564 2565 public boolean setScanningMacOui(byte[] oui) { 2566 synchronized (sLock) { 2567 if (isHalStarted()) { 2568 return setScanningMacOuiNative(sWlan0Index, oui); 2569 } else { 2570 return false; 2571 } 2572 } 2573 } 2574 2575 private static native int[] getChannelsForBandNative( 2576 int iface, int band); 2577 2578 public int [] getChannelsForBand(int band) { 2579 synchronized (sLock) { 2580 if (isHalStarted()) { 2581 return getChannelsForBandNative(sWlan0Index, band); 2582 } else { 2583 return null; 2584 } 2585 } 2586 } 2587 2588 private static native boolean isGetChannelsForBandSupportedNative(); 2589 public boolean isGetChannelsForBandSupported(){ 2590 synchronized (sLock) { 2591 if (isHalStarted()) { 2592 return isGetChannelsForBandSupportedNative(); 2593 } else { 2594 return false; 2595 } 2596 } 2597 } 2598 2599 private static native boolean setDfsFlagNative(int iface, boolean dfsOn); 2600 public boolean setDfsFlag(boolean dfsOn) { 2601 synchronized (sLock) { 2602 if (isHalStarted()) { 2603 return setDfsFlagNative(sWlan0Index, dfsOn); 2604 } else { 2605 return false; 2606 } 2607 } 2608 } 2609 2610 private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface); 2611 public RttManager.RttCapabilities getRttCapabilities() { 2612 synchronized (sLock) { 2613 if (isHalStarted()) { 2614 return getRttCapabilitiesNative(sWlan0Index); 2615 } else { 2616 return null; 2617 } 2618 } 2619 } 2620 2621 private static native ApfCapabilities getApfCapabilitiesNative(int iface); 2622 public ApfCapabilities getApfCapabilities() { 2623 synchronized (sLock) { 2624 if (isHalStarted()) { 2625 return getApfCapabilitiesNative(sWlan0Index); 2626 } else { 2627 return null; 2628 } 2629 } 2630 } 2631 2632 private static native boolean installPacketFilterNative(int iface, byte[] filter); 2633 public boolean installPacketFilter(byte[] filter) { 2634 synchronized (sLock) { 2635 if (isHalStarted()) { 2636 return installPacketFilterNative(sWlan0Index, filter); 2637 } else { 2638 return false; 2639 } 2640 } 2641 } 2642 2643 private static native boolean setCountryCodeHalNative(int iface, String CountryCode); 2644 public boolean setCountryCodeHal(String CountryCode) { 2645 synchronized (sLock) { 2646 if (isHalStarted()) { 2647 return setCountryCodeHalNative(sWlan0Index, CountryCode); 2648 } else { 2649 return false; 2650 } 2651 } 2652 } 2653 2654 /* Rtt related commands/events */ 2655 public abstract class TdlsEventHandler { 2656 abstract public void onTdlsStatus(String macAddr, int status, int reason); 2657 } 2658 2659 private static TdlsEventHandler sTdlsEventHandler; 2660 2661 private static native boolean enableDisableTdlsNative(int iface, boolean enable, 2662 String macAddr); 2663 public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) { 2664 synchronized (sLock) { 2665 sTdlsEventHandler = tdlsCallBack; 2666 return enableDisableTdlsNative(sWlan0Index, enable, macAdd); 2667 } 2668 } 2669 2670 // Once TDLS per mac and event feature is implemented, this class definition should be 2671 // moved to the right place, like WifiManager etc 2672 public static class TdlsStatus { 2673 int channel; 2674 int global_operating_class; 2675 int state; 2676 int reason; 2677 } 2678 private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr); 2679 public TdlsStatus getTdlsStatus(String macAdd) { 2680 synchronized (sLock) { 2681 if (isHalStarted()) { 2682 return getTdlsStatusNative(sWlan0Index, macAdd); 2683 } else { 2684 return null; 2685 } 2686 } 2687 } 2688 2689 //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be 2690 // moved to the right place, like WifiStateMachine etc 2691 public static class TdlsCapabilities { 2692 /* Maximum TDLS session number can be supported by the Firmware and hardware */ 2693 int maxConcurrentTdlsSessionNumber; 2694 boolean isGlobalTdlsSupported; 2695 boolean isPerMacTdlsSupported; 2696 boolean isOffChannelTdlsSupported; 2697 } 2698 2699 2700 2701 private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface); 2702 public TdlsCapabilities getTdlsCapabilities () { 2703 synchronized (sLock) { 2704 if (isHalStarted()) { 2705 return getTdlsCapabilitiesNative(sWlan0Index); 2706 } else { 2707 return null; 2708 } 2709 } 2710 } 2711 2712 private static boolean onTdlsStatus(String macAddr, int status, int reason) { 2713 TdlsEventHandler handler = sTdlsEventHandler; 2714 if (handler == null) { 2715 return false; 2716 } else { 2717 handler.onTdlsStatus(macAddr, status, reason); 2718 return true; 2719 } 2720 } 2721 2722 //--------------------------------------------------------------------------------- 2723 2724 /* Wifi Logger commands/events */ 2725 2726 public static interface WifiLoggerEventHandler { 2727 void onRingBufferData(RingBufferStatus status, byte[] buffer); 2728 void onWifiAlert(int errorCode, byte[] buffer); 2729 } 2730 2731 private static WifiLoggerEventHandler sWifiLoggerEventHandler = null; 2732 2733 // Callback from native 2734 private static void onRingBufferData(RingBufferStatus status, byte[] buffer) { 2735 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2736 if (handler != null) 2737 handler.onRingBufferData(status, buffer); 2738 } 2739 2740 // Callback from native 2741 private static void onWifiAlert(byte[] buffer, int errorCode) { 2742 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2743 if (handler != null) 2744 handler.onWifiAlert(errorCode, buffer); 2745 } 2746 2747 private static int sLogCmdId = -1; 2748 private static native boolean setLoggingEventHandlerNative(int iface, int id); 2749 public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 2750 synchronized (sLock) { 2751 if (isHalStarted()) { 2752 int oldId = sLogCmdId; 2753 sLogCmdId = getNewCmdIdLocked(); 2754 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) { 2755 sLogCmdId = oldId; 2756 return false; 2757 } 2758 sWifiLoggerEventHandler = handler; 2759 return true; 2760 } else { 2761 return false; 2762 } 2763 } 2764 } 2765 2766 private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel, 2767 int flags, int minIntervalSec ,int minDataSize, String ringName); 2768 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 2769 int minDataSize, String ringName){ 2770 synchronized (sLock) { 2771 if (isHalStarted()) { 2772 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval, 2773 minDataSize, ringName); 2774 } else { 2775 return false; 2776 } 2777 } 2778 } 2779 2780 private static native int getSupportedLoggerFeatureSetNative(int iface); 2781 public int getSupportedLoggerFeatureSet() { 2782 synchronized (sLock) { 2783 if (isHalStarted()) { 2784 return getSupportedLoggerFeatureSetNative(sWlan0Index); 2785 } else { 2786 return 0; 2787 } 2788 } 2789 } 2790 2791 private static native boolean resetLogHandlerNative(int iface, int id); 2792 public boolean resetLogHandler() { 2793 synchronized (sLock) { 2794 if (isHalStarted()) { 2795 if (sLogCmdId == -1) { 2796 Log.e(TAG,"Can not reset handler Before set any handler"); 2797 return false; 2798 } 2799 sWifiLoggerEventHandler = null; 2800 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) { 2801 sLogCmdId = -1; 2802 return true; 2803 } else { 2804 return false; 2805 } 2806 } else { 2807 return false; 2808 } 2809 } 2810 } 2811 2812 private static native String getDriverVersionNative(int iface); 2813 public String getDriverVersion() { 2814 synchronized (sLock) { 2815 if (isHalStarted()) { 2816 return getDriverVersionNative(sWlan0Index); 2817 } else { 2818 return ""; 2819 } 2820 } 2821 } 2822 2823 2824 private static native String getFirmwareVersionNative(int iface); 2825 public String getFirmwareVersion() { 2826 synchronized (sLock) { 2827 if (isHalStarted()) { 2828 return getFirmwareVersionNative(sWlan0Index); 2829 } else { 2830 return ""; 2831 } 2832 } 2833 } 2834 2835 public static class RingBufferStatus{ 2836 String name; 2837 int flag; 2838 int ringBufferId; 2839 int ringBufferByteSize; 2840 int verboseLevel; 2841 int writtenBytes; 2842 int readBytes; 2843 int writtenRecords; 2844 2845 // Bit masks for interpreting |flag| 2846 public static final int HAS_BINARY_ENTRIES = (1 << 0); 2847 public static final int HAS_ASCII_ENTRIES = (1 << 1); 2848 public static final int HAS_PER_PACKET_ENTRIES = (1 << 2); 2849 2850 @Override 2851 public String toString() { 2852 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 2853 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 2854 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 2855 " writtenRecords: " + writtenRecords; 2856 } 2857 } 2858 2859 private static native RingBufferStatus[] getRingBufferStatusNative(int iface); 2860 public RingBufferStatus[] getRingBufferStatus() { 2861 synchronized (sLock) { 2862 if (isHalStarted()) { 2863 return getRingBufferStatusNative(sWlan0Index); 2864 } else { 2865 return null; 2866 } 2867 } 2868 } 2869 2870 private static native boolean getRingBufferDataNative(int iface, String ringName); 2871 public boolean getRingBufferData(String ringName) { 2872 synchronized (sLock) { 2873 if (isHalStarted()) { 2874 return getRingBufferDataNative(sWlan0Index, ringName); 2875 } else { 2876 return false; 2877 } 2878 } 2879 } 2880 2881 private static byte[] mFwMemoryDump; 2882 // Callback from native 2883 private static void onWifiFwMemoryAvailable(byte[] buffer) { 2884 mFwMemoryDump = buffer; 2885 if (DBG) { 2886 Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " + 2887 (buffer == null ? 0 : buffer.length)); 2888 } 2889 } 2890 2891 private static native boolean getFwMemoryDumpNative(int iface); 2892 public byte[] getFwMemoryDump() { 2893 synchronized (sLock) { 2894 if (isHalStarted()) { 2895 if(getFwMemoryDumpNative(sWlan0Index)) { 2896 byte[] fwMemoryDump = mFwMemoryDump; 2897 mFwMemoryDump = null; 2898 return fwMemoryDump; 2899 } else { 2900 return null; 2901 } 2902 } 2903 return null; 2904 } 2905 } 2906 2907 private static native byte[] getDriverStateDumpNative(int iface); 2908 /** Fetch the driver state, for driver debugging. */ 2909 public byte[] getDriverStateDump() { 2910 synchronized (sLock) { 2911 if (isHalStarted()) { 2912 return getDriverStateDumpNative(sWlan0Index); 2913 } else { 2914 return null; 2915 } 2916 } 2917 } 2918 2919 //--------------------------------------------------------------------------------- 2920 /* Packet fate API */ 2921 2922 @Immutable 2923 abstract static class FateReport { 2924 final static int USEC_PER_MSEC = 1000; 2925 // The driver timestamp is a 32-bit counter, in microseconds. This field holds the 2926 // maximal value of a driver timestamp in milliseconds. 2927 final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000); 2928 final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); 2929 2930 final byte mFate; 2931 final long mDriverTimestampUSec; 2932 final byte mFrameType; 2933 final byte[] mFrameBytes; 2934 final long mEstimatedWallclockMSec; 2935 2936 FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2937 mFate = fate; 2938 mDriverTimestampUSec = driverTimestampUSec; 2939 mEstimatedWallclockMSec = 2940 convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec); 2941 mFrameType = frameType; 2942 mFrameBytes = frameBytes; 2943 } 2944 2945 public String toTableRowString() { 2946 StringWriter sw = new StringWriter(); 2947 PrintWriter pw = new PrintWriter(sw); 2948 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2949 dateFormatter.setTimeZone(TimeZone.getDefault()); 2950 pw.format("%-15s %12s %-9s %-32s %-12s %-23s %s\n", 2951 mDriverTimestampUSec, 2952 dateFormatter.format(new Date(mEstimatedWallclockMSec)), 2953 directionToString(), fateToString(), parser.mMostSpecificProtocolString, 2954 parser.mTypeString, parser.mResultString); 2955 return sw.toString(); 2956 } 2957 2958 public String toVerboseStringWithPiiAllowed() { 2959 StringWriter sw = new StringWriter(); 2960 PrintWriter pw = new PrintWriter(sw); 2961 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2962 pw.format("Frame direction: %s\n", directionToString()); 2963 pw.format("Frame timestamp: %d\n", mDriverTimestampUSec); 2964 pw.format("Frame fate: %s\n", fateToString()); 2965 pw.format("Frame type: %s\n", frameTypeToString(mFrameType)); 2966 pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString); 2967 pw.format("Frame protocol type: %s\n", parser.mTypeString); 2968 pw.format("Frame length: %d\n", mFrameBytes.length); 2969 pw.append("Frame bytes"); 2970 pw.append(HexDump.dumpHexString(mFrameBytes)); // potentially contains PII 2971 pw.append("\n"); 2972 return sw.toString(); 2973 } 2974 2975 /* Returns a header to match the output of toTableRowString(). */ 2976 public static String getTableHeader() { 2977 StringWriter sw = new StringWriter(); 2978 PrintWriter pw = new PrintWriter(sw); 2979 pw.format("\n%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2980 "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result"); 2981 pw.format("%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2982 "---------", "--------", "---------", "----", "--------", "----", "------"); 2983 return sw.toString(); 2984 } 2985 2986 protected abstract String directionToString(); 2987 2988 protected abstract String fateToString(); 2989 2990 private static String frameTypeToString(byte frameType) { 2991 switch (frameType) { 2992 case WifiLoggerHal.FRAME_TYPE_UNKNOWN: 2993 return "unknown"; 2994 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II: 2995 return "data"; 2996 case WifiLoggerHal.FRAME_TYPE_80211_MGMT: 2997 return "802.11 management"; 2998 default: 2999 return Byte.toString(frameType); 3000 } 3001 } 3002 3003 /** 3004 * Converts a driver timestamp to a wallclock time, based on the current 3005 * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of 3006 * microseconds, with the same base as BOOTTIME. 3007 */ 3008 private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) { 3009 final long wallclockMillisNow = System.currentTimeMillis(); 3010 final long boottimeMillisNow = SystemClock.elapsedRealtime(); 3011 final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC; 3012 3013 long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC; 3014 if (boottimeTimestampMillis < driverTimestampMillis) { 3015 // The 32-bit microsecond count has wrapped between the time that the driver 3016 // recorded the packet, and the call to this function. Adjust the BOOTTIME 3017 // timestamp, to compensate. 3018 // 3019 // Note that overflow is not a concern here, since the result is less than 3020 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above, 3021 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since 3022 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit 3023 // within a long. 3024 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC; 3025 } 3026 3027 final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis; 3028 return wallclockMillisNow - millisSincePacketTimestamp; 3029 } 3030 } 3031 3032 /** 3033 * Represents the fate information for one outbound packet. 3034 */ 3035 @Immutable 3036 public static final class TxFateReport extends FateReport { 3037 TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 3038 super(fate, driverTimestampUSec, frameType, frameBytes); 3039 } 3040 3041 @Override 3042 protected String directionToString() { 3043 return "TX"; 3044 } 3045 3046 @Override 3047 protected String fateToString() { 3048 switch (mFate) { 3049 case WifiLoggerHal.TX_PKT_FATE_ACKED: 3050 return "acked"; 3051 case WifiLoggerHal.TX_PKT_FATE_SENT: 3052 return "sent"; 3053 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED: 3054 return "firmware queued"; 3055 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID: 3056 return "firmware dropped (invalid frame)"; 3057 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS: 3058 return "firmware dropped (no bufs)"; 3059 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER: 3060 return "firmware dropped (other)"; 3061 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED: 3062 return "driver queued"; 3063 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID: 3064 return "driver dropped (invalid frame)"; 3065 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS: 3066 return "driver dropped (no bufs)"; 3067 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER: 3068 return "driver dropped (other)"; 3069 default: 3070 return Byte.toString(mFate); 3071 } 3072 } 3073 } 3074 3075 /** 3076 * Represents the fate information for one inbound packet. 3077 */ 3078 @Immutable 3079 public static final class RxFateReport extends FateReport { 3080 RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 3081 super(fate, driverTimestampUSec, frameType, frameBytes); 3082 } 3083 3084 @Override 3085 protected String directionToString() { 3086 return "RX"; 3087 } 3088 3089 @Override 3090 protected String fateToString() { 3091 switch (mFate) { 3092 case WifiLoggerHal.RX_PKT_FATE_SUCCESS: 3093 return "success"; 3094 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED: 3095 return "firmware queued"; 3096 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER: 3097 return "firmware dropped (filter)"; 3098 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID: 3099 return "firmware dropped (invalid frame)"; 3100 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS: 3101 return "firmware dropped (no bufs)"; 3102 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER: 3103 return "firmware dropped (other)"; 3104 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED: 3105 return "driver queued"; 3106 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER: 3107 return "driver dropped (filter)"; 3108 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID: 3109 return "driver dropped (invalid frame)"; 3110 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS: 3111 return "driver dropped (no bufs)"; 3112 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER: 3113 return "driver dropped (other)"; 3114 default: 3115 return Byte.toString(mFate); 3116 } 3117 } 3118 } 3119 3120 private static native int startPktFateMonitoringNative(int iface); 3121 /** 3122 * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started. 3123 */ 3124 public boolean startPktFateMonitoring() { 3125 synchronized (sLock) { 3126 if (isHalStarted()) { 3127 return startPktFateMonitoringNative(sWlan0Index) == WIFI_SUCCESS; 3128 } else { 3129 return false; 3130 } 3131 } 3132 } 3133 3134 private static native int getTxPktFatesNative(int iface, TxFateReport[] reportBufs); 3135 /** 3136 * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started. 3137 */ 3138 public boolean getTxPktFates(TxFateReport[] reportBufs) { 3139 synchronized (sLock) { 3140 if (isHalStarted()) { 3141 int res = getTxPktFatesNative(sWlan0Index, reportBufs); 3142 if (res != WIFI_SUCCESS) { 3143 Log.e(TAG, "getTxPktFatesNative returned " + res); 3144 return false; 3145 } else { 3146 return true; 3147 } 3148 } else { 3149 return false; 3150 } 3151 } 3152 } 3153 3154 private static native int getRxPktFatesNative(int iface, RxFateReport[] reportBufs); 3155 /** 3156 * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started. 3157 */ 3158 public boolean getRxPktFates(RxFateReport[] reportBufs) { 3159 synchronized (sLock) { 3160 if (isHalStarted()) { 3161 int res = getRxPktFatesNative(sWlan0Index, reportBufs); 3162 if (res != WIFI_SUCCESS) { 3163 Log.e(TAG, "getRxPktFatesNative returned " + res); 3164 return false; 3165 } else { 3166 return true; 3167 } 3168 } else { 3169 return false; 3170 } 3171 } 3172 } 3173 3174 //--------------------------------------------------------------------------------- 3175 /* Configure ePNO/PNO */ 3176 private static PnoEventHandler sPnoEventHandler; 3177 private static int sPnoCmdId = 0; 3178 3179 private static native boolean setPnoListNative(int iface, int id, PnoSettings settings); 3180 3181 /** 3182 * Set the PNO settings & the network list in HAL to start PNO. 3183 * @param settings PNO settings and network list. 3184 * @param eventHandler Handler to receive notifications back during PNO scan. 3185 * @return true if success, false otherwise 3186 */ 3187 public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) { 3188 Log.e(TAG, "setPnoList cmd " + sPnoCmdId); 3189 3190 synchronized (sLock) { 3191 if (isHalStarted()) { 3192 sPnoCmdId = getNewCmdIdLocked(); 3193 sPnoEventHandler = eventHandler; 3194 if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) { 3195 return true; 3196 } 3197 } 3198 sPnoEventHandler = null; 3199 return false; 3200 } 3201 } 3202 3203 /** 3204 * Set the PNO network list in HAL to start PNO. 3205 * @param list PNO network list. 3206 * @param eventHandler Handler to receive notifications back during PNO scan. 3207 * @return true if success, false otherwise 3208 */ 3209 public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) { 3210 PnoSettings settings = new PnoSettings(); 3211 settings.networkList = list; 3212 return setPnoList(settings, eventHandler); 3213 } 3214 3215 private static native boolean resetPnoListNative(int iface, int id); 3216 3217 /** 3218 * Reset the PNO settings in HAL to stop PNO. 3219 * @return true if success, false otherwise 3220 */ 3221 public boolean resetPnoList() { 3222 Log.e(TAG, "resetPnoList cmd " + sPnoCmdId); 3223 3224 synchronized (sLock) { 3225 if (isHalStarted()) { 3226 sPnoCmdId = getNewCmdIdLocked(); 3227 sPnoEventHandler = null; 3228 if (resetPnoListNative(sWlan0Index, sPnoCmdId)) { 3229 return true; 3230 } 3231 } 3232 return false; 3233 } 3234 } 3235 3236 // Callback from native 3237 private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) { 3238 if (results == null) { 3239 Log.e(TAG, "onPnoNetworkFound null results"); 3240 return; 3241 3242 } 3243 Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length); 3244 3245 PnoEventHandler handler = sPnoEventHandler; 3246 if (sPnoCmdId != 0 && handler != null) { 3247 for (int i=0; i<results.length; i++) { 3248 Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID 3249 + " " + results[i].level + " " + results[i].frequency); 3250 3251 populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound "); 3252 results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID); 3253 } 3254 3255 handler.onPnoNetworkFound(results); 3256 } else { 3257 /* this can happen because of race conditions */ 3258 Log.d(TAG, "Ignoring Pno Network found event"); 3259 } 3260 } 3261 3262 private native static int startSendingOffloadedPacketNative(int iface, int idx, 3263 byte[] srcMac, byte[] dstMac, byte[] pktData, int period); 3264 3265 public int 3266 startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) { 3267 Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period); 3268 3269 String[] macAddrStr = getMacAddress().split(":"); 3270 byte[] srcMac = new byte[6]; 3271 for(int i = 0; i < 6; i++) { 3272 Integer hexVal = Integer.parseInt(macAddrStr[i], 16); 3273 srcMac[i] = hexVal.byteValue(); 3274 } 3275 synchronized (sLock) { 3276 if (isHalStarted()) { 3277 return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac, 3278 keepAlivePacket.dstMac, keepAlivePacket.data, period); 3279 } else { 3280 return -1; 3281 } 3282 } 3283 } 3284 3285 private native static int stopSendingOffloadedPacketNative(int iface, int idx); 3286 3287 public int 3288 stopSendingOffloadedPacket(int slot) { 3289 Log.d(TAG, "stopSendingOffloadedPacket " + slot); 3290 synchronized (sLock) { 3291 if (isHalStarted()) { 3292 return stopSendingOffloadedPacketNative(sWlan0Index, slot); 3293 } else { 3294 return -1; 3295 } 3296 } 3297 } 3298 3299 public static interface WifiRssiEventHandler { 3300 void onRssiThresholdBreached(byte curRssi); 3301 } 3302 3303 private static WifiRssiEventHandler sWifiRssiEventHandler; 3304 3305 // Callback from native 3306 private static void onRssiThresholdBreached(int id, byte curRssi) { 3307 WifiRssiEventHandler handler = sWifiRssiEventHandler; 3308 if (handler != null) { 3309 handler.onRssiThresholdBreached(curRssi); 3310 } 3311 } 3312 3313 private native static int startRssiMonitoringNative(int iface, int id, 3314 byte maxRssi, byte minRssi); 3315 3316 private static int sRssiMonitorCmdId = 0; 3317 3318 public int startRssiMonitoring(byte maxRssi, byte minRssi, 3319 WifiRssiEventHandler rssiEventHandler) { 3320 Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi); 3321 synchronized (sLock) { 3322 sWifiRssiEventHandler = rssiEventHandler; 3323 if (isHalStarted()) { 3324 if (sRssiMonitorCmdId != 0) { 3325 stopRssiMonitoring(); 3326 } 3327 3328 sRssiMonitorCmdId = getNewCmdIdLocked(); 3329 Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); 3330 int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, 3331 maxRssi, minRssi); 3332 if (ret != 0) { // if not success 3333 sRssiMonitorCmdId = 0; 3334 } 3335 return ret; 3336 } else { 3337 return -1; 3338 } 3339 } 3340 } 3341 3342 private native static int stopRssiMonitoringNative(int iface, int idx); 3343 3344 public int stopRssiMonitoring() { 3345 Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId); 3346 synchronized (sLock) { 3347 if (isHalStarted()) { 3348 int ret = 0; 3349 if (sRssiMonitorCmdId != 0) { 3350 ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); 3351 } 3352 sRssiMonitorCmdId = 0; 3353 return ret; 3354 } else { 3355 return -1; 3356 } 3357 } 3358 } 3359 3360 private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface); 3361 3362 /** 3363 * Fetch the host wakeup reasons stats from wlan driver. 3364 * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver. 3365 */ 3366 public WifiWakeReasonAndCounts getWlanWakeReasonCount() { 3367 Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index); 3368 synchronized (sLock) { 3369 if (isHalStarted()) { 3370 return getWlanWakeReasonCountNative(sWlan0Index); 3371 } else { 3372 return null; 3373 } 3374 } 3375 } 3376 3377 private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled); 3378 3379 public boolean configureNeighborDiscoveryOffload(boolean enabled) { 3380 final String logMsg = "configureNeighborDiscoveryOffload(" + enabled + ")"; 3381 Log.d(mTAG, logMsg); 3382 synchronized (sLock) { 3383 if (isHalStarted()) { 3384 final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled); 3385 if (ret != 0) { 3386 Log.d(mTAG, logMsg + " returned: " + ret); 3387 } 3388 return (ret == 0); 3389 } 3390 } 3391 return false; 3392 } 3393 3394 // Firmware roaming control. 3395 3396 /** 3397 * Class to retrieve firmware roaming capability parameters. 3398 */ 3399 public static class RoamingCapabilities { 3400 public int maxBlacklistSize; 3401 public int maxWhitelistSize; 3402 } 3403 3404 /** 3405 * Query the firmware roaming capabilities. 3406 */ 3407 public boolean getRoamingCapabilities(RoamingCapabilities capabilities) { 3408 Log.d(TAG, "getRoamingCapabilities "); 3409 try { 3410 if (mWifiVendorHal != null) { 3411 return mWifiVendorHal.getRoamingCapabilities(capabilities); 3412 } 3413 } catch (UnsupportedOperationException e) { 3414 } 3415 3416 return false; 3417 } 3418 3419 /** 3420 * Macros for controlling firmware roaming. 3421 */ 3422 public static final int DISABLE_FIRMWARE_ROAMING = 0; 3423 public static final int ENABLE_FIRMWARE_ROAMING = 1; 3424 3425 /** 3426 * Enable/disable firmware roaming. 3427 */ 3428 public int enableFirmwareRoaming(int state) { 3429 Log.d(TAG, "enableFirmwareRoaming: state =" + state); 3430 try { 3431 if (mWifiVendorHal != null) { 3432 return mWifiVendorHal.enableFirmwareRoaming(state); 3433 } 3434 } catch (UnsupportedOperationException e) { 3435 } 3436 3437 return -1; 3438 } 3439 3440 /** 3441 * Class for specifying the roaming configurations. 3442 */ 3443 public static class RoamingConfig { 3444 public ArrayList<String> blacklistBssids; 3445 public ArrayList<String> whitelistSsids; 3446 } 3447 3448 /** 3449 * Set firmware roaming configurations. 3450 */ 3451 public boolean configureRoaming(RoamingConfig config) { 3452 Log.d(TAG, "configureRoaming "); 3453 try { 3454 if (mWifiVendorHal != null) { 3455 return mWifiVendorHal.configureRoaming(config); 3456 } 3457 } catch (UnsupportedOperationException e) { 3458 } 3459 3460 return false; 3461 } 3462 3463 /** 3464 * Reset firmware roaming configuration. 3465 */ 3466 public boolean resetRoamingConfiguration() { 3467 Log.d(TAG, "resetRoamingConfiguration "); 3468 try { 3469 if (mWifiVendorHal != null) { 3470 // Pass in an empty RoamingConfig object which translates to zero size 3471 // blacklist and whitelist to reset the firmware roaming configuration. 3472 RoamingConfig config = new RoamingConfig(); 3473 return mWifiVendorHal.configureRoaming(config); 3474 } 3475 } catch (UnsupportedOperationException e) { 3476 } 3477 3478 return false; 3479 } 3480 3481 3482 StackTraceElement[] mTrace; 3483 void legacyHalWarning() { 3484 Thread cur = Thread.currentThread(); 3485 mTrace = cur.getStackTrace(); 3486 StackTraceElement s = mTrace[3]; 3487 Log.e(TAG, "LEGACY HAL th " + cur.getId() 3488 + " line " + s.getLineNumber() + " " + s.getMethodName()); 3489 } 3490} 3491