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