WifiNative.java revision b86089a48fae8878b5a27533a116c97b0be6d0e7
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 710 InformationElementUtil.Capabilities capabilities = 711 new InformationElementUtil.Capabilities(); 712 capabilities.from(infoElements, beaconCapBits); 713 flags = capabilities.generateCapabilitiesString(); 714 ScanDetail scan = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 715 level, freq, tsf, infoElements, anqpLines); 716 results.add(scan); 717 } catch (IllegalArgumentException iae) { 718 Log.d(TAG, "Failed to parse information elements: " + iae); 719 } 720 } 721 bssid = null; 722 level = 0; 723 freq = 0; 724 tsf = 0; 725 cap = 0; 726 flags = ""; 727 wifiSsid = null; 728 infoElementsStr = null; 729 anqpLines = null; 730 } 731 } 732 } 733 return results; 734 } 735 736 /** 737 * Format of result: 738 * id=1016 739 * bssid=00:03:7f:40:84:10 740 * freq=2462 741 * beacon_int=200 742 * capabilities=0x0431 743 * qual=0 744 * noise=0 745 * level=-46 746 * tsf=0000002669008476 747 * age=5 748 * ie=00105143412d485332302d52322d54455354010882848b960c12182403010b0706555... 749 * flags=[WPA2-EAP-CCMP][ESS][P2P][HS20] 750 * ssid=QCA-HS20-R2-TEST 751 * p2p_device_name= 752 * p2p_config_methods=0x0SET_NE 753 * anqp_venue_name=02083d656e6757692d466920416c6c69616e63650a3239383920436f... 754 * anqp_network_auth_type=010000 755 * anqp_roaming_consortium=03506f9a05001bc504bd 756 * anqp_ip_addr_type_availability=0c 757 * anqp_nai_realm=0200300000246d61696c2e6578616d706c652e636f6d3b636973636f2... 758 * anqp_3gpp=000600040132f465 759 * anqp_domain_name=0b65786d61706c652e636f6d 760 * hs20_operator_friendly_name=11656e6757692d466920416c6c69616e63650e636869... 761 * hs20_wan_metrics=01c40900008001000000000a00 762 * hs20_connection_capability=0100000006140001061600000650000106bb010106bb0... 763 * hs20_osu_providers_list=0b5143412d4f53552d425353010901310015656e6757692d... 764 */ 765 public String scanResult(String bssid) { 766 return doStringCommand("BSS " + bssid); 767 } 768 769 /** 770 * Start filtering out Multicast V4 packets 771 * @return {@code true} if the operation succeeded, {@code false} otherwise 772 * 773 * Multicast filtering rules work as follows: 774 * 775 * The driver can filter multicast (v4 and/or v6) and broadcast packets when in 776 * a power optimized mode (typically when screen goes off). 777 * 778 * In order to prevent the driver from filtering the multicast/broadcast packets, we have to 779 * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective 780 * 781 * DRIVER RXFILTER-ADD Num 782 * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 783 * 784 * and DRIVER RXFILTER-START 785 * In order to stop the usage of these rules, we do 786 * 787 * DRIVER RXFILTER-STOP 788 * DRIVER RXFILTER-REMOVE Num 789 * where Num is as described for RXFILTER-ADD 790 * 791 * The SETSUSPENDOPT driver command overrides the filtering rules 792 */ 793 public boolean startFilteringMulticastV4Packets() { 794 return doBooleanCommand("DRIVER RXFILTER-STOP") 795 && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") 796 && doBooleanCommand("DRIVER RXFILTER-START"); 797 } 798 799 /** 800 * Stop filtering out Multicast V4 packets. 801 * @return {@code true} if the operation succeeded, {@code false} otherwise 802 */ 803 public boolean stopFilteringMulticastV4Packets() { 804 return doBooleanCommand("DRIVER RXFILTER-STOP") 805 && doBooleanCommand("DRIVER RXFILTER-ADD 2") 806 && doBooleanCommand("DRIVER RXFILTER-START"); 807 } 808 809 /** 810 * Start filtering out Multicast V6 packets 811 * @return {@code true} if the operation succeeded, {@code false} otherwise 812 */ 813 public boolean startFilteringMulticastV6Packets() { 814 return doBooleanCommand("DRIVER RXFILTER-STOP") 815 && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") 816 && doBooleanCommand("DRIVER RXFILTER-START"); 817 } 818 819 /** 820 * Stop filtering out Multicast V6 packets. 821 * @return {@code true} if the operation succeeded, {@code false} otherwise 822 */ 823 public boolean stopFilteringMulticastV6Packets() { 824 return doBooleanCommand("DRIVER RXFILTER-STOP") 825 && doBooleanCommand("DRIVER RXFILTER-ADD 3") 826 && doBooleanCommand("DRIVER RXFILTER-START"); 827 } 828 829 public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 830 public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 831 public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 832 /** 833 * Sets the bluetooth coexistence mode. 834 * 835 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 836 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 837 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 838 * @return Whether the mode was successfully set. 839 */ 840 public boolean setBluetoothCoexistenceMode(int mode) { 841 return doBooleanCommand("DRIVER BTCOEXMODE " + mode); 842 } 843 844 /** 845 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 846 * some of the low-level scan parameters used by the driver are changed to 847 * reduce interference with A2DP streaming. 848 * 849 * @param setCoexScanMode whether to enable or disable this mode 850 * @return {@code true} if the command succeeded, {@code false} otherwise. 851 */ 852 public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { 853 if (setCoexScanMode) { 854 return doBooleanCommand("DRIVER BTCOEXSCAN-START"); 855 } else { 856 return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); 857 } 858 } 859 860 public void enableSaveConfig() { 861 doBooleanCommand("SET update_config 1"); 862 } 863 864 public boolean saveConfig() { 865 return doBooleanCommand("SAVE_CONFIG"); 866 } 867 868 public boolean addToBlacklist(String bssid) { 869 if (TextUtils.isEmpty(bssid)) return false; 870 return doBooleanCommand("BLACKLIST " + bssid); 871 } 872 873 public boolean clearBlacklist() { 874 return doBooleanCommand("BLACKLIST clear"); 875 } 876 877 public boolean setSuspendOptimizations(boolean enabled) { 878 if (enabled) { 879 return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); 880 } else { 881 return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); 882 } 883 } 884 885 public boolean setCountryCode(String countryCode) { 886 if (countryCode != null) 887 return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT)); 888 else 889 return doBooleanCommand("DRIVER COUNTRY"); 890 } 891 892 /** 893 * Start/Stop PNO scan. 894 * @param enable boolean indicating whether PNO is being enabled or disabled. 895 */ 896 public boolean setPnoScan(boolean enable) { 897 String cmd = enable ? "SET pno 1" : "SET pno 0"; 898 return doBooleanCommand(cmd); 899 } 900 901 public void enableAutoConnect(boolean enable) { 902 if (enable) { 903 doBooleanCommand("STA_AUTOCONNECT 1"); 904 } else { 905 doBooleanCommand("STA_AUTOCONNECT 0"); 906 } 907 } 908 909 public void setScanInterval(int scanInterval) { 910 doBooleanCommand("SCAN_INTERVAL " + scanInterval); 911 } 912 913 public void setHs20(boolean hs20) { 914 if (hs20) { 915 doBooleanCommand("SET HS20 1"); 916 } else { 917 doBooleanCommand("SET HS20 0"); 918 } 919 } 920 921 public void startTdls(String macAddr, boolean enable) { 922 if (enable) { 923 synchronized (sLock) { 924 doBooleanCommand("TDLS_DISCOVER " + macAddr); 925 doBooleanCommand("TDLS_SETUP " + macAddr); 926 } 927 } else { 928 doBooleanCommand("TDLS_TEARDOWN " + macAddr); 929 } 930 } 931 932 public boolean startWpsPbc(String bssid) { 933 if (TextUtils.isEmpty(bssid)) { 934 return doBooleanCommand("WPS_PBC"); 935 } else { 936 return doBooleanCommand("WPS_PBC " + bssid); 937 } 938 } 939 940 public boolean startWpsPbc(String iface, String bssid) { 941 synchronized (sLock) { 942 if (TextUtils.isEmpty(bssid)) { 943 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); 944 } else { 945 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); 946 } 947 } 948 } 949 950 public boolean startWpsPinKeypad(String pin) { 951 if (TextUtils.isEmpty(pin)) return false; 952 return doBooleanCommand("WPS_PIN any " + pin); 953 } 954 955 public boolean startWpsPinKeypad(String iface, String pin) { 956 if (TextUtils.isEmpty(pin)) return false; 957 synchronized (sLock) { 958 return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); 959 } 960 } 961 962 963 public String startWpsPinDisplay(String bssid) { 964 if (TextUtils.isEmpty(bssid)) { 965 return doStringCommand("WPS_PIN any"); 966 } else { 967 return doStringCommand("WPS_PIN " + bssid); 968 } 969 } 970 971 public String startWpsPinDisplay(String iface, String bssid) { 972 synchronized (sLock) { 973 if (TextUtils.isEmpty(bssid)) { 974 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); 975 } else { 976 return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); 977 } 978 } 979 } 980 981 public boolean setExternalSim(boolean external) { 982 String value = external ? "1" : "0"; 983 Log.d(TAG, "Setting external_sim to " + value); 984 return doBooleanCommand("SET external_sim " + value); 985 } 986 987 public boolean simAuthResponse(int id, String type, String response) { 988 // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS 989 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response); 990 } 991 992 public boolean simAuthFailedResponse(int id) { 993 // should be used with type GSM-AUTH 994 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-FAIL"); 995 } 996 997 public boolean umtsAuthFailedResponse(int id) { 998 // should be used with type UMTS-AUTH 999 return doBooleanCommand("CTRL-RSP-SIM-" + id + ":UMTS-FAIL"); 1000 } 1001 1002 public boolean simIdentityResponse(int id, String response) { 1003 return doBooleanCommand("CTRL-RSP-IDENTITY-" + id + ":" + response); 1004 } 1005 1006 /* Configures an access point connection */ 1007 public boolean startWpsRegistrar(String bssid, String pin) { 1008 if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; 1009 return doBooleanCommand("WPS_REG " + bssid + " " + pin); 1010 } 1011 1012 public boolean cancelWps() { 1013 return doBooleanCommand("WPS_CANCEL"); 1014 } 1015 1016 public boolean setPersistentReconnect(boolean enabled) { 1017 int value = (enabled == true) ? 1 : 0; 1018 return doBooleanCommand("SET persistent_reconnect " + value); 1019 } 1020 1021 public boolean setDeviceName(String name) { 1022 return doBooleanCommand("SET device_name " + name); 1023 } 1024 1025 public boolean setDeviceType(String type) { 1026 return doBooleanCommand("SET device_type " + type); 1027 } 1028 1029 public boolean setConfigMethods(String cfg) { 1030 return doBooleanCommand("SET config_methods " + cfg); 1031 } 1032 1033 public boolean setManufacturer(String value) { 1034 return doBooleanCommand("SET manufacturer " + value); 1035 } 1036 1037 public boolean setModelName(String value) { 1038 return doBooleanCommand("SET model_name " + value); 1039 } 1040 1041 public boolean setModelNumber(String value) { 1042 return doBooleanCommand("SET model_number " + value); 1043 } 1044 1045 public boolean setSerialNumber(String value) { 1046 return doBooleanCommand("SET serial_number " + value); 1047 } 1048 1049 public boolean setP2pSsidPostfix(String postfix) { 1050 return doBooleanCommand("SET p2p_ssid_postfix " + postfix); 1051 } 1052 1053 public boolean setP2pGroupIdle(String iface, int time) { 1054 synchronized (sLock) { 1055 return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); 1056 } 1057 } 1058 1059 public void setPowerSave(boolean enabled) { 1060 if (enabled) { 1061 doBooleanCommand("SET ps 1"); 1062 } else { 1063 doBooleanCommand("SET ps 0"); 1064 } 1065 } 1066 1067 public boolean setP2pPowerSave(String iface, boolean enabled) { 1068 synchronized (sLock) { 1069 if (enabled) { 1070 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); 1071 } else { 1072 return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); 1073 } 1074 } 1075 } 1076 1077 public boolean setWfdEnable(boolean enable) { 1078 return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); 1079 } 1080 1081 public boolean setWfdDeviceInfo(String hex) { 1082 return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); 1083 } 1084 1085 /** 1086 * "sta" prioritizes STA connection over P2P and "p2p" prioritizes 1087 * P2P connection over STA 1088 */ 1089 public boolean setConcurrencyPriority(String s) { 1090 return doBooleanCommand("P2P_SET conc_pref " + s); 1091 } 1092 1093 public boolean p2pFind() { 1094 return doBooleanCommand("P2P_FIND"); 1095 } 1096 1097 public boolean p2pFind(int timeout) { 1098 if (timeout <= 0) { 1099 return p2pFind(); 1100 } 1101 return doBooleanCommand("P2P_FIND " + timeout); 1102 } 1103 1104 public boolean p2pStopFind() { 1105 return doBooleanCommand("P2P_STOP_FIND"); 1106 } 1107 1108 public boolean p2pListen() { 1109 return doBooleanCommand("P2P_LISTEN"); 1110 } 1111 1112 public boolean p2pListen(int timeout) { 1113 if (timeout <= 0) { 1114 return p2pListen(); 1115 } 1116 return doBooleanCommand("P2P_LISTEN " + timeout); 1117 } 1118 1119 public boolean p2pExtListen(boolean enable, int period, int interval) { 1120 if (enable && interval < period) { 1121 return false; 1122 } 1123 return doBooleanCommand("P2P_EXT_LISTEN" 1124 + (enable ? (" " + period + " " + interval) : "")); 1125 } 1126 1127 public boolean p2pSetChannel(int lc, int oc) { 1128 if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc); 1129 1130 synchronized (sLock) { 1131 if (lc >=1 && lc <= 11) { 1132 if (!doBooleanCommand("P2P_SET listen_channel " + lc)) { 1133 return false; 1134 } 1135 } else if (lc != 0) { 1136 return false; 1137 } 1138 1139 if (oc >= 1 && oc <= 165 ) { 1140 int freq = (oc <= 14 ? 2407 : 5000) + oc * 5; 1141 return doBooleanCommand("P2P_SET disallow_freq 1000-" 1142 + (freq - 5) + "," + (freq + 5) + "-6000"); 1143 } else if (oc == 0) { 1144 /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */ 1145 return doBooleanCommand("P2P_SET disallow_freq \"\""); 1146 } 1147 } 1148 return false; 1149 } 1150 1151 public boolean p2pFlush() { 1152 return doBooleanCommand("P2P_FLUSH"); 1153 } 1154 1155 private static final int DEFAULT_GROUP_OWNER_INTENT = 6; 1156 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 1157 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 1158 public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 1159 if (config == null) return null; 1160 List<String> args = new ArrayList<>(); 1161 WpsInfo wps = config.wps; 1162 args.add(config.deviceAddress); 1163 1164 switch (wps.setup) { 1165 case WpsInfo.PBC: 1166 args.add("pbc"); 1167 break; 1168 case WpsInfo.DISPLAY: 1169 if (TextUtils.isEmpty(wps.pin)) { 1170 args.add("pin"); 1171 } else { 1172 args.add(wps.pin); 1173 } 1174 args.add("display"); 1175 break; 1176 case WpsInfo.KEYPAD: 1177 args.add(wps.pin); 1178 args.add("keypad"); 1179 break; 1180 case WpsInfo.LABEL: 1181 args.add(wps.pin); 1182 args.add("label"); 1183 default: 1184 break; 1185 } 1186 1187 if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { 1188 args.add("persistent"); 1189 } 1190 1191 if (joinExistingGroup) { 1192 args.add("join"); 1193 } else { 1194 //TODO: This can be adapted based on device plugged in state and 1195 //device battery state 1196 int groupOwnerIntent = config.groupOwnerIntent; 1197 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 1198 groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; 1199 } 1200 args.add("go_intent=" + groupOwnerIntent); 1201 } 1202 1203 String command = "P2P_CONNECT "; 1204 for (String s : args) command += s + " "; 1205 1206 return doStringCommand(command); 1207 } 1208 1209 public boolean p2pCancelConnect() { 1210 return doBooleanCommand("P2P_CANCEL"); 1211 } 1212 1213 public boolean p2pProvisionDiscovery(WifiP2pConfig config) { 1214 if (config == null) return false; 1215 1216 switch (config.wps.setup) { 1217 case WpsInfo.PBC: 1218 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 1219 case WpsInfo.DISPLAY: 1220 //We are doing display, so provision discovery is keypad 1221 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 1222 case WpsInfo.KEYPAD: 1223 //We are doing keypad, so provision discovery is display 1224 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 1225 default: 1226 break; 1227 } 1228 return false; 1229 } 1230 1231 public boolean p2pGroupAdd(boolean persistent) { 1232 if (persistent) { 1233 return doBooleanCommand("P2P_GROUP_ADD persistent"); 1234 } 1235 return doBooleanCommand("P2P_GROUP_ADD"); 1236 } 1237 1238 public boolean p2pGroupAdd(int netId) { 1239 return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); 1240 } 1241 1242 public boolean p2pGroupRemove(String iface) { 1243 if (TextUtils.isEmpty(iface)) return false; 1244 synchronized (sLock) { 1245 return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); 1246 } 1247 } 1248 1249 public boolean p2pReject(String deviceAddress) { 1250 return doBooleanCommand("P2P_REJECT " + deviceAddress); 1251 } 1252 1253 /* Invite a peer to a group */ 1254 public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 1255 if (TextUtils.isEmpty(deviceAddress)) return false; 1256 1257 if (group == null) { 1258 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 1259 } else { 1260 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 1261 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 1262 } 1263 } 1264 1265 /* Reinvoke a persistent connection */ 1266 public boolean p2pReinvoke(int netId, String deviceAddress) { 1267 if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; 1268 1269 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 1270 } 1271 1272 public String p2pGetSsid(String deviceAddress) { 1273 return p2pGetParam(deviceAddress, "oper_ssid"); 1274 } 1275 1276 public String p2pGetDeviceAddress() { 1277 Log.d(TAG, "p2pGetDeviceAddress"); 1278 1279 String status = null; 1280 1281 /* Explicitly calling the API without IFNAME= prefix to take care of the devices that 1282 don't have p2p0 interface. Supplicant seems to be returning the correct address anyway. */ 1283 1284 synchronized (sLock) { 1285 status = doStringCommandNative("STATUS"); 1286 } 1287 1288 String result = ""; 1289 if (status != null) { 1290 String[] tokens = status.split("\n"); 1291 for (String token : tokens) { 1292 if (token.startsWith("p2p_device_address=")) { 1293 String[] nameValue = token.split("="); 1294 if (nameValue.length != 2) 1295 break; 1296 result = nameValue[1]; 1297 } 1298 } 1299 } 1300 1301 Log.d(TAG, "p2pGetDeviceAddress returning " + result); 1302 return result; 1303 } 1304 1305 public int getGroupCapability(String deviceAddress) { 1306 int gc = 0; 1307 if (TextUtils.isEmpty(deviceAddress)) return gc; 1308 String peerInfo = p2pPeer(deviceAddress); 1309 if (TextUtils.isEmpty(peerInfo)) return gc; 1310 1311 String[] tokens = peerInfo.split("\n"); 1312 for (String token : tokens) { 1313 if (token.startsWith("group_capab=")) { 1314 String[] nameValue = token.split("="); 1315 if (nameValue.length != 2) break; 1316 try { 1317 return Integer.decode(nameValue[1]); 1318 } catch(NumberFormatException e) { 1319 return gc; 1320 } 1321 } 1322 } 1323 return gc; 1324 } 1325 1326 public String p2pPeer(String deviceAddress) { 1327 return doStringCommand("P2P_PEER " + deviceAddress); 1328 } 1329 1330 private String p2pGetParam(String deviceAddress, String key) { 1331 if (deviceAddress == null) return null; 1332 1333 String peerInfo = p2pPeer(deviceAddress); 1334 if (peerInfo == null) return null; 1335 String[] tokens= peerInfo.split("\n"); 1336 1337 key += "="; 1338 for (String token : tokens) { 1339 if (token.startsWith(key)) { 1340 String[] nameValue = token.split("="); 1341 if (nameValue.length != 2) break; 1342 return nameValue[1]; 1343 } 1344 } 1345 return null; 1346 } 1347 1348 public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { 1349 /* 1350 * P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump> 1351 * P2P_SERVICE_ADD upnp <version hex> <service> 1352 * 1353 * e.g) 1354 * [Bonjour] 1355 * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) 1356 * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 1357 * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) 1358 * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 1359 * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 1360 * 1361 * [UPnP] 1362 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 1363 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice 1364 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp 1365 * -org:device:InternetGatewayDevice:1 1366 * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp 1367 * -org:service:ContentDirectory:2 1368 */ 1369 synchronized (sLock) { 1370 for (String s : servInfo.getSupplicantQueryList()) { 1371 String command = "P2P_SERVICE_ADD"; 1372 command += (" " + s); 1373 if (!doBooleanCommand(command)) { 1374 return false; 1375 } 1376 } 1377 } 1378 return true; 1379 } 1380 1381 public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { 1382 /* 1383 * P2P_SERVICE_DEL bonjour <query hexdump> 1384 * P2P_SERVICE_DEL upnp <version hex> <service> 1385 */ 1386 synchronized (sLock) { 1387 for (String s : servInfo.getSupplicantQueryList()) { 1388 String command = "P2P_SERVICE_DEL "; 1389 1390 String[] data = s.split(" "); 1391 if (data.length < 2) { 1392 return false; 1393 } 1394 if ("upnp".equals(data[0])) { 1395 command += s; 1396 } else if ("bonjour".equals(data[0])) { 1397 command += data[0]; 1398 command += (" " + data[1]); 1399 } else { 1400 return false; 1401 } 1402 if (!doBooleanCommand(command)) { 1403 return false; 1404 } 1405 } 1406 } 1407 return true; 1408 } 1409 1410 public boolean p2pServiceFlush() { 1411 return doBooleanCommand("P2P_SERVICE_FLUSH"); 1412 } 1413 1414 public String p2pServDiscReq(String addr, String query) { 1415 String command = "P2P_SERV_DISC_REQ"; 1416 command += (" " + addr); 1417 command += (" " + query); 1418 1419 return doStringCommand(command); 1420 } 1421 1422 public boolean p2pServDiscCancelReq(String id) { 1423 return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); 1424 } 1425 1426 /* Set the current mode of miracast operation. 1427 * 0 = disabled 1428 * 1 = operating as source 1429 * 2 = operating as sink 1430 */ 1431 public void setMiracastMode(int mode) { 1432 // Note: optional feature on the driver. It is ok for this to fail. 1433 doBooleanCommand("DRIVER MIRACAST " + mode); 1434 } 1435 1436 /* 1437 * NFC-related calls 1438 */ 1439 public String getNfcWpsConfigurationToken(int netId) { 1440 return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId); 1441 } 1442 1443 public String getNfcHandoverRequest() { 1444 return doStringCommand("NFC_GET_HANDOVER_REQ NDEF P2P-CR"); 1445 } 1446 1447 public String getNfcHandoverSelect() { 1448 return doStringCommand("NFC_GET_HANDOVER_SEL NDEF P2P-CR"); 1449 } 1450 1451 public boolean initiatorReportNfcHandover(String selectMessage) { 1452 return doBooleanCommand("NFC_REPORT_HANDOVER INIT P2P 00 " + selectMessage); 1453 } 1454 1455 public boolean responderReportNfcHandover(String requestMessage) { 1456 return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00"); 1457 } 1458 1459 1460 /* kernel logging support */ 1461 private static native byte[] readKernelLogNative(); 1462 1463 synchronized public String readKernelLog() { 1464 byte[] bytes = readKernelLogNative(); 1465 if (bytes != null) { 1466 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 1467 try { 1468 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); 1469 return decoded.toString(); 1470 } catch (CharacterCodingException cce) { 1471 return new String(bytes, StandardCharsets.ISO_8859_1); 1472 } 1473 } else { 1474 return "*** failed to read kernel log ***"; 1475 } 1476 } 1477 1478 /* WIFI HAL support */ 1479 1480 // HAL command ids 1481 private static int sCmdId = 1; 1482 private static int getNewCmdIdLocked() { 1483 return sCmdId++; 1484 } 1485 1486 private static final String TAG = "WifiNative-HAL"; 1487 private static long sWifiHalHandle = 0; /* used by JNI to save wifi_handle */ 1488 private static long[] sWifiIfaceHandles = null; /* used by JNI to save interface handles */ 1489 public static int sWlan0Index = -1; 1490 private static MonitorThread sThread; 1491 private static final int STOP_HAL_TIMEOUT_MS = 1000; 1492 1493 private static native boolean startHalNative(); 1494 private static native void stopHalNative(); 1495 private static native void waitForHalEventNative(); 1496 1497 private static class MonitorThread extends Thread { 1498 @Override 1499 public void run() { 1500 Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle)); 1501 waitForHalEventNative(); 1502 } 1503 } 1504 1505 public boolean startHal() { 1506 String debugLog = "startHal stack: "; 1507 java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 1508 for (int i = 2; i < elements.length && i <= 7; i++ ) { 1509 debugLog = debugLog + " - " + elements[i].getMethodName(); 1510 } 1511 1512 sLocalLog.log(debugLog); 1513 1514 synchronized (sLock) { 1515 if (startHalNative()) { 1516 int wlan0Index = queryInterfaceIndex(mInterfaceName); 1517 if (wlan0Index == -1) { 1518 if (DBG) sLocalLog.log("Could not find interface with name: " + mInterfaceName); 1519 return false; 1520 } 1521 sWlan0Index = wlan0Index; 1522 sThread = new MonitorThread(); 1523 sThread.start(); 1524 return true; 1525 } else { 1526 if (DBG) sLocalLog.log("Could not start hal"); 1527 Log.e(TAG, "Could not start hal"); 1528 return false; 1529 } 1530 } 1531 } 1532 1533 public void stopHal() { 1534 synchronized (sLock) { 1535 if (isHalStarted()) { 1536 stopHalNative(); 1537 try { 1538 sThread.join(STOP_HAL_TIMEOUT_MS); 1539 Log.d(TAG, "HAL event thread stopped successfully"); 1540 } catch (InterruptedException e) { 1541 Log.e(TAG, "Could not stop HAL cleanly"); 1542 } 1543 sThread = null; 1544 sWifiHalHandle = 0; 1545 sWifiIfaceHandles = null; 1546 sWlan0Index = -1; 1547 } 1548 } 1549 } 1550 1551 public boolean isHalStarted() { 1552 return (sWifiHalHandle != 0); 1553 } 1554 private static native int getInterfacesNative(); 1555 1556 public int queryInterfaceIndex(String interfaceName) { 1557 synchronized (sLock) { 1558 if (isHalStarted()) { 1559 int num = getInterfacesNative(); 1560 for (int i = 0; i < num; i++) { 1561 String name = getInterfaceNameNative(i); 1562 if (name.equals(interfaceName)) { 1563 return i; 1564 } 1565 } 1566 } 1567 } 1568 return -1; 1569 } 1570 1571 private static native String getInterfaceNameNative(int index); 1572 public String getInterfaceName(int index) { 1573 synchronized (sLock) { 1574 return getInterfaceNameNative(index); 1575 } 1576 } 1577 1578 // TODO: Change variable names to camel style. 1579 public static class ScanCapabilities { 1580 public int max_scan_cache_size; 1581 public int max_scan_buckets; 1582 public int max_ap_cache_per_scan; 1583 public int max_rssi_sample_size; 1584 public int max_scan_reporting_threshold; 1585 public int max_hotlist_bssids; 1586 public int max_significant_wifi_change_aps; 1587 public int max_bssid_history_entries; 1588 public int max_number_epno_networks; 1589 public int max_number_epno_networks_by_ssid; 1590 public int max_number_of_white_listed_ssid; 1591 } 1592 1593 public boolean getScanCapabilities(ScanCapabilities capabilities) { 1594 synchronized (sLock) { 1595 return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities); 1596 } 1597 } 1598 1599 private static native boolean getScanCapabilitiesNative( 1600 int iface, ScanCapabilities capabilities); 1601 1602 private static native boolean startScanNative(int iface, int id, ScanSettings settings); 1603 private static native boolean stopScanNative(int iface, int id); 1604 private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush); 1605 private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface); 1606 private static native void setWifiLinkLayerStatsNative(int iface, int enable); 1607 1608 public static class ChannelSettings { 1609 public int frequency; 1610 public int dwell_time_ms; 1611 public boolean passive; 1612 } 1613 1614 public static class BucketSettings { 1615 public int bucket; 1616 public int band; 1617 public int period_ms; 1618 public int max_period_ms; 1619 public int step_count; 1620 public int report_events; 1621 public int num_channels; 1622 public ChannelSettings[] channels; 1623 } 1624 1625 /** 1626 * Network parameters for hidden networks to be scanned for. 1627 */ 1628 public static class HiddenNetwork { 1629 public String ssid; 1630 1631 @Override 1632 public boolean equals(Object otherObj) { 1633 if (this == otherObj) { 1634 return true; 1635 } else if (otherObj == null || getClass() != otherObj.getClass()) { 1636 return false; 1637 } 1638 HiddenNetwork other = (HiddenNetwork) otherObj; 1639 return Objects.equals(ssid, other.ssid); 1640 } 1641 } 1642 1643 public static class ScanSettings { 1644 public int base_period_ms; 1645 public int max_ap_per_scan; 1646 public int report_threshold_percent; 1647 public int report_threshold_num_scans; 1648 public int num_buckets; 1649 /* Not used for bg scans. Only works for single scans. */ 1650 public HiddenNetwork[] hiddenNetworks; 1651 public BucketSettings[] buckets; 1652 } 1653 1654 /** 1655 * Network parameters to start PNO scan. 1656 */ 1657 public static class PnoNetwork { 1658 public String ssid; 1659 public byte flags; 1660 public byte auth_bit_field; 1661 1662 @Override 1663 public boolean equals(Object otherObj) { 1664 if (this == otherObj) { 1665 return true; 1666 } else if (otherObj == null || getClass() != otherObj.getClass()) { 1667 return false; 1668 } 1669 PnoNetwork other = (PnoNetwork) otherObj; 1670 return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags) 1671 && (auth_bit_field == other.auth_bit_field)); 1672 } 1673 } 1674 1675 /** 1676 * Parameters to start PNO scan. This holds the list of networks which are going to used for 1677 * PNO scan. 1678 */ 1679 public static class PnoSettings { 1680 public int min5GHzRssi; 1681 public int min24GHzRssi; 1682 public int initialScoreMax; 1683 public int currentConnectionBonus; 1684 public int sameNetworkBonus; 1685 public int secureBonus; 1686 public int band5GHzBonus; 1687 public boolean isConnected; 1688 public PnoNetwork[] networkList; 1689 } 1690 1691 /** 1692 * Wi-Fi channel information. 1693 */ 1694 public static class WifiChannelInfo { 1695 int mPrimaryFrequency; 1696 int mCenterFrequency0; 1697 int mCenterFrequency1; 1698 int mChannelWidth; 1699 // TODO: add preamble once available in HAL. 1700 } 1701 1702 public static interface ScanEventHandler { 1703 /** 1704 * Called for each AP as it is found with the entire contents of the beacon/probe response. 1705 * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified. 1706 */ 1707 void onFullScanResult(ScanResult fullScanResult, int bucketsScanned); 1708 /** 1709 * Callback on an event during a gscan scan. 1710 * See WifiNative.WIFI_SCAN_* for possible values. 1711 */ 1712 void onScanStatus(int event); 1713 /** 1714 * Called with the current cached scan results when gscan is paused. 1715 */ 1716 void onScanPaused(WifiScanner.ScanData[] data); 1717 /** 1718 * Called with the current cached scan results when gscan is resumed. 1719 */ 1720 void onScanRestarted(); 1721 } 1722 1723 /** 1724 * Handler to notify the occurrence of various events during PNO scan. 1725 */ 1726 public interface PnoEventHandler { 1727 /** 1728 * Callback to notify when one of the shortlisted networks is found during PNO scan. 1729 * @param results List of Scan results received. 1730 */ 1731 void onPnoNetworkFound(ScanResult[] results); 1732 1733 /** 1734 * Callback to notify when the PNO scan schedule fails. 1735 */ 1736 void onPnoScanFailed(); 1737 } 1738 1739 /* scan status, keep these values in sync with gscan.h */ 1740 public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0; 1741 public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1; 1742 public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2; 1743 public static final int WIFI_SCAN_FAILED = 3; 1744 1745 // Callback from native 1746 private static void onScanStatus(int id, int event) { 1747 ScanEventHandler handler = sScanEventHandler; 1748 if (handler != null) { 1749 handler.onScanStatus(event); 1750 } 1751 } 1752 1753 public static WifiSsid createWifiSsid(byte[] rawSsid) { 1754 String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid)); 1755 1756 if (ssidHexString == null) { 1757 return null; 1758 } 1759 1760 WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString); 1761 1762 return wifiSsid; 1763 } 1764 1765 public static String ssidConvert(byte[] rawSsid) { 1766 String ssid; 1767 1768 CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 1769 try { 1770 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid)); 1771 ssid = decoded.toString(); 1772 } catch (CharacterCodingException cce) { 1773 ssid = null; 1774 } 1775 1776 if (ssid == null) { 1777 ssid = new String(rawSsid, StandardCharsets.ISO_8859_1); 1778 } 1779 1780 return ssid; 1781 } 1782 1783 // Called from native 1784 public static boolean setSsid(byte[] rawSsid, ScanResult result) { 1785 if (rawSsid == null || rawSsid.length == 0 || result == null) { 1786 return false; 1787 } 1788 1789 result.SSID = ssidConvert(rawSsid); 1790 result.wifiSsid = createWifiSsid(rawSsid); 1791 return true; 1792 } 1793 1794 private static void populateScanResult(ScanResult result, int beaconCap, String dbg) { 1795 if (dbg == null) dbg = ""; 1796 1797 InformationElementUtil.HtOperation htOperation = new InformationElementUtil.HtOperation(); 1798 InformationElementUtil.VhtOperation vhtOperation = 1799 new InformationElementUtil.VhtOperation(); 1800 InformationElementUtil.ExtendedCapabilities extendedCaps = 1801 new InformationElementUtil.ExtendedCapabilities(); 1802 1803 ScanResult.InformationElement elements[] = 1804 InformationElementUtil.parseInformationElements(result.bytes); 1805 for (ScanResult.InformationElement ie : elements) { 1806 if(ie.id == ScanResult.InformationElement.EID_HT_OPERATION) { 1807 htOperation.from(ie); 1808 } else if(ie.id == ScanResult.InformationElement.EID_VHT_OPERATION) { 1809 vhtOperation.from(ie); 1810 } else if (ie.id == ScanResult.InformationElement.EID_EXTENDED_CAPS) { 1811 extendedCaps.from(ie); 1812 } 1813 } 1814 1815 if (extendedCaps.is80211McRTTResponder()) { 1816 result.setFlag(ScanResult.FLAG_80211mc_RESPONDER); 1817 } else { 1818 result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER); 1819 } 1820 1821 //handle RTT related information 1822 if (vhtOperation.isValid()) { 1823 result.channelWidth = vhtOperation.getChannelWidth(); 1824 result.centerFreq0 = vhtOperation.getCenterFreq0(); 1825 result.centerFreq1 = vhtOperation.getCenterFreq1(); 1826 } else { 1827 result.channelWidth = htOperation.getChannelWidth(); 1828 result.centerFreq0 = htOperation.getCenterFreq0(result.frequency); 1829 result.centerFreq1 = 0; 1830 } 1831 1832 // build capabilities string 1833 BitSet beaconCapBits = new BitSet(16); 1834 for (int i = 0; i < 16; i++) { 1835 if ((beaconCap & (1 << i)) != 0) { 1836 beaconCapBits.set(i); 1837 } 1838 } 1839 InformationElementUtil.Capabilities capabilities = 1840 new InformationElementUtil.Capabilities(); 1841 capabilities.from(elements, beaconCapBits); 1842 result.capabilities = capabilities.generateCapabilitiesString(); 1843 1844 if(DBG) { 1845 Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth 1846 + " PrimaryFreq: " + result.frequency + " mCenterfreq0: " + result.centerFreq0 1847 + " mCenterfreq1: " + result.centerFreq1 1848 + (extendedCaps.is80211McRTTResponder() ? "Support RTT reponder: " 1849 : "Do not support RTT responder") 1850 + " Capabilities: " + result.capabilities); 1851 } 1852 1853 result.informationElements = elements; 1854 } 1855 1856 // Callback from native 1857 private static void onFullScanResult(int id, ScanResult result, 1858 int bucketsScanned, int beaconCap) { 1859 if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID); 1860 1861 ScanEventHandler handler = sScanEventHandler; 1862 if (handler != null) { 1863 populateScanResult(result, beaconCap, " onFullScanResult "); 1864 handler.onFullScanResult(result, bucketsScanned); 1865 } 1866 } 1867 1868 private static int sScanCmdId = 0; 1869 private static ScanEventHandler sScanEventHandler; 1870 private static ScanSettings sScanSettings; 1871 1872 public boolean startScan(ScanSettings settings, ScanEventHandler eventHandler) { 1873 synchronized (sLock) { 1874 if (isHalStarted()) { 1875 if (sScanCmdId != 0) { 1876 stopScan(); 1877 } else if (sScanSettings != null || sScanEventHandler != null) { 1878 /* current scan is paused; no need to stop it */ 1879 } 1880 1881 sScanCmdId = getNewCmdIdLocked(); 1882 1883 sScanSettings = settings; 1884 sScanEventHandler = eventHandler; 1885 1886 if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) { 1887 sScanEventHandler = null; 1888 sScanSettings = null; 1889 sScanCmdId = 0; 1890 return false; 1891 } 1892 1893 return true; 1894 } else { 1895 return false; 1896 } 1897 } 1898 } 1899 1900 public void stopScan() { 1901 synchronized (sLock) { 1902 if (isHalStarted()) { 1903 if (sScanCmdId != 0) { 1904 stopScanNative(sWlan0Index, sScanCmdId); 1905 } 1906 sScanSettings = null; 1907 sScanEventHandler = null; 1908 sScanCmdId = 0; 1909 } 1910 } 1911 } 1912 1913 public void pauseScan() { 1914 synchronized (sLock) { 1915 if (isHalStarted()) { 1916 if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) { 1917 Log.d(TAG, "Pausing scan"); 1918 WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true); 1919 stopScanNative(sWlan0Index, sScanCmdId); 1920 sScanCmdId = 0; 1921 sScanEventHandler.onScanPaused(scanData); 1922 } 1923 } 1924 } 1925 } 1926 1927 public void restartScan() { 1928 synchronized (sLock) { 1929 if (isHalStarted()) { 1930 if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) { 1931 Log.d(TAG, "Restarting scan"); 1932 ScanEventHandler handler = sScanEventHandler; 1933 ScanSettings settings = sScanSettings; 1934 if (startScan(sScanSettings, sScanEventHandler)) { 1935 sScanEventHandler.onScanRestarted(); 1936 } else { 1937 /* we are still paused; don't change state */ 1938 sScanEventHandler = handler; 1939 sScanSettings = settings; 1940 } 1941 } 1942 } 1943 } 1944 } 1945 1946 public WifiScanner.ScanData[] getScanResults(boolean flush) { 1947 synchronized (sLock) { 1948 WifiScanner.ScanData[] sd = null; 1949 if (isHalStarted()) { 1950 sd = getScanResultsNative(sWlan0Index, flush); 1951 } 1952 1953 if (sd != null) { 1954 return sd; 1955 } else { 1956 return new WifiScanner.ScanData[0]; 1957 } 1958 } 1959 } 1960 1961 public static interface HotlistEventHandler { 1962 void onHotlistApFound (ScanResult[] result); 1963 void onHotlistApLost (ScanResult[] result); 1964 } 1965 1966 private static int sHotlistCmdId = 0; 1967 private static HotlistEventHandler sHotlistEventHandler; 1968 1969 private native static boolean setHotlistNative(int iface, int id, 1970 WifiScanner.HotlistSettings settings); 1971 private native static boolean resetHotlistNative(int iface, int id); 1972 1973 public boolean setHotlist(WifiScanner.HotlistSettings settings, 1974 HotlistEventHandler eventHandler) { 1975 synchronized (sLock) { 1976 if (isHalStarted()) { 1977 if (sHotlistCmdId != 0) { 1978 return false; 1979 } else { 1980 sHotlistCmdId = getNewCmdIdLocked(); 1981 } 1982 1983 sHotlistEventHandler = eventHandler; 1984 if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) { 1985 sHotlistEventHandler = null; 1986 return false; 1987 } 1988 1989 return true; 1990 } else { 1991 return false; 1992 } 1993 } 1994 } 1995 1996 public void resetHotlist() { 1997 synchronized (sLock) { 1998 if (isHalStarted()) { 1999 if (sHotlistCmdId != 0) { 2000 resetHotlistNative(sWlan0Index, sHotlistCmdId); 2001 sHotlistCmdId = 0; 2002 sHotlistEventHandler = null; 2003 } 2004 } 2005 } 2006 } 2007 2008 // Callback from native 2009 private static void onHotlistApFound(int id, ScanResult[] results) { 2010 HotlistEventHandler handler = sHotlistEventHandler; 2011 if (handler != null) { 2012 handler.onHotlistApFound(results); 2013 } else { 2014 /* this can happen because of race conditions */ 2015 Log.d(TAG, "Ignoring hotlist AP found event"); 2016 } 2017 } 2018 2019 // Callback from native 2020 private static void onHotlistApLost(int id, ScanResult[] results) { 2021 HotlistEventHandler handler = sHotlistEventHandler; 2022 if (handler != null) { 2023 handler.onHotlistApLost(results); 2024 } else { 2025 /* this can happen because of race conditions */ 2026 Log.d(TAG, "Ignoring hotlist AP lost event"); 2027 } 2028 } 2029 2030 public static interface SignificantWifiChangeEventHandler { 2031 void onChangesFound(ScanResult[] result); 2032 } 2033 2034 private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler; 2035 private static int sSignificantWifiChangeCmdId; 2036 2037 private static native boolean trackSignificantWifiChangeNative( 2038 int iface, int id, WifiScanner.WifiChangeSettings settings); 2039 private static native boolean untrackSignificantWifiChangeNative(int iface, int id); 2040 2041 public boolean trackSignificantWifiChange( 2042 WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) { 2043 synchronized (sLock) { 2044 if (isHalStarted()) { 2045 if (sSignificantWifiChangeCmdId != 0) { 2046 return false; 2047 } else { 2048 sSignificantWifiChangeCmdId = getNewCmdIdLocked(); 2049 } 2050 2051 sSignificantWifiChangeHandler = handler; 2052 if (trackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId, 2053 settings) == false) { 2054 sSignificantWifiChangeHandler = null; 2055 return false; 2056 } 2057 2058 return true; 2059 } else { 2060 return false; 2061 } 2062 2063 } 2064 } 2065 2066 public void untrackSignificantWifiChange() { 2067 synchronized (sLock) { 2068 if (isHalStarted()) { 2069 if (sSignificantWifiChangeCmdId != 0) { 2070 untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId); 2071 sSignificantWifiChangeCmdId = 0; 2072 sSignificantWifiChangeHandler = null; 2073 } 2074 } 2075 } 2076 } 2077 2078 // Callback from native 2079 private static void onSignificantWifiChange(int id, ScanResult[] results) { 2080 SignificantWifiChangeEventHandler handler = sSignificantWifiChangeHandler; 2081 if (handler != null) { 2082 handler.onChangesFound(results); 2083 } else { 2084 /* this can happen because of race conditions */ 2085 Log.d(TAG, "Ignoring significant wifi change"); 2086 } 2087 } 2088 2089 public WifiLinkLayerStats getWifiLinkLayerStats(String iface) { 2090 // TODO: use correct iface name to Index translation 2091 if (iface == null) return null; 2092 synchronized (sLock) { 2093 if (isHalStarted()) { 2094 return getWifiLinkLayerStatsNative(sWlan0Index); 2095 } else { 2096 return null; 2097 } 2098 } 2099 } 2100 2101 public void setWifiLinkLayerStats(String iface, int enable) { 2102 if (iface == null) return; 2103 synchronized (sLock) { 2104 if (isHalStarted()) { 2105 setWifiLinkLayerStatsNative(sWlan0Index, enable); 2106 } 2107 } 2108 } 2109 2110 public static native int getSupportedFeatureSetNative(int iface); 2111 public int getSupportedFeatureSet() { 2112 synchronized (sLock) { 2113 if (isHalStarted()) { 2114 return getSupportedFeatureSetNative(sWlan0Index); 2115 } else { 2116 Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started"); 2117 return 0; 2118 } 2119 } 2120 } 2121 2122 /* Rtt related commands/events */ 2123 public static interface RttEventHandler { 2124 void onRttResults(RttManager.RttResult[] result); 2125 } 2126 2127 private static RttEventHandler sRttEventHandler; 2128 private static int sRttCmdId; 2129 2130 // Callback from native 2131 private static void onRttResults(int id, RttManager.RttResult[] results) { 2132 RttEventHandler handler = sRttEventHandler; 2133 if (handler != null && id == sRttCmdId) { 2134 Log.d(TAG, "Received " + results.length + " rtt results"); 2135 handler.onRttResults(results); 2136 sRttCmdId = 0; 2137 } else { 2138 Log.d(TAG, "RTT Received event for unknown cmd = " + id + 2139 ", current id = " + sRttCmdId); 2140 } 2141 } 2142 2143 private static native boolean requestRangeNative( 2144 int iface, int id, RttManager.RttParams[] params); 2145 private static native boolean cancelRangeRequestNative( 2146 int iface, int id, RttManager.RttParams[] params); 2147 2148 public boolean requestRtt( 2149 RttManager.RttParams[] params, RttEventHandler handler) { 2150 synchronized (sLock) { 2151 if (isHalStarted()) { 2152 if (sRttCmdId != 0) { 2153 Log.w(TAG, "Last one is still under measurement!"); 2154 return false; 2155 } else { 2156 sRttCmdId = getNewCmdIdLocked(); 2157 } 2158 sRttEventHandler = handler; 2159 return requestRangeNative(sWlan0Index, sRttCmdId, params); 2160 } else { 2161 return false; 2162 } 2163 } 2164 } 2165 2166 public boolean cancelRtt(RttManager.RttParams[] params) { 2167 synchronized (sLock) { 2168 if (isHalStarted()) { 2169 if (sRttCmdId == 0) { 2170 return false; 2171 } 2172 2173 sRttCmdId = 0; 2174 2175 if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) { 2176 sRttEventHandler = null; 2177 return true; 2178 } else { 2179 Log.e(TAG, "RTT cancel Request failed"); 2180 return false; 2181 } 2182 } else { 2183 return false; 2184 } 2185 } 2186 } 2187 2188 private static int sRttResponderCmdId = 0; 2189 2190 private static native ResponderConfig enableRttResponderNative(int iface, int commandId, 2191 int timeoutSeconds, WifiChannelInfo channelHint); 2192 /** 2193 * Enable RTT responder role on the device. Returns {@link ResponderConfig} if the responder 2194 * role is successfully enabled, {@code null} otherwise. 2195 */ 2196 @Nullable 2197 public ResponderConfig enableRttResponder(int timeoutSeconds) { 2198 synchronized (sLock) { 2199 if (!isHalStarted()) return null; 2200 if (sRttResponderCmdId != 0) { 2201 if (DBG) Log.e(mTAG, "responder mode already enabled - this shouldn't happen"); 2202 return null; 2203 } 2204 int id = getNewCmdIdLocked(); 2205 ResponderConfig config = enableRttResponderNative( 2206 sWlan0Index, id, timeoutSeconds, null); 2207 if (config != null) sRttResponderCmdId = id; 2208 if (DBG) Log.d(TAG, "enabling rtt " + (config != null)); 2209 return config; 2210 } 2211 } 2212 2213 private static native boolean disableRttResponderNative(int iface, int commandId); 2214 /** 2215 * Disable RTT responder role. Returns {@code true} if responder role is successfully disabled, 2216 * {@code false} otherwise. 2217 */ 2218 public boolean disableRttResponder() { 2219 synchronized (sLock) { 2220 if (!isHalStarted()) return false; 2221 if (sRttResponderCmdId == 0) { 2222 Log.e(mTAG, "responder role not enabled yet"); 2223 return true; 2224 } 2225 sRttResponderCmdId = 0; 2226 return disableRttResponderNative(sWlan0Index, sRttResponderCmdId); 2227 } 2228 } 2229 2230 private static native boolean setScanningMacOuiNative(int iface, byte[] oui); 2231 2232 public boolean setScanningMacOui(byte[] oui) { 2233 synchronized (sLock) { 2234 if (isHalStarted()) { 2235 return setScanningMacOuiNative(sWlan0Index, oui); 2236 } else { 2237 return false; 2238 } 2239 } 2240 } 2241 2242 private static native int[] getChannelsForBandNative( 2243 int iface, int band); 2244 2245 public int [] getChannelsForBand(int band) { 2246 synchronized (sLock) { 2247 if (isHalStarted()) { 2248 return getChannelsForBandNative(sWlan0Index, band); 2249 } else { 2250 return null; 2251 } 2252 } 2253 } 2254 2255 private static native boolean isGetChannelsForBandSupportedNative(); 2256 public boolean isGetChannelsForBandSupported(){ 2257 synchronized (sLock) { 2258 if (isHalStarted()) { 2259 return isGetChannelsForBandSupportedNative(); 2260 } else { 2261 return false; 2262 } 2263 } 2264 } 2265 2266 private static native boolean setDfsFlagNative(int iface, boolean dfsOn); 2267 public boolean setDfsFlag(boolean dfsOn) { 2268 synchronized (sLock) { 2269 if (isHalStarted()) { 2270 return setDfsFlagNative(sWlan0Index, dfsOn); 2271 } else { 2272 return false; 2273 } 2274 } 2275 } 2276 2277 private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface); 2278 public RttManager.RttCapabilities getRttCapabilities() { 2279 synchronized (sLock) { 2280 if (isHalStarted()) { 2281 return getRttCapabilitiesNative(sWlan0Index); 2282 } else { 2283 return null; 2284 } 2285 } 2286 } 2287 2288 private static native ApfCapabilities getApfCapabilitiesNative(int iface); 2289 public ApfCapabilities getApfCapabilities() { 2290 synchronized (sLock) { 2291 if (isHalStarted()) { 2292 return getApfCapabilitiesNative(sWlan0Index); 2293 } else { 2294 return null; 2295 } 2296 } 2297 } 2298 2299 private static native boolean installPacketFilterNative(int iface, byte[] filter); 2300 public boolean installPacketFilter(byte[] filter) { 2301 synchronized (sLock) { 2302 if (isHalStarted()) { 2303 return installPacketFilterNative(sWlan0Index, filter); 2304 } else { 2305 return false; 2306 } 2307 } 2308 } 2309 2310 private static native boolean setCountryCodeHalNative(int iface, String CountryCode); 2311 public boolean setCountryCodeHal(String CountryCode) { 2312 synchronized (sLock) { 2313 if (isHalStarted()) { 2314 return setCountryCodeHalNative(sWlan0Index, CountryCode); 2315 } else { 2316 return false; 2317 } 2318 } 2319 } 2320 2321 /* Rtt related commands/events */ 2322 public abstract class TdlsEventHandler { 2323 abstract public void onTdlsStatus(String macAddr, int status, int reason); 2324 } 2325 2326 private static TdlsEventHandler sTdlsEventHandler; 2327 2328 private static native boolean enableDisableTdlsNative(int iface, boolean enable, 2329 String macAddr); 2330 public boolean enableDisableTdls(boolean enable, String macAdd, TdlsEventHandler tdlsCallBack) { 2331 synchronized (sLock) { 2332 sTdlsEventHandler = tdlsCallBack; 2333 return enableDisableTdlsNative(sWlan0Index, enable, macAdd); 2334 } 2335 } 2336 2337 // Once TDLS per mac and event feature is implemented, this class definition should be 2338 // moved to the right place, like WifiManager etc 2339 public static class TdlsStatus { 2340 int channel; 2341 int global_operating_class; 2342 int state; 2343 int reason; 2344 } 2345 private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr); 2346 public TdlsStatus getTdlsStatus(String macAdd) { 2347 synchronized (sLock) { 2348 if (isHalStarted()) { 2349 return getTdlsStatusNative(sWlan0Index, macAdd); 2350 } else { 2351 return null; 2352 } 2353 } 2354 } 2355 2356 //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be 2357 // moved to the right place, like WifiStateMachine etc 2358 public static class TdlsCapabilities { 2359 /* Maximum TDLS session number can be supported by the Firmware and hardware */ 2360 int maxConcurrentTdlsSessionNumber; 2361 boolean isGlobalTdlsSupported; 2362 boolean isPerMacTdlsSupported; 2363 boolean isOffChannelTdlsSupported; 2364 } 2365 2366 2367 2368 private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface); 2369 public TdlsCapabilities getTdlsCapabilities () { 2370 synchronized (sLock) { 2371 if (isHalStarted()) { 2372 return getTdlsCapabilitiesNative(sWlan0Index); 2373 } else { 2374 return null; 2375 } 2376 } 2377 } 2378 2379 private static boolean onTdlsStatus(String macAddr, int status, int reason) { 2380 TdlsEventHandler handler = sTdlsEventHandler; 2381 if (handler == null) { 2382 return false; 2383 } else { 2384 handler.onTdlsStatus(macAddr, status, reason); 2385 return true; 2386 } 2387 } 2388 2389 //--------------------------------------------------------------------------------- 2390 2391 /* Wifi Logger commands/events */ 2392 2393 public static interface WifiLoggerEventHandler { 2394 void onRingBufferData(RingBufferStatus status, byte[] buffer); 2395 void onWifiAlert(int errorCode, byte[] buffer); 2396 } 2397 2398 private static WifiLoggerEventHandler sWifiLoggerEventHandler = null; 2399 2400 // Callback from native 2401 private static void onRingBufferData(RingBufferStatus status, byte[] buffer) { 2402 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2403 if (handler != null) 2404 handler.onRingBufferData(status, buffer); 2405 } 2406 2407 // Callback from native 2408 private static void onWifiAlert(byte[] buffer, int errorCode) { 2409 WifiLoggerEventHandler handler = sWifiLoggerEventHandler; 2410 if (handler != null) 2411 handler.onWifiAlert(errorCode, buffer); 2412 } 2413 2414 private static int sLogCmdId = -1; 2415 private static native boolean setLoggingEventHandlerNative(int iface, int id); 2416 public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) { 2417 synchronized (sLock) { 2418 if (isHalStarted()) { 2419 int oldId = sLogCmdId; 2420 sLogCmdId = getNewCmdIdLocked(); 2421 if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) { 2422 sLogCmdId = oldId; 2423 return false; 2424 } 2425 sWifiLoggerEventHandler = handler; 2426 return true; 2427 } else { 2428 return false; 2429 } 2430 } 2431 } 2432 2433 private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel, 2434 int flags, int minIntervalSec ,int minDataSize, String ringName); 2435 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval, 2436 int minDataSize, String ringName){ 2437 synchronized (sLock) { 2438 if (isHalStarted()) { 2439 return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval, 2440 minDataSize, ringName); 2441 } else { 2442 return false; 2443 } 2444 } 2445 } 2446 2447 private static native int getSupportedLoggerFeatureSetNative(int iface); 2448 public int getSupportedLoggerFeatureSet() { 2449 synchronized (sLock) { 2450 if (isHalStarted()) { 2451 return getSupportedLoggerFeatureSetNative(sWlan0Index); 2452 } else { 2453 return 0; 2454 } 2455 } 2456 } 2457 2458 private static native boolean resetLogHandlerNative(int iface, int id); 2459 public boolean resetLogHandler() { 2460 synchronized (sLock) { 2461 if (isHalStarted()) { 2462 if (sLogCmdId == -1) { 2463 Log.e(TAG,"Can not reset handler Before set any handler"); 2464 return false; 2465 } 2466 sWifiLoggerEventHandler = null; 2467 if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) { 2468 sLogCmdId = -1; 2469 return true; 2470 } else { 2471 return false; 2472 } 2473 } else { 2474 return false; 2475 } 2476 } 2477 } 2478 2479 private static native String getDriverVersionNative(int iface); 2480 public String getDriverVersion() { 2481 synchronized (sLock) { 2482 if (isHalStarted()) { 2483 return getDriverVersionNative(sWlan0Index); 2484 } else { 2485 return ""; 2486 } 2487 } 2488 } 2489 2490 2491 private static native String getFirmwareVersionNative(int iface); 2492 public String getFirmwareVersion() { 2493 synchronized (sLock) { 2494 if (isHalStarted()) { 2495 return getFirmwareVersionNative(sWlan0Index); 2496 } else { 2497 return ""; 2498 } 2499 } 2500 } 2501 2502 public static class RingBufferStatus{ 2503 String name; 2504 int flag; 2505 int ringBufferId; 2506 int ringBufferByteSize; 2507 int verboseLevel; 2508 int writtenBytes; 2509 int readBytes; 2510 int writtenRecords; 2511 2512 @Override 2513 public String toString() { 2514 return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId + 2515 " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel + 2516 " writtenBytes: " + writtenBytes + " readBytes: " + readBytes + 2517 " writtenRecords: " + writtenRecords; 2518 } 2519 } 2520 2521 private static native RingBufferStatus[] getRingBufferStatusNative(int iface); 2522 public RingBufferStatus[] getRingBufferStatus() { 2523 synchronized (sLock) { 2524 if (isHalStarted()) { 2525 return getRingBufferStatusNative(sWlan0Index); 2526 } else { 2527 return null; 2528 } 2529 } 2530 } 2531 2532 private static native boolean getRingBufferDataNative(int iface, String ringName); 2533 public boolean getRingBufferData(String ringName) { 2534 synchronized (sLock) { 2535 if (isHalStarted()) { 2536 return getRingBufferDataNative(sWlan0Index, ringName); 2537 } else { 2538 return false; 2539 } 2540 } 2541 } 2542 2543 private static byte[] mFwMemoryDump; 2544 // Callback from native 2545 private static void onWifiFwMemoryAvailable(byte[] buffer) { 2546 mFwMemoryDump = buffer; 2547 if (DBG) { 2548 Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " + 2549 (buffer == null ? 0 : buffer.length)); 2550 } 2551 } 2552 2553 private static native boolean getFwMemoryDumpNative(int iface); 2554 public byte[] getFwMemoryDump() { 2555 synchronized (sLock) { 2556 if (isHalStarted()) { 2557 if(getFwMemoryDumpNative(sWlan0Index)) { 2558 byte[] fwMemoryDump = mFwMemoryDump; 2559 mFwMemoryDump = null; 2560 return fwMemoryDump; 2561 } else { 2562 return null; 2563 } 2564 } 2565 return null; 2566 } 2567 } 2568 2569 private static native byte[] getDriverStateDumpNative(int iface); 2570 /** Fetch the driver state, for driver debugging. */ 2571 public byte[] getDriverStateDump() { 2572 synchronized (sLock) { 2573 if (isHalStarted()) { 2574 return getDriverStateDumpNative(sWlan0Index); 2575 } else { 2576 return null; 2577 } 2578 } 2579 } 2580 2581 //--------------------------------------------------------------------------------- 2582 /* Packet fate API */ 2583 2584 @Immutable 2585 abstract static class FateReport { 2586 final static int USEC_PER_MSEC = 1000; 2587 // The driver timestamp is a 32-bit counter, in microseconds. This field holds the 2588 // maximal value of a driver timestamp in milliseconds. 2589 final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000); 2590 final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS"); 2591 2592 final byte mFate; 2593 final long mDriverTimestampUSec; 2594 final byte mFrameType; 2595 final byte[] mFrameBytes; 2596 final long mEstimatedWallclockMSec; 2597 2598 FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2599 mFate = fate; 2600 mDriverTimestampUSec = driverTimestampUSec; 2601 mEstimatedWallclockMSec = 2602 convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec); 2603 mFrameType = frameType; 2604 mFrameBytes = frameBytes; 2605 } 2606 2607 public String toTableRowString() { 2608 StringWriter sw = new StringWriter(); 2609 PrintWriter pw = new PrintWriter(sw); 2610 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2611 dateFormatter.setTimeZone(TimeZone.getDefault()); 2612 pw.format("%-15s %12s %-9s %-32s %-12s %-23s %s\n", 2613 mDriverTimestampUSec, 2614 dateFormatter.format(new Date(mEstimatedWallclockMSec)), 2615 directionToString(), fateToString(), parser.mMostSpecificProtocolString, 2616 parser.mTypeString, parser.mResultString); 2617 return sw.toString(); 2618 } 2619 2620 public String toVerboseStringWithPiiAllowed() { 2621 StringWriter sw = new StringWriter(); 2622 PrintWriter pw = new PrintWriter(sw); 2623 FrameParser parser = new FrameParser(mFrameType, mFrameBytes); 2624 pw.format("Frame direction: %s\n", directionToString()); 2625 pw.format("Frame timestamp: %d\n", mDriverTimestampUSec); 2626 pw.format("Frame fate: %s\n", fateToString()); 2627 pw.format("Frame type: %s\n", frameTypeToString(mFrameType)); 2628 pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString); 2629 pw.format("Frame protocol type: %s\n", parser.mTypeString); 2630 pw.format("Frame length: %d\n", mFrameBytes.length); 2631 pw.append("Frame bytes"); 2632 pw.append(HexDump.dumpHexString(mFrameBytes)); // potentially contains PII 2633 pw.append("\n"); 2634 return sw.toString(); 2635 } 2636 2637 /* Returns a header to match the output of toTableRowString(). */ 2638 public static String getTableHeader() { 2639 StringWriter sw = new StringWriter(); 2640 PrintWriter pw = new PrintWriter(sw); 2641 pw.format("\n%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2642 "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result"); 2643 pw.format("%-15s %-12s %-9s %-32s %-12s %-23s %s\n", 2644 "---------", "--------", "---------", "----", "--------", "----", "------"); 2645 return sw.toString(); 2646 } 2647 2648 protected abstract String directionToString(); 2649 2650 protected abstract String fateToString(); 2651 2652 private static String frameTypeToString(byte frameType) { 2653 switch (frameType) { 2654 case WifiLoggerHal.FRAME_TYPE_UNKNOWN: 2655 return "unknown"; 2656 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II: 2657 return "data"; 2658 case WifiLoggerHal.FRAME_TYPE_80211_MGMT: 2659 return "802.11 management"; 2660 default: 2661 return Byte.toString(frameType); 2662 } 2663 } 2664 2665 /** 2666 * Converts a driver timestamp to a wallclock time, based on the current 2667 * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of 2668 * microseconds, with the same base as BOOTTIME. 2669 */ 2670 private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) { 2671 final long wallclockMillisNow = System.currentTimeMillis(); 2672 final long boottimeMillisNow = SystemClock.elapsedRealtime(); 2673 final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC; 2674 2675 long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC; 2676 if (boottimeTimestampMillis < driverTimestampMillis) { 2677 // The 32-bit microsecond count has wrapped between the time that the driver 2678 // recorded the packet, and the call to this function. Adjust the BOOTTIME 2679 // timestamp, to compensate. 2680 // 2681 // Note that overflow is not a concern here, since the result is less than 2682 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above, 2683 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since 2684 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit 2685 // within a long. 2686 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC; 2687 } 2688 2689 final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis; 2690 return wallclockMillisNow - millisSincePacketTimestamp; 2691 } 2692 } 2693 2694 /** 2695 * Represents the fate information for one outbound packet. 2696 */ 2697 @Immutable 2698 public static final class TxFateReport extends FateReport { 2699 TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2700 super(fate, driverTimestampUSec, frameType, frameBytes); 2701 } 2702 2703 @Override 2704 protected String directionToString() { 2705 return "TX"; 2706 } 2707 2708 @Override 2709 protected String fateToString() { 2710 switch (mFate) { 2711 case WifiLoggerHal.TX_PKT_FATE_ACKED: 2712 return "acked"; 2713 case WifiLoggerHal.TX_PKT_FATE_SENT: 2714 return "sent"; 2715 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED: 2716 return "firmware queued"; 2717 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID: 2718 return "firmware dropped (invalid frame)"; 2719 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS: 2720 return "firmware dropped (no bufs)"; 2721 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER: 2722 return "firmware dropped (other)"; 2723 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED: 2724 return "driver queued"; 2725 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID: 2726 return "driver dropped (invalid frame)"; 2727 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS: 2728 return "driver dropped (no bufs)"; 2729 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER: 2730 return "driver dropped (other)"; 2731 default: 2732 return Byte.toString(mFate); 2733 } 2734 } 2735 } 2736 2737 /** 2738 * Represents the fate information for one inbound packet. 2739 */ 2740 @Immutable 2741 public static final class RxFateReport extends FateReport { 2742 RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) { 2743 super(fate, driverTimestampUSec, frameType, frameBytes); 2744 } 2745 2746 @Override 2747 protected String directionToString() { 2748 return "RX"; 2749 } 2750 2751 @Override 2752 protected String fateToString() { 2753 switch (mFate) { 2754 case WifiLoggerHal.RX_PKT_FATE_SUCCESS: 2755 return "success"; 2756 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED: 2757 return "firmware queued"; 2758 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER: 2759 return "firmware dropped (filter)"; 2760 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID: 2761 return "firmware dropped (invalid frame)"; 2762 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS: 2763 return "firmware dropped (no bufs)"; 2764 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER: 2765 return "firmware dropped (other)"; 2766 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED: 2767 return "driver queued"; 2768 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER: 2769 return "driver dropped (filter)"; 2770 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID: 2771 return "driver dropped (invalid frame)"; 2772 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS: 2773 return "driver dropped (no bufs)"; 2774 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER: 2775 return "driver dropped (other)"; 2776 default: 2777 return Byte.toString(mFate); 2778 } 2779 } 2780 } 2781 2782 private static native int startPktFateMonitoringNative(int iface); 2783 /** 2784 * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started. 2785 */ 2786 public boolean startPktFateMonitoring() { 2787 synchronized (sLock) { 2788 if (isHalStarted()) { 2789 return startPktFateMonitoringNative(sWlan0Index) == WIFI_SUCCESS; 2790 } else { 2791 return false; 2792 } 2793 } 2794 } 2795 2796 private static native int getTxPktFatesNative(int iface, TxFateReport[] reportBufs); 2797 /** 2798 * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started. 2799 */ 2800 public boolean getTxPktFates(TxFateReport[] reportBufs) { 2801 synchronized (sLock) { 2802 if (isHalStarted()) { 2803 int res = getTxPktFatesNative(sWlan0Index, reportBufs); 2804 if (res != WIFI_SUCCESS) { 2805 Log.e(TAG, "getTxPktFatesNative returned " + res); 2806 return false; 2807 } else { 2808 return true; 2809 } 2810 } else { 2811 return false; 2812 } 2813 } 2814 } 2815 2816 private static native int getRxPktFatesNative(int iface, RxFateReport[] reportBufs); 2817 /** 2818 * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started. 2819 */ 2820 public boolean getRxPktFates(RxFateReport[] reportBufs) { 2821 synchronized (sLock) { 2822 if (isHalStarted()) { 2823 int res = getRxPktFatesNative(sWlan0Index, reportBufs); 2824 if (res != WIFI_SUCCESS) { 2825 Log.e(TAG, "getRxPktFatesNative returned " + res); 2826 return false; 2827 } else { 2828 return true; 2829 } 2830 } else { 2831 return false; 2832 } 2833 } 2834 } 2835 2836 //--------------------------------------------------------------------------------- 2837 /* Configure ePNO/PNO */ 2838 private static PnoEventHandler sPnoEventHandler; 2839 private static int sPnoCmdId = 0; 2840 2841 private static native boolean setPnoListNative(int iface, int id, PnoSettings settings); 2842 2843 /** 2844 * Set the PNO settings & the network list in HAL to start PNO. 2845 * @param settings PNO settings and network list. 2846 * @param eventHandler Handler to receive notifications back during PNO scan. 2847 * @return true if success, false otherwise 2848 */ 2849 public boolean setPnoList(PnoSettings settings, PnoEventHandler eventHandler) { 2850 Log.e(TAG, "setPnoList cmd " + sPnoCmdId); 2851 2852 synchronized (sLock) { 2853 if (isHalStarted()) { 2854 sPnoCmdId = getNewCmdIdLocked(); 2855 sPnoEventHandler = eventHandler; 2856 if (setPnoListNative(sWlan0Index, sPnoCmdId, settings)) { 2857 return true; 2858 } 2859 } 2860 sPnoEventHandler = null; 2861 return false; 2862 } 2863 } 2864 2865 /** 2866 * Set the PNO network list in HAL to start PNO. 2867 * @param list PNO network list. 2868 * @param eventHandler Handler to receive notifications back during PNO scan. 2869 * @return true if success, false otherwise 2870 */ 2871 public boolean setPnoList(PnoNetwork[] list, PnoEventHandler eventHandler) { 2872 PnoSettings settings = new PnoSettings(); 2873 settings.networkList = list; 2874 return setPnoList(settings, eventHandler); 2875 } 2876 2877 private static native boolean resetPnoListNative(int iface, int id); 2878 2879 /** 2880 * Reset the PNO settings in HAL to stop PNO. 2881 * @return true if success, false otherwise 2882 */ 2883 public boolean resetPnoList() { 2884 Log.e(TAG, "resetPnoList cmd " + sPnoCmdId); 2885 2886 synchronized (sLock) { 2887 if (isHalStarted()) { 2888 sPnoCmdId = getNewCmdIdLocked(); 2889 sPnoEventHandler = null; 2890 if (resetPnoListNative(sWlan0Index, sPnoCmdId)) { 2891 return true; 2892 } 2893 } 2894 return false; 2895 } 2896 } 2897 2898 // Callback from native 2899 private static void onPnoNetworkFound(int id, ScanResult[] results, int[] beaconCaps) { 2900 if (results == null) { 2901 Log.e(TAG, "onPnoNetworkFound null results"); 2902 return; 2903 2904 } 2905 Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length); 2906 2907 PnoEventHandler handler = sPnoEventHandler; 2908 if (sPnoCmdId != 0 && handler != null) { 2909 for (int i=0; i<results.length; i++) { 2910 Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID 2911 + " " + results[i].level + " " + results[i].frequency); 2912 2913 populateScanResult(results[i], beaconCaps[i], "onPnoNetworkFound "); 2914 results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID); 2915 } 2916 2917 handler.onPnoNetworkFound(results); 2918 } else { 2919 /* this can happen because of race conditions */ 2920 Log.d(TAG, "Ignoring Pno Network found event"); 2921 } 2922 } 2923 2924 private native static int startSendingOffloadedPacketNative(int iface, int idx, 2925 byte[] srcMac, byte[] dstMac, byte[] pktData, int period); 2926 2927 public int 2928 startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) { 2929 Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period); 2930 2931 String[] macAddrStr = getMacAddress().split(":"); 2932 byte[] srcMac = new byte[6]; 2933 for(int i = 0; i < 6; i++) { 2934 Integer hexVal = Integer.parseInt(macAddrStr[i], 16); 2935 srcMac[i] = hexVal.byteValue(); 2936 } 2937 synchronized (sLock) { 2938 if (isHalStarted()) { 2939 return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac, 2940 keepAlivePacket.dstMac, keepAlivePacket.data, period); 2941 } else { 2942 return -1; 2943 } 2944 } 2945 } 2946 2947 private native static int stopSendingOffloadedPacketNative(int iface, int idx); 2948 2949 public int 2950 stopSendingOffloadedPacket(int slot) { 2951 Log.d(TAG, "stopSendingOffloadedPacket " + slot); 2952 synchronized (sLock) { 2953 if (isHalStarted()) { 2954 return stopSendingOffloadedPacketNative(sWlan0Index, slot); 2955 } else { 2956 return -1; 2957 } 2958 } 2959 } 2960 2961 public static interface WifiRssiEventHandler { 2962 void onRssiThresholdBreached(byte curRssi); 2963 } 2964 2965 private static WifiRssiEventHandler sWifiRssiEventHandler; 2966 2967 // Callback from native 2968 private static void onRssiThresholdBreached(int id, byte curRssi) { 2969 WifiRssiEventHandler handler = sWifiRssiEventHandler; 2970 if (handler != null) { 2971 handler.onRssiThresholdBreached(curRssi); 2972 } 2973 } 2974 2975 private native static int startRssiMonitoringNative(int iface, int id, 2976 byte maxRssi, byte minRssi); 2977 2978 private static int sRssiMonitorCmdId = 0; 2979 2980 public int startRssiMonitoring(byte maxRssi, byte minRssi, 2981 WifiRssiEventHandler rssiEventHandler) { 2982 Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi); 2983 synchronized (sLock) { 2984 sWifiRssiEventHandler = rssiEventHandler; 2985 if (isHalStarted()) { 2986 if (sRssiMonitorCmdId != 0) { 2987 stopRssiMonitoring(); 2988 } 2989 2990 sRssiMonitorCmdId = getNewCmdIdLocked(); 2991 Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); 2992 int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, 2993 maxRssi, minRssi); 2994 if (ret != 0) { // if not success 2995 sRssiMonitorCmdId = 0; 2996 } 2997 return ret; 2998 } else { 2999 return -1; 3000 } 3001 } 3002 } 3003 3004 private native static int stopRssiMonitoringNative(int iface, int idx); 3005 3006 public int stopRssiMonitoring() { 3007 Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId); 3008 synchronized (sLock) { 3009 if (isHalStarted()) { 3010 int ret = 0; 3011 if (sRssiMonitorCmdId != 0) { 3012 ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); 3013 } 3014 sRssiMonitorCmdId = 0; 3015 return ret; 3016 } else { 3017 return -1; 3018 } 3019 } 3020 } 3021 3022 private static native WifiWakeReasonAndCounts getWlanWakeReasonCountNative(int iface); 3023 3024 /** 3025 * Fetch the host wakeup reasons stats from wlan driver. 3026 * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver. 3027 */ 3028 public WifiWakeReasonAndCounts getWlanWakeReasonCount() { 3029 Log.d(TAG, "getWlanWakeReasonCount " + sWlan0Index); 3030 synchronized (sLock) { 3031 if (isHalStarted()) { 3032 return getWlanWakeReasonCountNative(sWlan0Index); 3033 } else { 3034 return null; 3035 } 3036 } 3037 } 3038 3039 private static native int configureNeighborDiscoveryOffload(int iface, boolean enabled); 3040 3041 public boolean configureNeighborDiscoveryOffload(boolean enabled) { 3042 final String logMsg = "configureNeighborDiscoveryOffload(" + enabled + ")"; 3043 Log.d(mTAG, logMsg); 3044 synchronized (sLock) { 3045 if (isHalStarted()) { 3046 final int ret = configureNeighborDiscoveryOffload(sWlan0Index, enabled); 3047 if (ret != 0) { 3048 Log.d(mTAG, logMsg + " returned: " + ret); 3049 } 3050 return (ret == 0); 3051 } 3052 } 3053 return false; 3054 } 3055} 3056