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