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