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