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