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