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