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 
17 package com.android.server.wifi;
18 
19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.net.MacAddress;
24 import android.net.TrafficStats;
25 import android.net.apf.ApfCapabilities;
26 import android.net.wifi.ScanResult;
27 import android.net.wifi.SoftApConfiguration;
28 import android.net.wifi.WifiAnnotations;
29 import android.net.wifi.WifiConfiguration;
30 import android.net.wifi.WifiScanner;
31 import android.net.wifi.WifiSsid;
32 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
33 import android.net.wifi.nl80211.NativeScanResult;
34 import android.net.wifi.nl80211.RadioChainInfo;
35 import android.net.wifi.nl80211.WifiNl80211Manager;
36 import android.os.Handler;
37 import android.os.SystemClock;
38 import android.text.TextUtils;
39 import android.util.ArraySet;
40 import android.util.Log;
41 
42 import com.android.internal.annotations.Immutable;
43 import com.android.internal.util.HexDump;
44 import com.android.server.wifi.hotspot2.NetworkDetail;
45 import com.android.server.wifi.util.FrameParser;
46 import com.android.server.wifi.util.InformationElementUtil;
47 import com.android.server.wifi.util.NativeUtil;
48 import com.android.server.wifi.util.NetdWrapper;
49 import com.android.server.wifi.util.NetdWrapper.NetdEventObserver;
50 
51 import java.io.PrintWriter;
52 import java.io.StringWriter;
53 import java.lang.annotation.Retention;
54 import java.lang.annotation.RetentionPolicy;
55 import java.nio.ByteBuffer;
56 import java.nio.ByteOrder;
57 import java.text.SimpleDateFormat;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Date;
61 import java.util.HashMap;
62 import java.util.HashSet;
63 import java.util.Iterator;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.Objects;
67 import java.util.Random;
68 import java.util.Set;
69 import java.util.TimeZone;
70 
71 /**
72  * Native calls for bring up/shut down of the supplicant daemon and for
73  * sending requests to the supplicant daemon
74  *
75  * {@hide}
76  */
77 public class WifiNative {
78     private static final String TAG = "WifiNative";
79 
80     private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
81     private final HostapdHal mHostapdHal;
82     private final WifiVendorHal mWifiVendorHal;
83     private final WifiNl80211Manager mWifiCondManager;
84     private final WifiMonitor mWifiMonitor;
85     private final PropertyService mPropertyService;
86     private final WifiMetrics mWifiMetrics;
87     private final Handler mHandler;
88     private final Random mRandom;
89     private final WifiInjector mWifiInjector;
90     private NetdWrapper mNetdWrapper;
91     private boolean mVerboseLoggingEnabled = false;
92 
WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WifiNl80211Manager condManager, WifiMonitor wifiMonitor, PropertyService propertyService, WifiMetrics wifiMetrics, Handler handler, Random random, WifiInjector wifiInjector)93     public WifiNative(WifiVendorHal vendorHal,
94                       SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,
95                       WifiNl80211Manager condManager, WifiMonitor wifiMonitor,
96                       PropertyService propertyService, WifiMetrics wifiMetrics,
97                       Handler handler, Random random,
98                       WifiInjector wifiInjector) {
99         mWifiVendorHal = vendorHal;
100         mSupplicantStaIfaceHal = staIfaceHal;
101         mHostapdHal = hostapdHal;
102         mWifiCondManager = condManager;
103         mWifiMonitor = wifiMonitor;
104         mPropertyService = propertyService;
105         mWifiMetrics = wifiMetrics;
106         mHandler = handler;
107         mRandom = random;
108         mWifiInjector = wifiInjector;
109     }
110 
111     /**
112      * Enable verbose logging for all sub modules.
113      */
enableVerboseLogging(int verbose)114     public void enableVerboseLogging(int verbose) {
115         mVerboseLoggingEnabled = verbose > 0 ? true : false;
116         mWifiCondManager.enableVerboseLogging(mVerboseLoggingEnabled);
117         mSupplicantStaIfaceHal.enableVerboseLogging(mVerboseLoggingEnabled);
118         mHostapdHal.enableVerboseLogging(mVerboseLoggingEnabled);
119         mWifiVendorHal.enableVerboseLogging(mVerboseLoggingEnabled);
120     }
121 
122     /**
123      * Callbacks for SoftAp interface.
124      */
125     public interface SoftApListener extends WifiNl80211Manager.SoftApCallback {
126         // dummy for now - provide a shell so that clients don't use a
127         // WifiNl80211Manager-specific API.
128     }
129 
130     /********************************************************
131      * Interface management related methods.
132      ********************************************************/
133     /**
134      * Meta-info about every iface that is active.
135      */
136     private static class Iface {
137         /** Type of ifaces possible */
138         public static final int IFACE_TYPE_AP = 0;
139         public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1;
140         public static final int IFACE_TYPE_STA_FOR_SCAN = 2;
141 
142         @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN})
143         @Retention(RetentionPolicy.SOURCE)
144         public @interface IfaceType{}
145 
146         /** Identifier allocated for the interface */
147         public final int id;
148         /** Type of the iface: STA (for Connectivity or Scan) or AP */
149         public @IfaceType int type;
150         /** Name of the interface */
151         public String name;
152         /** Is the interface up? This is used to mask up/down notifications to external clients. */
153         public boolean isUp;
154         /** External iface destroyed listener for the iface */
155         public InterfaceCallback externalListener;
156         /** Network observer registered for this interface */
157         public NetworkObserverInternal networkObserver;
158         /** Interface feature set / capabilities */
159         public long featureSet;
160         public DeviceWiphyCapabilities phyCapabilities;
161 
Iface(int id, @Iface.IfaceType int type)162         Iface(int id, @Iface.IfaceType int type) {
163             this.id = id;
164             this.type = type;
165         }
166 
167         @Override
toString()168         public String toString() {
169             StringBuffer sb = new StringBuffer();
170             String typeString;
171             switch(type) {
172                 case IFACE_TYPE_STA_FOR_CONNECTIVITY:
173                     typeString = "STA_CONNECTIVITY";
174                     break;
175                 case IFACE_TYPE_STA_FOR_SCAN:
176                     typeString = "STA_SCAN";
177                     break;
178                 case IFACE_TYPE_AP:
179                     typeString = "AP";
180                     break;
181                 default:
182                     typeString = "<UNKNOWN>";
183                     break;
184             }
185             sb.append("Iface:")
186                 .append("{")
187                 .append("Name=").append(name)
188                 .append(",")
189                 .append("Id=").append(id)
190                 .append(",")
191                 .append("Type=").append(typeString)
192                 .append("}");
193             return sb.toString();
194         }
195     }
196 
197     /**
198      * Iface Management entity. This class maintains list of all the active ifaces.
199      */
200     private static class IfaceManager {
201         /** Integer to allocate for the next iface being created */
202         private int mNextId;
203         /** Map of the id to the iface structure */
204         private HashMap<Integer, Iface> mIfaces = new HashMap<>();
205 
206         /** Allocate a new iface for the given type */
allocateIface(@face.IfaceType int type)207         private Iface allocateIface(@Iface.IfaceType  int type) {
208             Iface iface = new Iface(mNextId, type);
209             mIfaces.put(mNextId, iface);
210             mNextId++;
211             return iface;
212         }
213 
214         /** Remove the iface using the provided id */
removeIface(int id)215         private Iface removeIface(int id) {
216             return mIfaces.remove(id);
217         }
218 
219         /** Lookup the iface using the provided id */
getIface(int id)220         private Iface getIface(int id) {
221             return mIfaces.get(id);
222         }
223 
224         /** Lookup the iface using the provided name */
getIface(@onNull String ifaceName)225         private Iface getIface(@NonNull String ifaceName) {
226             for (Iface iface : mIfaces.values()) {
227                 if (TextUtils.equals(iface.name, ifaceName)) {
228                     return iface;
229                 }
230             }
231             return null;
232         }
233 
234         /** Iterator to use for deleting all the ifaces while performing teardown on each of them */
getIfaceIdIter()235         private Iterator<Integer> getIfaceIdIter() {
236             return mIfaces.keySet().iterator();
237         }
238 
239         /** Checks if there are any iface active. */
hasAnyIface()240         private boolean hasAnyIface() {
241             return !mIfaces.isEmpty();
242         }
243 
244         /** Checks if there are any iface of the given type active. */
hasAnyIfaceOfType(@face.IfaceType int type)245         private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) {
246             for (Iface iface : mIfaces.values()) {
247                 if (iface.type == type) {
248                     return true;
249                 }
250             }
251             return false;
252         }
253 
254         /** Checks if there are any iface of the given type active. */
findAnyIfaceOfType(@face.IfaceType int type)255         private Iface findAnyIfaceOfType(@Iface.IfaceType int type) {
256             for (Iface iface : mIfaces.values()) {
257                 if (iface.type == type) {
258                     return iface;
259                 }
260             }
261             return null;
262         }
263 
264         /** Checks if there are any STA (for connectivity) iface active. */
hasAnyStaIfaceForConnectivity()265         private boolean hasAnyStaIfaceForConnectivity() {
266             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
267         }
268 
269         /** Checks if there are any STA (for scan) iface active. */
hasAnyStaIfaceForScan()270         private boolean hasAnyStaIfaceForScan() {
271             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN);
272         }
273 
274         /** Checks if there are any AP iface active. */
hasAnyApIface()275         private boolean hasAnyApIface() {
276             return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP);
277         }
278 
279         /** Finds the name of any STA iface active. */
findAnyStaIfaceName()280         private String findAnyStaIfaceName() {
281             Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
282             if (iface == null) {
283                 iface = findAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN);
284             }
285             if (iface == null) {
286                 return null;
287             }
288             return iface.name;
289         }
290 
291         /** Finds the name of any AP iface active. */
findAnyApIfaceName()292         private String findAnyApIfaceName() {
293             Iface iface = findAnyIfaceOfType(Iface.IFACE_TYPE_AP);
294             if (iface == null) {
295                 return null;
296             }
297             return iface.name;
298         }
299 
findAllStaIfaceNames()300         private @NonNull Set<String> findAllStaIfaceNames() {
301             Set<String> ifaceNames = new ArraySet<>();
302             for (Iface iface : mIfaces.values()) {
303                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
304                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
305                     ifaceNames.add(iface.name);
306                 }
307             }
308             return ifaceNames;
309         }
310 
311         /** Removes the existing iface that does not match the provided id. */
removeExistingIface(int newIfaceId)312         public Iface removeExistingIface(int newIfaceId) {
313             Iface removedIface = null;
314             // The number of ifaces in the database could be 1 existing & 1 new at the max.
315             if (mIfaces.size() > 2) {
316                 Log.wtf(TAG, "More than 1 existing interface found");
317             }
318             Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator();
319             while (iter.hasNext()) {
320                 Map.Entry<Integer, Iface> entry = iter.next();
321                 if (entry.getKey() != newIfaceId) {
322                     removedIface = entry.getValue();
323                     iter.remove();
324                 }
325             }
326             return removedIface;
327         }
328     }
329 
330     private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
331         private String mIfaceName;
332 
NormalScanEventCallback(String ifaceName)333         NormalScanEventCallback(String ifaceName) {
334             mIfaceName = ifaceName;
335         }
336 
337         @Override
onScanResultReady()338         public void onScanResultReady() {
339             Log.d(TAG, "Scan result ready event");
340             mWifiMonitor.broadcastScanResultEvent(mIfaceName);
341         }
342 
343         @Override
onScanFailed()344         public void onScanFailed() {
345             Log.d(TAG, "Scan failed event");
346             mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
347         }
348     }
349 
350     private class PnoScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
351         private String mIfaceName;
352 
PnoScanEventCallback(String ifaceName)353         PnoScanEventCallback(String ifaceName) {
354             mIfaceName = ifaceName;
355         }
356 
357         @Override
onScanResultReady()358         public void onScanResultReady() {
359             Log.d(TAG, "Pno scan result event");
360             mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName);
361             mWifiMetrics.incrementPnoFoundNetworkEventCount();
362         }
363 
364         @Override
onScanFailed()365         public void onScanFailed() {
366             Log.d(TAG, "Pno Scan failed event");
367             mWifiMetrics.incrementPnoScanFailedCount();
368         }
369     }
370 
371     private final Object mLock = new Object();
372     private final IfaceManager mIfaceMgr = new IfaceManager();
373     private HashSet<StatusListener> mStatusListeners = new HashSet<>();
374 
375     /** Helper method invoked to start supplicant if there were no ifaces */
startHal()376     private boolean startHal() {
377         synchronized (mLock) {
378             if (!mIfaceMgr.hasAnyIface()) {
379                 if (mWifiVendorHal.isVendorHalSupported()) {
380                     if (!mWifiVendorHal.startVendorHal()) {
381                         Log.e(TAG, "Failed to start vendor HAL");
382                         return false;
383                     }
384                 } else {
385                     Log.i(TAG, "Vendor Hal not supported, ignoring start.");
386                 }
387             }
388             return true;
389         }
390     }
391 
392     /** Helper method invoked to stop HAL if there are no more ifaces */
stopHalAndWificondIfNecessary()393     private void stopHalAndWificondIfNecessary() {
394         synchronized (mLock) {
395             if (!mIfaceMgr.hasAnyIface()) {
396                 if (!mWifiCondManager.tearDownInterfaces()) {
397                     Log.e(TAG, "Failed to teardown ifaces from wificond");
398                 }
399                 if (mWifiVendorHal.isVendorHalSupported()) {
400                     mWifiVendorHal.stopVendorHal();
401                 } else {
402                     Log.i(TAG, "Vendor Hal not supported, ignoring stop.");
403                 }
404             }
405         }
406     }
407 
408     private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100;
409     private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50;
410     /**
411      * This method is called to wait for establishing connection to wpa_supplicant.
412      *
413      * @return true if connection is established, false otherwise.
414      */
startAndWaitForSupplicantConnection()415     private boolean startAndWaitForSupplicantConnection() {
416         // Start initialization if not already started.
417         if (!mSupplicantStaIfaceHal.isInitializationStarted()
418                 && !mSupplicantStaIfaceHal.initialize()) {
419             return false;
420         }
421         if (!mSupplicantStaIfaceHal.startDaemon()) {
422             Log.e(TAG, "Failed to startup supplicant");
423             return false;
424         }
425         boolean connected = false;
426         int connectTries = 0;
427         while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
428             // Check if the initialization is complete.
429             connected = mSupplicantStaIfaceHal.isInitializationComplete();
430             if (connected) {
431                 break;
432             }
433             try {
434                 Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
435             } catch (InterruptedException ignore) {
436             }
437         }
438         return connected;
439     }
440 
441     /** Helper method invoked to start supplicant if there were no STA ifaces */
startSupplicant()442     private boolean startSupplicant() {
443         synchronized (mLock) {
444             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
445                 if (!startAndWaitForSupplicantConnection()) {
446                     Log.e(TAG, "Failed to connect to supplicant");
447                     return false;
448                 }
449                 if (!mSupplicantStaIfaceHal.registerDeathHandler(
450                         new SupplicantDeathHandlerInternal())) {
451                     Log.e(TAG, "Failed to register supplicant death handler");
452                     return false;
453                 }
454             }
455             return true;
456         }
457     }
458 
459     /** Helper method invoked to stop supplicant if there are no more STA ifaces */
stopSupplicantIfNecessary()460     private void stopSupplicantIfNecessary() {
461         synchronized (mLock) {
462             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
463                 if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) {
464                     Log.e(TAG, "Failed to deregister supplicant death handler");
465                 }
466                 mSupplicantStaIfaceHal.terminate();
467             }
468         }
469     }
470 
471     /** Helper method invoked to start hostapd if there were no AP ifaces */
startHostapd()472     private boolean startHostapd() {
473         synchronized (mLock) {
474             if (!mIfaceMgr.hasAnyApIface()) {
475                 if (!startAndWaitForHostapdConnection()) {
476                     Log.e(TAG, "Failed to connect to hostapd");
477                     return false;
478                 }
479                 if (!mHostapdHal.registerDeathHandler(
480                         new HostapdDeathHandlerInternal())) {
481                     Log.e(TAG, "Failed to register hostapd death handler");
482                     return false;
483                 }
484             }
485             return true;
486         }
487     }
488 
489     /** Helper method invoked to stop hostapd if there are no more AP ifaces */
stopHostapdIfNecessary()490     private void stopHostapdIfNecessary() {
491         synchronized (mLock) {
492             if (!mIfaceMgr.hasAnyApIface()) {
493                 if (!mHostapdHal.deregisterDeathHandler()) {
494                     Log.e(TAG, "Failed to deregister hostapd death handler");
495                 }
496                 mHostapdHal.terminate();
497             }
498         }
499     }
500 
501     /** Helper method to register a network observer and return it */
registerNetworkObserver(NetworkObserverInternal observer)502     private boolean registerNetworkObserver(NetworkObserverInternal observer) {
503         if (observer == null) return false;
504         mNetdWrapper.registerObserver(observer);
505         return true;
506     }
507 
508     /** Helper method to unregister a network observer */
unregisterNetworkObserver(NetworkObserverInternal observer)509     private boolean unregisterNetworkObserver(NetworkObserverInternal observer) {
510         if (observer == null) return false;
511         mNetdWrapper.unregisterObserver(observer);
512         return true;
513     }
514 
515     /**
516      * Helper method invoked to teardown client iface (for connectivity) and perform
517      * necessary cleanup
518      */
onClientInterfaceForConnectivityDestroyed(@onNull Iface iface)519     private void onClientInterfaceForConnectivityDestroyed(@NonNull Iface iface) {
520         synchronized (mLock) {
521             mWifiMonitor.stopMonitoring(iface.name);
522             if (!unregisterNetworkObserver(iface.networkObserver)) {
523                 Log.e(TAG, "Failed to unregister network observer on " + iface);
524             }
525             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
526                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
527             }
528             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
529                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
530             }
531             stopSupplicantIfNecessary();
532             stopHalAndWificondIfNecessary();
533         }
534     }
535 
536     /** Helper method invoked to teardown client iface (for scan) and perform necessary cleanup */
onClientInterfaceForScanDestroyed(@onNull Iface iface)537     private void onClientInterfaceForScanDestroyed(@NonNull Iface iface) {
538         synchronized (mLock) {
539             mWifiMonitor.stopMonitoring(iface.name);
540             if (!unregisterNetworkObserver(iface.networkObserver)) {
541                 Log.e(TAG, "Failed to unregister network observer on " + iface);
542             }
543             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
544                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
545             }
546             stopHalAndWificondIfNecessary();
547         }
548     }
549 
550     /** Helper method invoked to teardown softAp iface and perform necessary cleanup */
onSoftApInterfaceDestroyed(@onNull Iface iface)551     private void onSoftApInterfaceDestroyed(@NonNull Iface iface) {
552         synchronized (mLock) {
553             if (!unregisterNetworkObserver(iface.networkObserver)) {
554                 Log.e(TAG, "Failed to unregister network observer on " + iface);
555             }
556             if (!mHostapdHal.removeAccessPoint(iface.name)) {
557                 Log.e(TAG, "Failed to remove access point on " + iface);
558             }
559             if (!mWifiCondManager.tearDownSoftApInterface(iface.name)) {
560                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
561             }
562             stopHostapdIfNecessary();
563             stopHalAndWificondIfNecessary();
564         }
565     }
566 
567     /** Helper method invoked to teardown iface and perform necessary cleanup */
onInterfaceDestroyed(@onNull Iface iface)568     private void onInterfaceDestroyed(@NonNull Iface iface) {
569         synchronized (mLock) {
570             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
571                 onClientInterfaceForConnectivityDestroyed(iface);
572             } else if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
573                 onClientInterfaceForScanDestroyed(iface);
574             } else if (iface.type == Iface.IFACE_TYPE_AP) {
575                 onSoftApInterfaceDestroyed(iface);
576             }
577             // Invoke the external callback.
578             iface.externalListener.onDestroyed(iface.name);
579         }
580     }
581 
582     /**
583      * Callback to be invoked by HalDeviceManager when an interface is destroyed.
584      */
585     private class InterfaceDestoyedListenerInternal
586             implements HalDeviceManager.InterfaceDestroyedListener {
587         /** Identifier allocated for the interface */
588         private final int mInterfaceId;
589 
InterfaceDestoyedListenerInternal(int ifaceId)590         InterfaceDestoyedListenerInternal(int ifaceId) {
591             mInterfaceId = ifaceId;
592         }
593 
594         @Override
onDestroyed(@onNull String ifaceName)595         public void onDestroyed(@NonNull String ifaceName) {
596             synchronized (mLock) {
597                 final Iface iface = mIfaceMgr.removeIface(mInterfaceId);
598                 if (iface == null) {
599                     if (mVerboseLoggingEnabled) {
600                         Log.v(TAG, "Received iface destroyed notification on an invalid iface="
601                                 + ifaceName);
602                     }
603                     return;
604                 }
605                 onInterfaceDestroyed(iface);
606                 Log.i(TAG, "Successfully torn down " + iface);
607             }
608         }
609     }
610 
611     /**
612      * Helper method invoked to trigger the status changed callback after one of the native
613      * daemon's death.
614      */
onNativeDaemonDeath()615     private void onNativeDaemonDeath() {
616         synchronized (mLock) {
617             for (StatusListener listener : mStatusListeners) {
618                 listener.onStatusChanged(false);
619             }
620             for (StatusListener listener : mStatusListeners) {
621                 listener.onStatusChanged(true);
622             }
623         }
624     }
625 
626     /**
627      * Death handler for the Vendor HAL daemon.
628      */
629     private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler {
630         @Override
onDeath()631         public void onDeath() {
632             synchronized (mLock) {
633                 Log.i(TAG, "Vendor HAL died. Cleaning up internal state.");
634                 onNativeDaemonDeath();
635                 mWifiMetrics.incrementNumHalCrashes();
636             }
637         }
638     }
639 
640     /**
641      * Death handler for the wificond daemon.
642      */
643     private class WificondDeathHandlerInternal implements Runnable {
644         @Override
run()645         public void run() {
646             synchronized (mLock) {
647                 Log.i(TAG, "wificond died. Cleaning up internal state.");
648                 onNativeDaemonDeath();
649                 mWifiMetrics.incrementNumWificondCrashes();
650             }
651         }
652     }
653 
654     /**
655      * Death handler for the supplicant daemon.
656      */
657     private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler {
658         @Override
onDeath()659         public void onDeath() {
660             synchronized (mLock) {
661                 Log.i(TAG, "wpa_supplicant died. Cleaning up internal state.");
662                 onNativeDaemonDeath();
663                 mWifiMetrics.incrementNumSupplicantCrashes();
664             }
665         }
666     }
667 
668     /**
669      * Death handler for the hostapd daemon.
670      */
671     private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler {
672         @Override
onDeath()673         public void onDeath() {
674             synchronized (mLock) {
675                 Log.i(TAG, "hostapd died. Cleaning up internal state.");
676                 onNativeDaemonDeath();
677                 mWifiMetrics.incrementNumHostapdCrashes();
678             }
679         }
680     }
681 
682     /** Helper method invoked to handle interface change. */
onInterfaceStateChanged(Iface iface, boolean isUp)683     private void onInterfaceStateChanged(Iface iface, boolean isUp) {
684         synchronized (mLock) {
685             // Mask multiple notifications with the same state.
686             if (isUp == iface.isUp) {
687                 if (mVerboseLoggingEnabled) {
688                     Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp
689                             + ", Ignoring...");
690                 }
691                 return;
692             }
693             Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp);
694             if (isUp) {
695                 iface.externalListener.onUp(iface.name);
696             } else {
697                 iface.externalListener.onDown(iface.name);
698                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
699                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
700                     mWifiMetrics.incrementNumClientInterfaceDown();
701                 } else if (iface.type == Iface.IFACE_TYPE_AP) {
702                     mWifiMetrics.incrementNumSoftApInterfaceDown();
703                 }
704             }
705             iface.isUp = isUp;
706         }
707     }
708 
709     /**
710      * Network observer to use for all interface up/down notifications.
711      */
712     private class NetworkObserverInternal implements NetdEventObserver {
713         /** Identifier allocated for the interface */
714         private final int mInterfaceId;
715 
NetworkObserverInternal(int id)716         NetworkObserverInternal(int id) {
717             mInterfaceId = id;
718         }
719 
720         /**
721          * Note: We should ideally listen to
722          * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that
723          * callback is not working currently (broken in netd). So, instead listen to link state
724          * change callbacks as triggers to query the real interface state. We should get rid of
725          * this workaround if we get the |interfaceStatusChanged| callback to work in netd.
726          * Also, this workaround will not detect an interface up event, if the link state is
727          * still down.
728          */
729         @Override
interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp)730         public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) {
731             // This is invoked from the main system_server thread. Post to our handler.
732             mHandler.post(() -> {
733                 synchronized (mLock) {
734                     final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId);
735                     if (ifaceWithId == null) {
736                         if (mVerboseLoggingEnabled) {
737                             Log.v(TAG, "Received iface link up/down notification on an invalid"
738                                     + " iface=" + mInterfaceId);
739                         }
740                         return;
741                     }
742                     final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName);
743                     if (ifaceWithName == null || ifaceWithName != ifaceWithId) {
744                         if (mVerboseLoggingEnabled) {
745                             Log.v(TAG, "Received iface link up/down notification on an invalid"
746                                     + " iface=" + ifaceName);
747                         }
748                         return;
749                     }
750                     onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName));
751                 }
752             });
753         }
754 
755         @Override
interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp)756         public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) {
757             // unused currently. Look at note above.
758         }
759     }
760 
761     /**
762      * Radio mode change handler for the Vendor HAL daemon.
763      */
764     private class VendorHalRadioModeChangeHandlerInternal
765             implements VendorHalRadioModeChangeEventHandler {
766         @Override
onMcc(int band)767         public void onMcc(int band) {
768             synchronized (mLock) {
769                 Log.i(TAG, "Device is in MCC mode now");
770                 mWifiMetrics.incrementNumRadioModeChangeToMcc();
771             }
772         }
773         @Override
onScc(int band)774         public void onScc(int band) {
775             synchronized (mLock) {
776                 Log.i(TAG, "Device is in SCC mode now");
777                 mWifiMetrics.incrementNumRadioModeChangeToScc();
778             }
779         }
780         @Override
onSbs(int band)781         public void onSbs(int band) {
782             synchronized (mLock) {
783                 Log.i(TAG, "Device is in SBS mode now");
784                 mWifiMetrics.incrementNumRadioModeChangeToSbs();
785             }
786         }
787         @Override
onDbs()788         public void onDbs() {
789             synchronized (mLock) {
790                 Log.i(TAG, "Device is in DBS mode now");
791                 mWifiMetrics.incrementNumRadioModeChangeToDbs();
792             }
793         }
794     }
795 
796     // For devices that don't support the vendor HAL, we will not support any concurrency.
797     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
798     // any active interface.
handleIfaceCreationWhenVendorHalNotSupported(@onNull Iface newIface)799     private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) {
800         synchronized (mLock) {
801             Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id);
802             if (existingIface != null) {
803                 onInterfaceDestroyed(existingIface);
804                 Log.i(TAG, "Successfully torn down " + existingIface);
805             }
806             // Return the interface name directly from the system property.
807             return mPropertyService.getString("wifi.interface", "wlan0");
808         }
809     }
810 
811     /**
812      * Helper function to handle creation of STA iface.
813      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
814      * teardown any existing iface.
815      */
createStaIface(@onNull Iface iface)816     private String createStaIface(@NonNull Iface iface) {
817         synchronized (mLock) {
818             if (mWifiVendorHal.isVendorHalSupported()) {
819                 return mWifiVendorHal.createStaIface(
820                         new InterfaceDestoyedListenerInternal(iface.id));
821             } else {
822                 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
823                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
824             }
825         }
826     }
827 
828     /**
829      * Helper function to handle creation of AP iface.
830      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
831      * teardown any existing iface.
832      */
createApIface(@onNull Iface iface)833     private String createApIface(@NonNull Iface iface) {
834         synchronized (mLock) {
835             if (mWifiVendorHal.isVendorHalSupported()) {
836                 return mWifiVendorHal.createApIface(
837                         new InterfaceDestoyedListenerInternal(iface.id));
838             } else {
839                 Log.i(TAG, "Vendor Hal not supported, ignoring createApIface.");
840                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
841             }
842         }
843     }
844 
845     // For devices that don't support the vendor HAL, we will not support any concurrency.
846     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
847     // the interface.
handleIfaceRemovalWhenVendorHalNotSupported(@onNull Iface iface)848     private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) {
849         synchronized (mLock) {
850             mIfaceMgr.removeIface(iface.id);
851             onInterfaceDestroyed(iface);
852             Log.i(TAG, "Successfully torn down " + iface);
853             return true;
854         }
855     }
856 
857     /**
858      * Helper function to handle removal of STA iface.
859      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
860      * teardown any existing iface.
861      */
removeStaIface(@onNull Iface iface)862     private boolean removeStaIface(@NonNull Iface iface) {
863         synchronized (mLock) {
864             if (mWifiVendorHal.isVendorHalSupported()) {
865                 return mWifiVendorHal.removeStaIface(iface.name);
866             } else {
867                 Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface.");
868                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
869             }
870         }
871     }
872 
873     /**
874      * Helper function to handle removal of STA iface.
875      */
removeApIface(@onNull Iface iface)876     private boolean removeApIface(@NonNull Iface iface) {
877         synchronized (mLock) {
878             if (mWifiVendorHal.isVendorHalSupported()) {
879                 return mWifiVendorHal.removeApIface(iface.name);
880             } else {
881                 Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface.");
882                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
883             }
884         }
885     }
886 
887     /**
888      * Initialize the native modules.
889      *
890      * @return true on success, false otherwise.
891      */
initialize()892     public boolean initialize() {
893         synchronized (mLock) {
894             if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) {
895                 Log.e(TAG, "Failed to initialize vendor HAL");
896                 return false;
897             }
898             mWifiCondManager.setOnServiceDeadCallback(new WificondDeathHandlerInternal());
899             mWifiCondManager.tearDownInterfaces();
900             mWifiVendorHal.registerRadioModeChangeHandler(
901                     new VendorHalRadioModeChangeHandlerInternal());
902             mNetdWrapper = mWifiInjector.makeNetdWrapper();
903             return true;
904         }
905     }
906 
907     /**
908      * Callback to notify when the status of one of the native daemons
909      * (wificond, wpa_supplicant & vendor HAL) changes.
910      */
911     public interface StatusListener {
912         /**
913          * @param allReady Indicates if all the native daemons are ready for operation or not.
914          */
onStatusChanged(boolean allReady)915         void onStatusChanged(boolean allReady);
916     }
917 
918     /**
919      * Register a StatusListener to get notified about any status changes from the native daemons.
920      *
921      * It is safe to re-register the same callback object - duplicates are detected and only a
922      * single copy kept.
923      *
924      * @param listener StatusListener listener object.
925      */
registerStatusListener(@onNull StatusListener listener)926     public void registerStatusListener(@NonNull StatusListener listener) {
927         mStatusListeners.add(listener);
928     }
929 
930     /**
931      * Callback to notify when the availability of an interface has changed.
932      */
933     public interface InterfaceAvailableForRequestListener {
934         /**
935          * @param isAvailable Whether it is possible to create an iface of the specified type or
936          *                    not.
937          */
onAvailabilityChanged(boolean isAvailable)938         void onAvailabilityChanged(boolean isAvailable);
939     }
940 
941     /**
942      * Register a callback to notify when the availability of Client interface has changed.
943      *
944      * It is safe to re-register the same callback object - duplicates are detected and only a
945      * single copy kept.
946      *
947      * @param listener Instance of {@link InterfaceAvailableForRequestListener}.
948      */
registerClientInterfaceAvailabilityListener( @onNull InterfaceAvailableForRequestListener listener)949     public void registerClientInterfaceAvailabilityListener(
950             @NonNull InterfaceAvailableForRequestListener listener) {
951         mWifiVendorHal.registerStaIfaceAvailabilityListener(listener);
952     }
953 
954     /**
955      * Register a callback to notify when the availability of SoftAp interface has changed.
956      *
957      * It is safe to re-register the same callback object - duplicates are detected and only a
958      * single copy kept.
959      *
960      * @param listener Instance of {@link InterfaceAvailableForRequestListener}.
961      */
registerSoftApInterfaceAvailabilityListener( @onNull InterfaceAvailableForRequestListener listener)962     public void registerSoftApInterfaceAvailabilityListener(
963             @NonNull InterfaceAvailableForRequestListener listener) {
964         mWifiVendorHal.registerApIfaceAvailabilityListener(listener);
965     }
966 
967     /**
968      * Callback to notify when the associated interface is destroyed, up or down.
969      */
970     public interface InterfaceCallback {
971         /**
972          * Interface destroyed by HalDeviceManager.
973          *
974          * @param ifaceName Name of the iface.
975          */
onDestroyed(String ifaceName)976         void onDestroyed(String ifaceName);
977 
978         /**
979          * Interface is up.
980          *
981          * @param ifaceName Name of the iface.
982          */
onUp(String ifaceName)983         void onUp(String ifaceName);
984 
985         /**
986          * Interface is down.
987          *
988          * @param ifaceName Name of the iface.
989          */
onDown(String ifaceName)990         void onDown(String ifaceName);
991     }
992 
initializeNwParamsForClientInterface(@onNull String ifaceName)993     private void initializeNwParamsForClientInterface(@NonNull String ifaceName) {
994         try {
995             // A runtime crash or shutting down AP mode can leave
996             // IP addresses configured, and this affects
997             // connectivity when supplicant starts up.
998             // Ensure we have no IP addresses before a supplicant start.
999             mNetdWrapper.clearInterfaceAddresses(ifaceName);
1000 
1001             // Set privacy extensions
1002             mNetdWrapper.setInterfaceIpv6PrivacyExtensions(ifaceName, true);
1003 
1004             // IPv6 is enabled only as long as access point is connected since:
1005             // - IPv6 addresses and routes stick around after disconnection
1006             // - kernel is unaware when connected and fails to start IPv6 negotiation
1007             // - kernel can start autoconfiguration when 802.1x is not complete
1008             mNetdWrapper.disableIpv6(ifaceName);
1009         } catch (IllegalStateException e) {
1010             Log.e(TAG, "Unable to change interface settings", e);
1011         }
1012     }
1013 
1014     /**
1015      * Setup an interface for client mode (for connectivity) operations.
1016      *
1017      * This method configures an interface in STA mode in all the native daemons
1018      * (wificond, wpa_supplicant & vendor HAL).
1019      *
1020      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1021      * @return Returns the name of the allocated interface, will be null on failure.
1022      */
setupInterfaceForClientInConnectivityMode( @onNull InterfaceCallback interfaceCallback)1023     public String setupInterfaceForClientInConnectivityMode(
1024             @NonNull InterfaceCallback interfaceCallback) {
1025         synchronized (mLock) {
1026             if (!startHal()) {
1027                 Log.e(TAG, "Failed to start Hal");
1028                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1029                 return null;
1030             }
1031             if (!startSupplicant()) {
1032                 Log.e(TAG, "Failed to start supplicant");
1033                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1034                 return null;
1035             }
1036             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
1037             if (iface == null) {
1038                 Log.e(TAG, "Failed to allocate new STA iface");
1039                 return null;
1040             }
1041             iface.externalListener = interfaceCallback;
1042             iface.name = createStaIface(iface);
1043             if (TextUtils.isEmpty(iface.name)) {
1044                 Log.e(TAG, "Failed to create STA iface in vendor HAL");
1045                 mIfaceMgr.removeIface(iface.id);
1046                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1047                 return null;
1048             }
1049             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1050                     new NormalScanEventCallback(iface.name),
1051                     new PnoScanEventCallback(iface.name))) {
1052                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1053                 teardownInterface(iface.name);
1054                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1055                 return null;
1056             }
1057             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1058                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1059                 teardownInterface(iface.name);
1060                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1061                 return null;
1062             }
1063             iface.networkObserver = new NetworkObserverInternal(iface.id);
1064             if (!registerNetworkObserver(iface.networkObserver)) {
1065                 Log.e(TAG, "Failed to register network observer on " + iface);
1066                 teardownInterface(iface.name);
1067                 return null;
1068             }
1069             mWifiMonitor.startMonitoring(iface.name);
1070             // Just to avoid any race conditions with interface state change callbacks,
1071             // update the interface state before we exit.
1072             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1073             initializeNwParamsForClientInterface(iface.name);
1074             Log.i(TAG, "Successfully setup " + iface);
1075 
1076             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1077             return iface.name;
1078         }
1079     }
1080 
1081     /**
1082      * Setup an interface for client mode (for scan) operations.
1083      *
1084      * This method configures an interface in STA mode in the native daemons
1085      * (wificond, vendor HAL).
1086      *
1087      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1088      * @return Returns the name of the allocated interface, will be null on failure.
1089      */
setupInterfaceForClientInScanMode( @onNull InterfaceCallback interfaceCallback)1090     public String setupInterfaceForClientInScanMode(
1091             @NonNull InterfaceCallback interfaceCallback) {
1092         synchronized (mLock) {
1093             if (!startHal()) {
1094                 Log.e(TAG, "Failed to start Hal");
1095                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1096                 return null;
1097             }
1098             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
1099             if (iface == null) {
1100                 Log.e(TAG, "Failed to allocate new STA iface");
1101                 return null;
1102             }
1103             iface.externalListener = interfaceCallback;
1104             iface.name = createStaIface(iface);
1105             if (TextUtils.isEmpty(iface.name)) {
1106                 Log.e(TAG, "Failed to create iface in vendor HAL");
1107                 mIfaceMgr.removeIface(iface.id);
1108                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1109                 return null;
1110             }
1111             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1112                     new NormalScanEventCallback(iface.name),
1113                     new PnoScanEventCallback(iface.name))) {
1114                 Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
1115                 teardownInterface(iface.name);
1116                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1117                 return null;
1118             }
1119             iface.networkObserver = new NetworkObserverInternal(iface.id);
1120             if (!registerNetworkObserver(iface.networkObserver)) {
1121                 Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
1122                 teardownInterface(iface.name);
1123                 return null;
1124             }
1125             mWifiMonitor.startMonitoring(iface.name);
1126             // Just to avoid any race conditions with interface state change callbacks,
1127             // update the interface state before we exit.
1128             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1129             Log.i(TAG, "Successfully setup " + iface);
1130 
1131             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1132             return iface.name;
1133         }
1134     }
1135 
1136     /**
1137      * Setup an interface for Soft AP mode operations.
1138      *
1139      * This method configures an interface in AP mode in all the native daemons
1140      * (wificond, wpa_supplicant & vendor HAL).
1141      *
1142      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1143      * @return Returns the name of the allocated interface, will be null on failure.
1144      */
setupInterfaceForSoftApMode(@onNull InterfaceCallback interfaceCallback)1145     public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
1146         synchronized (mLock) {
1147             if (!startHal()) {
1148                 Log.e(TAG, "Failed to start Hal");
1149                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1150                 return null;
1151             }
1152             if (!startHostapd()) {
1153                 Log.e(TAG, "Failed to start hostapd");
1154                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1155                 return null;
1156             }
1157             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
1158             if (iface == null) {
1159                 Log.e(TAG, "Failed to allocate new AP iface");
1160                 return null;
1161             }
1162             iface.externalListener = interfaceCallback;
1163             iface.name = createApIface(iface);
1164             if (TextUtils.isEmpty(iface.name)) {
1165                 Log.e(TAG, "Failed to create AP iface in vendor HAL");
1166                 mIfaceMgr.removeIface(iface.id);
1167                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1168                 return null;
1169             }
1170             if (!mWifiCondManager.setupInterfaceForSoftApMode(iface.name)) {
1171                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1172                 teardownInterface(iface.name);
1173                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
1174                 return null;
1175             }
1176             iface.networkObserver = new NetworkObserverInternal(iface.id);
1177             if (!registerNetworkObserver(iface.networkObserver)) {
1178                 Log.e(TAG, "Failed to register network observer on " + iface);
1179                 teardownInterface(iface.name);
1180                 return null;
1181             }
1182             // Just to avoid any race conditions with interface state change callbacks,
1183             // update the interface state before we exit.
1184             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1185             Log.i(TAG, "Successfully setup " + iface);
1186 
1187             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1188             return iface.name;
1189         }
1190     }
1191 
1192     /**
1193      * Switches an existing Client mode interface from connectivity
1194      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY} to scan mode
1195      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN}.
1196      *
1197      * @param ifaceName Name of the interface.
1198      * @return true if the operation succeeded, false if there is an error or the iface is already
1199      * in scan mode.
1200      */
switchClientInterfaceToScanMode(@onNull String ifaceName)1201     public boolean switchClientInterfaceToScanMode(@NonNull String ifaceName) {
1202         synchronized (mLock) {
1203             final Iface iface = mIfaceMgr.getIface(ifaceName);
1204             if (iface == null) {
1205                 Log.e(TAG, "Trying to switch to scan mode on an invalid iface=" + ifaceName);
1206                 return false;
1207             }
1208             if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1209                 Log.e(TAG, "Already in scan mode on iface=" + ifaceName);
1210                 return true;
1211             }
1212             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
1213                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
1214                 teardownInterface(iface.name);
1215                 return false;
1216             }
1217             iface.type = Iface.IFACE_TYPE_STA_FOR_SCAN;
1218             stopSupplicantIfNecessary();
1219             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1220             iface.phyCapabilities = null;
1221             Log.i(TAG, "Successfully switched to scan mode on iface=" + iface);
1222             return true;
1223         }
1224     }
1225 
1226     /**
1227      * Switches an existing Client mode interface from scan mode
1228      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode
1229      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}.
1230      *
1231      * @param ifaceName Name of the interface.
1232      * @return true if the operation succeeded, false if there is an error or the iface is already
1233      * in scan mode.
1234      */
switchClientInterfaceToConnectivityMode(@onNull String ifaceName)1235     public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName) {
1236         synchronized (mLock) {
1237             final Iface iface = mIfaceMgr.getIface(ifaceName);
1238             if (iface == null) {
1239                 Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface="
1240                         + ifaceName);
1241                 return false;
1242             }
1243             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
1244                 Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName);
1245                 return true;
1246             }
1247             if (!startSupplicant()) {
1248                 Log.e(TAG, "Failed to start supplicant");
1249                 teardownInterface(iface.name);
1250                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1251                 return false;
1252             }
1253             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1254                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1255                 teardownInterface(iface.name);
1256                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1257                 return false;
1258             }
1259             iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY;
1260             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1261             Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface);
1262             return true;
1263         }
1264     }
1265 
1266     /**
1267      *
1268      * Check if the interface is up or down.
1269      *
1270      * @param ifaceName Name of the interface.
1271      * @return true if iface is up, false if it's down or on error.
1272      */
isInterfaceUp(@onNull String ifaceName)1273     public boolean isInterfaceUp(@NonNull String ifaceName) {
1274         synchronized (mLock) {
1275             final Iface iface = mIfaceMgr.getIface(ifaceName);
1276             if (iface == null) {
1277                 Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName);
1278                 return false;
1279             }
1280             try {
1281                 return mNetdWrapper.isInterfaceUp(ifaceName);
1282             } catch (IllegalStateException e) {
1283                 Log.e(TAG, "Unable to get interface config", e);
1284                 return false;
1285             }
1286         }
1287     }
1288 
1289     /**
1290      * Teardown an interface in Client/AP mode.
1291      *
1292      * This method tears down the associated interface from all the native daemons
1293      * (wificond, wpa_supplicant & vendor HAL).
1294      * Also, brings down the HAL, supplicant or hostapd as necessary.
1295      *
1296      * @param ifaceName Name of the interface.
1297      */
teardownInterface(@onNull String ifaceName)1298     public void teardownInterface(@NonNull String ifaceName) {
1299         synchronized (mLock) {
1300             final Iface iface = mIfaceMgr.getIface(ifaceName);
1301             if (iface == null) {
1302                 Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName);
1303                 return;
1304             }
1305             // Trigger the iface removal from HAL. The rest of the cleanup will be triggered
1306             // from the interface destroyed callback.
1307             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
1308                     || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1309                 if (!removeStaIface(iface)) {
1310                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1311                     return;
1312                 }
1313             } else if (iface.type == Iface.IFACE_TYPE_AP) {
1314                 if (!removeApIface(iface)) {
1315                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1316                     return;
1317                 }
1318             }
1319             Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName);
1320         }
1321     }
1322 
1323     /**
1324      * Teardown all the active interfaces.
1325      *
1326      * This method tears down the associated interfaces from all the native daemons
1327      * (wificond, wpa_supplicant & vendor HAL).
1328      * Also, brings down the HAL, supplicant or hostapd as necessary.
1329      */
teardownAllInterfaces()1330     public void teardownAllInterfaces() {
1331         synchronized (mLock) {
1332             Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter();
1333             while (ifaceIdIter.hasNext()) {
1334                 Iface iface = mIfaceMgr.getIface(ifaceIdIter.next());
1335                 ifaceIdIter.remove();
1336                 onInterfaceDestroyed(iface);
1337                 Log.i(TAG, "Successfully torn down " + iface);
1338             }
1339             Log.i(TAG, "Successfully torn down all ifaces");
1340         }
1341     }
1342 
1343     /**
1344      * Get name of the client interface.
1345      *
1346      * This is mainly used by external modules that needs to perform some
1347      * client operations on the STA interface.
1348      *
1349      * TODO(b/70932231): This may need to be reworked once we start supporting STA + STA.
1350      *
1351      * @return Interface name of any active client interface, null if no active client interface
1352      * exist.
1353      * Return Values for the different scenarios are listed below:
1354      * a) When there are no client interfaces, returns null.
1355      * b) when there is 1 client interface, returns the name of that interface.
1356      * c) When there are 2 or more client interface, returns the name of any client interface.
1357      */
getClientInterfaceName()1358     public String getClientInterfaceName() {
1359         synchronized (mLock) {
1360             return mIfaceMgr.findAnyStaIfaceName();
1361         }
1362     }
1363 
1364     /**
1365      * Get names of all the client interfaces.
1366      *
1367      * @return List of interface name of all active client interfaces.
1368      */
getClientInterfaceNames()1369     public Set<String> getClientInterfaceNames() {
1370         synchronized (mLock) {
1371             return mIfaceMgr.findAllStaIfaceNames();
1372         }
1373     }
1374 
1375     /**
1376      * Get name of the softap interface.
1377      *
1378      * This is mainly used by external modules that needs to perform some
1379      * operations on the AP interface.
1380      *
1381      * TODO(b/70932231): This may need to be reworked once we start supporting AP + AP.
1382      *
1383      * @return Interface name of any active softap interface, null if no active softap interface
1384      * exist.
1385      * Return Values for the different scenarios are listed below:
1386      * a) When there are no softap interfaces, returns null.
1387      * b) when there is 1 softap interface, returns the name of that interface.
1388      * c) When there are 2 or more softap interface, returns the name of any softap interface.
1389      */
getSoftApInterfaceName()1390     public String getSoftApInterfaceName() {
1391         synchronized (mLock) {
1392             return mIfaceMgr.findAnyApIfaceName();
1393         }
1394     }
1395 
1396     /********************************************************
1397      * Wificond operations
1398      ********************************************************/
1399 
1400     /**
1401      * Request signal polling to wificond.
1402      *
1403      * @param ifaceName Name of the interface.
1404      * Returns an SignalPollResult object.
1405      * Returns null on failure.
1406      */
signalPoll(@onNull String ifaceName)1407     public WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String ifaceName) {
1408         return mWifiCondManager.signalPoll(ifaceName);
1409     }
1410 
1411     /**
1412      * Query the list of valid frequencies for the provided band.
1413      * The result depends on the on the country code that has been set.
1414      *
1415      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1416      * The following bands are supported {@link WifiAnnotations.WifiBandBasic}:
1417      * WifiScanner.WIFI_BAND_24_GHZ
1418      * WifiScanner.WIFI_BAND_5_GHZ
1419      * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
1420      * WifiScanner.WIFI_BAND_6_GHZ
1421      * @return frequencies vector of valid frequencies (MHz), or null for error.
1422      * @throws IllegalArgumentException if band is not recognized.
1423      */
getChannelsForBand(@ifiAnnotations.WifiBandBasic int band)1424     public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) {
1425         return mWifiCondManager.getChannelsMhzForBand(band);
1426     }
1427 
1428     /**
1429      * Start a scan using wificond for the given parameters.
1430      * @param ifaceName Name of the interface.
1431      * @param scanType Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
1432      * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
1433      * @param freqs list of frequencies to scan for, if null scan all supported channels.
1434      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
1435      * @return Returns true on success.
1436      */
scan( @onNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs)1437     public boolean scan(
1438             @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,
1439             List<String> hiddenNetworkSSIDs) {
1440         List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();
1441         for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {
1442             try {
1443                 hiddenNetworkSsidsArrays.add(
1444                         NativeUtil.byteArrayFromArrayList(
1445                                 NativeUtil.decodeSsid(hiddenNetworkSsid)));
1446             } catch (IllegalArgumentException e) {
1447                 Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);
1448                 continue;
1449             }
1450         }
1451         return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays);
1452     }
1453 
1454     /**
1455      * Fetch the latest scan result from kernel via wificond.
1456      * @param ifaceName Name of the interface.
1457      * @return Returns an ArrayList of ScanDetail.
1458      * Returns an empty ArrayList on failure.
1459      */
getScanResults(@onNull String ifaceName)1460     public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
1461         return convertNativeScanResults(mWifiCondManager.getScanResults(
1462                 ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN));
1463     }
1464 
1465     /**
1466      * Fetch the latest scan result from kernel via wificond.
1467      * @param ifaceName Name of the interface.
1468      * @return Returns an ArrayList of ScanDetail.
1469      * Returns an empty ArrayList on failure.
1470      */
getPnoScanResults(@onNull String ifaceName)1471     public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) {
1472         return convertNativeScanResults(mWifiCondManager.getScanResults(ifaceName,
1473                 WifiNl80211Manager.SCAN_TYPE_PNO_SCAN));
1474     }
1475 
convertNativeScanResults(List<NativeScanResult> nativeResults)1476     private ArrayList<ScanDetail> convertNativeScanResults(List<NativeScanResult> nativeResults) {
1477         ArrayList<ScanDetail> results = new ArrayList<>();
1478         for (NativeScanResult result : nativeResults) {
1479             WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.getSsid());
1480             MacAddress bssidMac = result.getBssid();
1481             if (bssidMac == null) {
1482                 Log.e(TAG, "Invalid MAC (BSSID) for SSID " + wifiSsid);
1483                 continue;
1484             }
1485             String bssid = bssidMac.toString();
1486             ScanResult.InformationElement[] ies =
1487                     InformationElementUtil.parseInformationElements(result.getInformationElements());
1488             InformationElementUtil.Capabilities capabilities =
1489                     new InformationElementUtil.Capabilities();
1490             capabilities.from(ies, result.getCapabilities(), isEnhancedOpenSupported());
1491             String flags = capabilities.generateCapabilitiesString();
1492             NetworkDetail networkDetail;
1493             try {
1494                 networkDetail = new NetworkDetail(bssid, ies, null, result.getFrequencyMhz());
1495             } catch (IllegalArgumentException e) {
1496                 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
1497                 continue;
1498             }
1499 
1500             ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
1501                     result.getSignalMbm() / 100, result.getFrequencyMhz(), result.getTsf(), ies,
1502                     null, result.getInformationElements());
1503             ScanResult scanResult = scanDetail.getScanResult();
1504             scanResult.setWifiStandard(wifiModeToWifiStandard(networkDetail.getWifiMode()));
1505 
1506             // Fill up the radio chain info.
1507             scanResult.radioChainInfos =
1508                     new ScanResult.RadioChainInfo[result.getRadioChainInfos().size()];
1509             int idx = 0;
1510             for (RadioChainInfo nativeRadioChainInfo : result.getRadioChainInfos()) {
1511                 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
1512                 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.getChainId();
1513                 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.getLevelDbm();
1514                 idx++;
1515             }
1516             results.add(scanDetail);
1517         }
1518         if (mVerboseLoggingEnabled) {
1519             Log.d(TAG, "get " + results.size() + " scan results from wificond");
1520         }
1521 
1522         return results;
1523     }
1524 
1525     @WifiAnnotations.WifiStandard
wifiModeToWifiStandard(int wifiMode)1526     private static int wifiModeToWifiStandard(int wifiMode) {
1527         switch (wifiMode) {
1528             case InformationElementUtil.WifiMode.MODE_11A:
1529             case InformationElementUtil.WifiMode.MODE_11B:
1530             case InformationElementUtil.WifiMode.MODE_11G:
1531                 return ScanResult.WIFI_STANDARD_LEGACY;
1532             case InformationElementUtil.WifiMode.MODE_11N:
1533                 return ScanResult.WIFI_STANDARD_11N;
1534             case InformationElementUtil.WifiMode.MODE_11AC:
1535                 return ScanResult.WIFI_STANDARD_11AC;
1536             case InformationElementUtil.WifiMode.MODE_11AX:
1537                 return ScanResult.WIFI_STANDARD_11AX;
1538             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
1539             default:
1540                 return ScanResult.WIFI_STANDARD_UNKNOWN;
1541         }
1542     }
1543 
1544     private boolean mIsEnhancedOpenSupportedInitialized = false;
1545     private boolean mIsEnhancedOpenSupported;
1546 
1547     /**
1548      * Check if OWE (Enhanced Open) is supported on the device
1549      *
1550      * @return true if OWE is supported
1551      */
isEnhancedOpenSupported()1552     private boolean isEnhancedOpenSupported() {
1553         if (mIsEnhancedOpenSupportedInitialized) {
1554             return mIsEnhancedOpenSupported;
1555         }
1556 
1557         String iface = getClientInterfaceName();
1558         if (iface == null) {
1559             // Client interface might not be initialized during boot or Wi-Fi off
1560             return false;
1561         }
1562 
1563         mIsEnhancedOpenSupportedInitialized = true;
1564         mIsEnhancedOpenSupported = (getSupportedFeatureSet(iface) & WIFI_FEATURE_OWE) != 0;
1565         return mIsEnhancedOpenSupported;
1566     }
1567 
1568     /**
1569      * Start PNO scan.
1570      * @param ifaceName Name of the interface.
1571      * @param pnoSettings Pno scan configuration.
1572      * @return true on success.
1573      */
startPnoScan(@onNull String ifaceName, PnoSettings pnoSettings)1574     public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) {
1575         return mWifiCondManager.startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(),
1576                 Runnable::run,
1577                 new WifiNl80211Manager.PnoScanRequestCallback() {
1578                     @Override
1579                     public void onPnoRequestSucceeded() {
1580                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1581                     }
1582 
1583                     @Override
1584                     public void onPnoRequestFailed() {
1585                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1586                         mWifiMetrics.incrementPnoScanFailedCount();
1587                     }
1588                 });
1589     }
1590 
1591     /**
1592      * Stop PNO scan.
1593      * @param ifaceName Name of the interface.
1594      * @return true on success.
1595      */
1596     public boolean stopPnoScan(@NonNull String ifaceName) {
1597         return mWifiCondManager.stopPnoScan(ifaceName);
1598     }
1599 
1600     /**
1601      * Sends an arbitrary 802.11 management frame on the current channel.
1602      *
1603      * @param ifaceName Name of the interface.
1604      * @param frame Bytes of the 802.11 management frame to be sent, including the header, but not
1605      *              including the frame check sequence (FCS).
1606      * @param callback A callback triggered when the transmitted frame is ACKed or the transmission
1607      *                 fails.
1608      * @param mcs The MCS index that the frame will be sent at. If mcs < 0, the driver will select
1609      *            the rate automatically. If the device does not support sending the frame at a
1610      *            specified MCS rate, the transmission will be aborted and
1611      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1612      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1613      */
1614     public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
1615             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1616         mWifiCondManager.sendMgmtFrame(ifaceName, frame, mcs, Runnable::run, callback);
1617     }
1618 
1619     /**
1620      * Sends a probe request to the AP and waits for a response in order to determine whether
1621      * there is connectivity between the device and AP.
1622      *
1623      * @param ifaceName Name of the interface.
1624      * @param receiverMac the MAC address of the AP that the probe request will be sent to.
1625      * @param callback callback triggered when the probe was ACKed by the AP, or when
1626      *                an error occurs after the link probe was started.
1627      * @param mcs The MCS index that this probe will be sent at. If mcs < 0, the driver will select
1628      *            the rate automatically. If the device does not support sending the frame at a
1629      *            specified MCS rate, the transmission will be aborted and
1630      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1631      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1632      */
1633     public void probeLink(@NonNull String ifaceName, @NonNull MacAddress receiverMac,
1634             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1635         if (callback == null) {
1636             Log.e(TAG, "callback cannot be null!");
1637             return;
1638         }
1639 
1640         if (receiverMac == null) {
1641             Log.e(TAG, "Receiver MAC address cannot be null!");
1642             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1643             return;
1644         }
1645 
1646         String senderMacStr = getMacAddress(ifaceName);
1647         if (senderMacStr == null) {
1648             Log.e(TAG, "Failed to get this device's MAC Address");
1649             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1650             return;
1651         }
1652 
1653         byte[] frame = buildProbeRequestFrame(
1654                 receiverMac.toByteArray(),
1655                 NativeUtil.macAddressToByteArray(senderMacStr));
1656         sendMgmtFrame(ifaceName, frame, callback, mcs);
1657     }
1658 
1659     // header = 24 bytes, minimal body = 2 bytes, no FCS (will be added by driver)
1660     private static final int BASIC_PROBE_REQUEST_FRAME_SIZE = 24 + 2;
1661 
1662     private byte[] buildProbeRequestFrame(byte[] receiverMac, byte[] transmitterMac) {
1663         ByteBuffer frame = ByteBuffer.allocate(BASIC_PROBE_REQUEST_FRAME_SIZE);
1664         // ByteBuffer is big endian by default, switch to little endian
1665         frame.order(ByteOrder.LITTLE_ENDIAN);
1666 
1667         // Protocol version = 0, Type = management, Subtype = Probe Request
1668         frame.put((byte) 0x40);
1669 
1670         // no flags set
1671         frame.put((byte) 0x00);
1672 
1673         // duration = 60 microseconds. Note: this is little endian
1674         // Note: driver should calculate the duration and replace it before sending, putting a
1675         // reasonable default value here just in case.
1676         frame.putShort((short) 0x3c);
1677 
1678         // receiver/destination MAC address byte array
1679         frame.put(receiverMac);
1680         // sender MAC address byte array
1681         frame.put(transmitterMac);
1682         // BSSID (same as receiver address since we are sending to the AP)
1683         frame.put(receiverMac);
1684 
1685         // Generate random sequence number, fragment number = 0
1686         // Note: driver should replace the sequence number with the correct number that is
1687         // incremented from the last used sequence number. Putting a random sequence number as a
1688         // default here just in case.
1689         // bit 0 is least significant bit, bit 15 is most significant bit
1690         // bits [0, 7] go in byte 0
1691         // bits [8, 15] go in byte 1
1692         // bits [0, 3] represent the fragment number (which is 0)
1693         // bits [4, 15] represent the sequence number (which is random)
1694         // clear bits [0, 3] to set fragment number = 0
1695         short sequenceAndFragmentNumber = (short) (mRandom.nextInt() & 0xfff0);
1696         frame.putShort(sequenceAndFragmentNumber);
1697 
1698         // NL80211 rejects frames with an empty body, so we just need to put a placeholder
1699         // information element.
1700         // Tag for SSID
1701         frame.put((byte) 0x00);
1702         // Represents broadcast SSID. Not accurate, but works as placeholder.
1703         frame.put((byte) 0x00);
1704 
1705         return frame.array();
1706     }
1707 
1708     private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100;
1709     private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50;
1710     /**
1711      * This method is called to wait for establishing connection to hostapd.
1712      *
1713      * @return true if connection is established, false otherwise.
1714      */
1715     private boolean startAndWaitForHostapdConnection() {
1716         // Start initialization if not already started.
1717         if (!mHostapdHal.isInitializationStarted()
1718                 && !mHostapdHal.initialize()) {
1719             return false;
1720         }
1721         if (!mHostapdHal.startDaemon()) {
1722             Log.e(TAG, "Failed to startup hostapd");
1723             return false;
1724         }
1725         boolean connected = false;
1726         int connectTries = 0;
1727         while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) {
1728             // Check if the initialization is complete.
1729             connected = mHostapdHal.isInitializationComplete();
1730             if (connected) {
1731                 break;
1732             }
1733             try {
1734                 Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS);
1735             } catch (InterruptedException ignore) {
1736             }
1737         }
1738         return connected;
1739     }
1740 
1741     /**
1742      * Start Soft AP operation using the provided configuration.
1743      *
1744      * @param ifaceName Name of the interface.
1745      * @param config Configuration to use for the soft ap created.
1746      * @param listener Callback for AP events.
1747      * @return true on success, false otherwise.
1748      */
1749     public boolean startSoftAp(
1750             @NonNull String ifaceName, SoftApConfiguration config, SoftApListener listener) {
1751         if (!mWifiCondManager.registerApCallback(ifaceName, Runnable::run, listener)) {
1752             Log.e(TAG, "Failed to register ap listener");
1753             return false;
1754         }
1755         if (!mHostapdHal.addAccessPoint(ifaceName, config, listener::onFailure)) {
1756             Log.e(TAG, "Failed to add acccess point");
1757             mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1758             return false;
1759         }
1760         return true;
1761     }
1762 
1763     /**
1764      * Force a softap client disconnect with specific reason code.
1765      *
1766      * @param ifaceName Name of the interface.
1767      * @param client Mac address to force disconnect in clients of the SoftAp.
1768      * @param reasonCode One of disconnect reason code which defined in {@link ApConfigUtil}.
1769      * @return true on success, false otherwise.
1770      */
1771     public boolean forceClientDisconnect(@NonNull String ifaceName,
1772             @NonNull MacAddress client, int reasonCode) {
1773         return mHostapdHal.forceClientDisconnect(ifaceName, client, reasonCode);
1774     }
1775 
1776     /**
1777      * Set MAC address of the given interface
1778      * @param interfaceName Name of the interface
1779      * @param mac Mac address to change into
1780      * @return true on success
1781      */
1782     public boolean setMacAddress(String interfaceName, MacAddress mac) {
1783         // TODO(b/72459123): Suppress interface down/up events from this call
1784         // Trigger an explicit disconnect to avoid losing the disconnect event reason (if currently
1785         // connected) from supplicant if the interface is brought down for MAC address change.
1786         disconnect(interfaceName);
1787         return mWifiVendorHal.setMacAddress(interfaceName, mac);
1788     }
1789 
1790     /**
1791      * Returns true if Hal version supports setMacAddress, otherwise false.
1792      *
1793      * @param interfaceName Name of the interface
1794      */
1795     public boolean isSetMacAddressSupported(@NonNull String interfaceName) {
1796         return mWifiVendorHal.isSetMacAddressSupported(interfaceName);
1797     }
1798 
1799     /**
1800      * Get the factory MAC address of the given interface
1801      * @param interfaceName Name of the interface.
1802      * @return factory MAC address, or null on a failed call or if feature is unavailable.
1803      */
1804     public MacAddress getFactoryMacAddress(@NonNull String interfaceName) {
1805         return mWifiVendorHal.getFactoryMacAddress(interfaceName);
1806     }
1807 
1808     /********************************************************
1809      * Hostapd operations
1810      ********************************************************/
1811 
1812     /**
1813      * Callback to notify hostapd death.
1814      */
1815     public interface HostapdDeathEventHandler {
1816         /**
1817          * Invoked when the supplicant dies.
1818          */
1819         void onDeath();
1820     }
1821 
1822     /********************************************************
1823      * Supplicant operations
1824      ********************************************************/
1825 
1826     /**
1827      * Callback to notify supplicant death.
1828      */
1829     public interface SupplicantDeathEventHandler {
1830         /**
1831          * Invoked when the supplicant dies.
1832          */
1833         void onDeath();
1834     }
1835 
1836     /**
1837      * Set supplicant log level
1838      *
1839      * @param turnOnVerbose Whether to turn on verbose logging or not.
1840      */
1841     public void setSupplicantLogLevel(boolean turnOnVerbose) {
1842         mSupplicantStaIfaceHal.setLogLevel(turnOnVerbose);
1843     }
1844 
1845     /**
1846      * Trigger a reconnection if the iface is disconnected.
1847      *
1848      * @param ifaceName Name of the interface.
1849      * @return true if request is sent successfully, false otherwise.
1850      */
1851     public boolean reconnect(@NonNull String ifaceName) {
1852         return mSupplicantStaIfaceHal.reconnect(ifaceName);
1853     }
1854 
1855     /**
1856      * Trigger a reassociation even if the iface is currently connected.
1857      *
1858      * @param ifaceName Name of the interface.
1859      * @return true if request is sent successfully, false otherwise.
1860      */
1861     public boolean reassociate(@NonNull String ifaceName) {
1862         return mSupplicantStaIfaceHal.reassociate(ifaceName);
1863     }
1864 
1865     /**
1866      * Trigger a disconnection from the currently connected network.
1867      *
1868      * @param ifaceName Name of the interface.
1869      * @return true if request is sent successfully, false otherwise.
1870      */
1871     public boolean disconnect(@NonNull String ifaceName) {
1872         return mSupplicantStaIfaceHal.disconnect(ifaceName);
1873     }
1874 
1875     /**
1876      * Makes a callback to HIDL to getMacAddress from supplicant
1877      *
1878      * @param ifaceName Name of the interface.
1879      * @return string containing the MAC address, or null on a failed call
1880      */
1881     public String getMacAddress(@NonNull String ifaceName) {
1882         return mSupplicantStaIfaceHal.getMacAddress(ifaceName);
1883     }
1884 
1885     public static final int RX_FILTER_TYPE_V4_MULTICAST = 0;
1886     public static final int RX_FILTER_TYPE_V6_MULTICAST = 1;
1887     /**
1888      * Start filtering out Multicast V4 packets
1889      * @param ifaceName Name of the interface.
1890      * @return {@code true} if the operation succeeded, {@code false} otherwise
1891      *
1892      * Multicast filtering rules work as follows:
1893      *
1894      * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
1895      * a power optimized mode (typically when screen goes off).
1896      *
1897      * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
1898      * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
1899      *
1900      * DRIVER RXFILTER-ADD Num
1901      *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
1902      *
1903      * and DRIVER RXFILTER-START
1904      * In order to stop the usage of these rules, we do
1905      *
1906      * DRIVER RXFILTER-STOP
1907      * DRIVER RXFILTER-REMOVE Num
1908      *   where Num is as described for RXFILTER-ADD
1909      *
1910      * The  SETSUSPENDOPT driver command overrides the filtering rules
1911      */
1912     public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) {
1913         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1914                 && mSupplicantStaIfaceHal.removeRxFilter(
1915                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
1916                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1917     }
1918 
1919     /**
1920      * Stop filtering out Multicast V4 packets.
1921      * @param ifaceName Name of the interface.
1922      * @return {@code true} if the operation succeeded, {@code false} otherwise
1923      */
1924     public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) {
1925         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1926                 && mSupplicantStaIfaceHal.addRxFilter(
1927                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
1928                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1929     }
1930 
1931     /**
1932      * Start filtering out Multicast V6 packets
1933      * @param ifaceName Name of the interface.
1934      * @return {@code true} if the operation succeeded, {@code false} otherwise
1935      */
1936     public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) {
1937         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1938                 && mSupplicantStaIfaceHal.removeRxFilter(
1939                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
1940                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1941     }
1942 
1943     /**
1944      * Stop filtering out Multicast V6 packets.
1945      * @param ifaceName Name of the interface.
1946      * @return {@code true} if the operation succeeded, {@code false} otherwise
1947      */
1948     public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) {
1949         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
1950                 && mSupplicantStaIfaceHal.addRxFilter(
1951                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
1952                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
1953     }
1954 
1955     public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED  = 0;
1956     public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
1957     public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE    = 2;
1958     /**
1959      * Sets the bluetooth coexistence mode.
1960      *
1961      * @param ifaceName Name of the interface.
1962      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
1963      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
1964      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
1965      * @return Whether the mode was successfully set.
1966      */
1967     public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) {
1968         return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode);
1969     }
1970 
1971     /**
1972      * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
1973      * some of the low-level scan parameters used by the driver are changed to
1974      * reduce interference with A2DP streaming.
1975      *
1976      * @param ifaceName Name of the interface.
1977      * @param setCoexScanMode whether to enable or disable this mode
1978      * @return {@code true} if the command succeeded, {@code false} otherwise.
1979      */
1980     public boolean setBluetoothCoexistenceScanMode(
1981             @NonNull String ifaceName, boolean setCoexScanMode) {
1982         return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(
1983                 ifaceName, setCoexScanMode);
1984     }
1985 
1986     /**
1987      * Enable or disable suspend mode optimizations.
1988      *
1989      * @param ifaceName Name of the interface.
1990      * @param enabled true to enable, false otherwise.
1991      * @return true if request is sent successfully, false otherwise.
1992      */
1993     public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) {
1994         return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled);
1995     }
1996 
1997     /**
1998      * Set country code.
1999      *
2000      * @param ifaceName Name of the interface.
2001      * @param countryCode 2 byte ASCII string. For ex: US, CA.
2002      * @return true if request is sent successfully, false otherwise.
2003      */
2004     public boolean setCountryCode(@NonNull String ifaceName, String countryCode) {
2005         return mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode);
2006     }
2007 
2008     /**
2009      * Flush all previously configured HLPs.
2010      *
2011      * @return true if request is sent successfully, false otherwise.
2012      */
2013     public boolean flushAllHlp(@NonNull String ifaceName) {
2014         return mSupplicantStaIfaceHal.flushAllHlp(ifaceName);
2015     }
2016 
2017     /**
2018      * Set FILS HLP packet.
2019      *
2020      * @param dst Destination MAC address.
2021      * @param hlpPacket Hlp Packet data in hex.
2022      * @return true if request is sent successfully, false otherwise.
2023      */
2024     public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) {
2025         return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket);
2026     }
2027 
2028     /**
2029      * Initiate TDLS discover and setup or teardown with the specified peer.
2030      *
2031      * @param ifaceName Name of the interface.
2032      * @param macAddr MAC Address of the peer.
2033      * @param enable true to start discovery and setup, false to teardown.
2034      */
2035     public void startTdls(@NonNull String ifaceName, String macAddr, boolean enable) {
2036         if (enable) {
2037             mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr);
2038             mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr);
2039         } else {
2040             mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr);
2041         }
2042     }
2043 
2044     /**
2045      * Start WPS pin display operation with the specified peer.
2046      *
2047      * @param ifaceName Name of the interface.
2048      * @param bssid BSSID of the peer.
2049      * @return true if request is sent successfully, false otherwise.
2050      */
2051     public boolean startWpsPbc(@NonNull String ifaceName, String bssid) {
2052         return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid);
2053     }
2054 
2055     /**
2056      * Start WPS pin keypad operation with the specified pin.
2057      *
2058      * @param ifaceName Name of the interface.
2059      * @param pin Pin to be used.
2060      * @return true if request is sent successfully, false otherwise.
2061      */
2062     public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2063         return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin);
2064     }
2065 
2066     /**
2067      * Start WPS pin display operation with the specified peer.
2068      *
2069      * @param ifaceName Name of the interface.
2070      * @param bssid BSSID of the peer.
2071      * @return new pin generated on success, null otherwise.
2072      */
2073     public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) {
2074         return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid);
2075     }
2076 
2077     /**
2078      * Sets whether to use external sim for SIM/USIM processing.
2079      *
2080      * @param ifaceName Name of the interface.
2081      * @param external true to enable, false otherwise.
2082      * @return true if request is sent successfully, false otherwise.
2083      */
2084     public boolean setExternalSim(@NonNull String ifaceName, boolean external) {
2085         return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external);
2086     }
2087 
2088     /**
2089      * Sim auth response types.
2090      */
2091     public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH";
2092     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH";
2093     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS";
2094 
2095     /**
2096      * EAP-SIM Error Codes
2097      */
2098     public static final int EAP_SIM_NOT_SUBSCRIBED = 1031;
2099     public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385;
2100 
2101     /**
2102      * Send the sim auth response for the currently configured network.
2103      *
2104      * @param ifaceName Name of the interface.
2105      * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|.
2106      * @param response Response params.
2107      * @return true if succeeds, false otherwise.
2108      */
2109     public boolean simAuthResponse(
2110             @NonNull String ifaceName, String type, String response) {
2111         if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
2112             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(
2113                     ifaceName, response);
2114         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
2115             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(
2116                     ifaceName, response);
2117         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
2118             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(
2119                     ifaceName, response);
2120         } else {
2121             return false;
2122         }
2123     }
2124 
2125     /**
2126      * Send the eap sim gsm auth failure for the currently configured network.
2127      *
2128      * @param ifaceName Name of the interface.
2129      * @return true if succeeds, false otherwise.
2130      */
2131     public boolean simAuthFailedResponse(@NonNull String ifaceName) {
2132         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName);
2133     }
2134 
2135     /**
2136      * Send the eap sim umts auth failure for the currently configured network.
2137      *
2138      * @param ifaceName Name of the interface.
2139      * @return true if succeeds, false otherwise.
2140      */
2141     public boolean umtsAuthFailedResponse(@NonNull String ifaceName) {
2142         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName);
2143     }
2144 
2145     /**
2146      * Send the eap identity response for the currently configured network.
2147      *
2148      * @param ifaceName Name of the interface.
2149      * @param unencryptedResponse String to send.
2150      * @param encryptedResponse String to send.
2151      * @return true if succeeds, false otherwise.
2152      */
2153     public boolean simIdentityResponse(@NonNull String ifaceName, String unencryptedResponse,
2154                                        String encryptedResponse) {
2155         return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName,
2156                 unencryptedResponse, encryptedResponse);
2157     }
2158 
2159     /**
2160      * This get anonymous identity from supplicant and returns it as a string.
2161      *
2162      * @param ifaceName Name of the interface.
2163      * @return anonymous identity string if succeeds, null otherwise.
2164      */
2165     public String getEapAnonymousIdentity(@NonNull String ifaceName) {
2166         return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity(ifaceName);
2167     }
2168 
2169     /**
2170      * Start WPS pin registrar operation with the specified peer and pin.
2171      *
2172      * @param ifaceName Name of the interface.
2173      * @param bssid BSSID of the peer.
2174      * @param pin Pin to be used.
2175      * @return true if request is sent successfully, false otherwise.
2176      */
2177     public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) {
2178         return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin);
2179     }
2180 
2181     /**
2182      * Cancels any ongoing WPS requests.
2183      *
2184      * @param ifaceName Name of the interface.
2185      * @return true if request is sent successfully, false otherwise.
2186      */
2187     public boolean cancelWps(@NonNull String ifaceName) {
2188         return mSupplicantStaIfaceHal.cancelWps(ifaceName);
2189     }
2190 
2191     /**
2192      * Set WPS device name.
2193      *
2194      * @param ifaceName Name of the interface.
2195      * @param name String to be set.
2196      * @return true if request is sent successfully, false otherwise.
2197      */
2198     public boolean setDeviceName(@NonNull String ifaceName, String name) {
2199         return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name);
2200     }
2201 
2202     /**
2203      * Set WPS device type.
2204      *
2205      * @param ifaceName Name of the interface.
2206      * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
2207      * @return true if request is sent successfully, false otherwise.
2208      */
2209     public boolean setDeviceType(@NonNull String ifaceName, String type) {
2210         return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type);
2211     }
2212 
2213     /**
2214      * Set WPS config methods
2215      *
2216      * @param cfg List of config methods.
2217      * @return true if request is sent successfully, false otherwise.
2218      */
2219     public boolean setConfigMethods(@NonNull String ifaceName, String cfg) {
2220         return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg);
2221     }
2222 
2223     /**
2224      * Set WPS manufacturer.
2225      *
2226      * @param ifaceName Name of the interface.
2227      * @param value String to be set.
2228      * @return true if request is sent successfully, false otherwise.
2229      */
2230     public boolean setManufacturer(@NonNull String ifaceName, String value) {
2231         return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value);
2232     }
2233 
2234     /**
2235      * Set WPS model name.
2236      *
2237      * @param ifaceName Name of the interface.
2238      * @param value String to be set.
2239      * @return true if request is sent successfully, false otherwise.
2240      */
2241     public boolean setModelName(@NonNull String ifaceName, String value) {
2242         return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value);
2243     }
2244 
2245     /**
2246      * Set WPS model number.
2247      *
2248      * @param ifaceName Name of the interface.
2249      * @param value String to be set.
2250      * @return true if request is sent successfully, false otherwise.
2251      */
2252     public boolean setModelNumber(@NonNull String ifaceName, String value) {
2253         return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value);
2254     }
2255 
2256     /**
2257      * Set WPS serial number.
2258      *
2259      * @param ifaceName Name of the interface.
2260      * @param value String to be set.
2261      * @return true if request is sent successfully, false otherwise.
2262      */
2263     public boolean setSerialNumber(@NonNull String ifaceName, String value) {
2264         return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value);
2265     }
2266 
2267     /**
2268      * Enable or disable power save mode.
2269      *
2270      * @param ifaceName Name of the interface.
2271      * @param enabled true to enable, false to disable.
2272      */
2273     public void setPowerSave(@NonNull String ifaceName, boolean enabled) {
2274         mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled);
2275     }
2276 
2277     /**
2278      * Enable or disable low latency mode.
2279      *
2280      * @param enabled true to enable, false to disable.
2281      * @return true on success, false on failure
2282      */
2283     public boolean setLowLatencyMode(boolean enabled) {
2284         return mWifiVendorHal.setLowLatencyMode(enabled);
2285     }
2286 
2287     /**
2288      * Set concurrency priority between P2P & STA operations.
2289      *
2290      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2291      *                            false otherwise.
2292      * @return true if request is sent successfully, false otherwise.
2293      */
2294     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2295         return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority);
2296     }
2297 
2298     /**
2299      * Enable/Disable auto reconnect functionality in wpa_supplicant.
2300      *
2301      * @param ifaceName Name of the interface.
2302      * @param enable true to enable auto reconnecting, false to disable.
2303      * @return true if request is sent successfully, false otherwise.
2304      */
2305     public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) {
2306         return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable);
2307     }
2308 
2309     /**
2310      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
2311      * This method does the following:
2312      * 1. Abort any ongoing scan to unblock the connection request.
2313      * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
2314      * 3. Add a new network to wpa_supplicant.
2315      * 4. Save the provided configuration to wpa_supplicant.
2316      * 5. Select the new network in wpa_supplicant.
2317      * 6. Triggers reconnect command to wpa_supplicant.
2318      *
2319      * @param ifaceName Name of the interface.
2320      * @param configuration WifiConfiguration parameters for the provided network.
2321      * @return {@code true} if it succeeds, {@code false} otherwise
2322      */
2323     public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2324         // Abort ongoing scan before connect() to unblock connection request.
2325         mWifiCondManager.abortScan(ifaceName);
2326         return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
2327     }
2328 
2329     /**
2330      * Initiates roaming to the already configured network in wpa_supplicant. If the network
2331      * configuration provided does not match the already configured network, then this triggers
2332      * a new connection attempt (instead of roam).
2333      * 1. Abort any ongoing scan to unblock the roam request.
2334      * 2. First check if we're attempting to connect to the same network as we currently have
2335      * configured.
2336      * 3. Set the new bssid for the network in wpa_supplicant.
2337      * 4. Triggers reassociate command to wpa_supplicant.
2338      *
2339      * @param ifaceName Name of the interface.
2340      * @param configuration WifiConfiguration parameters for the provided network.
2341      * @return {@code true} if it succeeds, {@code false} otherwise
2342      */
2343     public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2344         // Abort ongoing scan before connect() to unblock roaming request.
2345         mWifiCondManager.abortScan(ifaceName);
2346         return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration);
2347     }
2348 
2349     /**
2350      * Remove all the networks.
2351      *
2352      * @param ifaceName Name of the interface.
2353      * @return {@code true} if it succeeds, {@code false} otherwise
2354      */
2355     public boolean removeAllNetworks(@NonNull String ifaceName) {
2356         return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName);
2357     }
2358 
2359     /**
2360      * Set the BSSID for the currently configured network in wpa_supplicant.
2361      *
2362      * @param ifaceName Name of the interface.
2363      * @return true if successful, false otherwise.
2364      */
2365     public boolean setConfiguredNetworkBSSID(@NonNull String ifaceName, String bssid) {
2366         return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid);
2367     }
2368 
2369     /**
2370      * Initiate ANQP query.
2371      *
2372      * @param ifaceName Name of the interface.
2373      * @param bssid BSSID of the AP to be queried
2374      * @param anqpIds Set of anqp IDs.
2375      * @param hs20Subtypes Set of HS20 subtypes.
2376      * @return true on success, false otherwise.
2377      */
2378     public boolean requestAnqp(
2379             @NonNull String ifaceName, String bssid, Set<Integer> anqpIds,
2380             Set<Integer> hs20Subtypes) {
2381         if (bssid == null || ((anqpIds == null || anqpIds.isEmpty())
2382                 && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) {
2383             Log.e(TAG, "Invalid arguments for ANQP request.");
2384             return false;
2385         }
2386         ArrayList<Short> anqpIdList = new ArrayList<>();
2387         for (Integer anqpId : anqpIds) {
2388             anqpIdList.add(anqpId.shortValue());
2389         }
2390         ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
2391         hs20SubtypeList.addAll(hs20Subtypes);
2392         return mSupplicantStaIfaceHal.initiateAnqpQuery(
2393                 ifaceName, bssid, anqpIdList, hs20SubtypeList);
2394     }
2395 
2396     /**
2397      * Request a passpoint icon file |filename| from the specified AP |bssid|.
2398      *
2399      * @param ifaceName Name of the interface.
2400      * @param bssid BSSID of the AP
2401      * @param fileName name of the icon file
2402      * @return true if request is sent successfully, false otherwise
2403      */
2404     public boolean requestIcon(@NonNull String ifaceName, String  bssid, String fileName) {
2405         if (bssid == null || fileName == null) {
2406             Log.e(TAG, "Invalid arguments for Icon request.");
2407             return false;
2408         }
2409         return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName);
2410     }
2411 
2412     /**
2413      * Get the currently configured network's WPS NFC token.
2414      *
2415      * @param ifaceName Name of the interface.
2416      * @return Hex string corresponding to the WPS NFC token.
2417      */
2418     public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
2419         return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName);
2420     }
2421 
2422     /**
2423      * Clean HAL cached data for |networkId|.
2424      *
2425      * @param networkId network id of the network to be removed from supplicant.
2426      */
2427     public void removeNetworkCachedData(int networkId) {
2428         mSupplicantStaIfaceHal.removeNetworkCachedData(networkId);
2429     }
2430 
2431     /** Clear HAL cached data for |networkId| if MAC address is changed.
2432      *
2433      * @param networkId network id of the network to be checked.
2434      * @param curMacAddress current MAC address
2435      */
2436     public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
2437         mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress);
2438     }
2439 
2440     /*
2441      * DPP
2442      */
2443 
2444     /**
2445      * Adds a DPP peer URI to the URI list.
2446      *
2447      * @param ifaceName Interface name
2448      * @param uri Bootstrap (URI) string (e.g. DPP:....)
2449      * @return ID, or -1 for failure
2450      */
2451     public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
2452         return mSupplicantStaIfaceHal.addDppPeerUri(ifaceName, uri);
2453     }
2454 
2455     /**
2456      * Removes a DPP URI to the URI list given an ID.
2457      *
2458      * @param ifaceName Interface name
2459      * @param bootstrapId Bootstrap (URI) ID
2460      * @return true when operation is successful, or false for failure
2461      */
2462     public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId)  {
2463         return mSupplicantStaIfaceHal.removeDppUri(ifaceName, bootstrapId);
2464     }
2465 
2466     /**
2467      * Stops/aborts DPP Initiator request
2468      *
2469      * @param ifaceName Interface name
2470      * @return true when operation is successful, or false for failure
2471      */
2472     public boolean stopDppInitiator(@NonNull String ifaceName)  {
2473         return mSupplicantStaIfaceHal.stopDppInitiator(ifaceName);
2474     }
2475 
2476     /**
2477      * Starts DPP Configurator-Initiator request
2478      *
2479      * @param ifaceName Interface name
2480      * @param peerBootstrapId Peer's bootstrap (URI) ID
2481      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2482      * @param ssid SSID of the selected network
2483      * @param password Password of the selected network, or
2484      * @param psk PSK of the selected network in hexadecimal representation
2485      * @param netRole The network role of the enrollee (STA or AP)
2486      * @param securityAkm Security AKM to use: PSK, SAE
2487      * @return true when operation is successful, or false for failure
2488      */
2489     public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
2490             int ownBootstrapId, @NonNull String ssid, String password, String psk,
2491             int netRole, int securityAkm)  {
2492         return mSupplicantStaIfaceHal.startDppConfiguratorInitiator(ifaceName, peerBootstrapId,
2493                 ownBootstrapId, ssid, password, psk, netRole, securityAkm);
2494     }
2495 
2496     /**
2497      * Starts DPP Enrollee-Initiator request
2498      *
2499      * @param ifaceName Interface name
2500      * @param peerBootstrapId Peer's bootstrap (URI) ID
2501      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2502      * @return true when operation is successful, or false for failure
2503      */
2504     public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
2505             int ownBootstrapId)  {
2506         return mSupplicantStaIfaceHal.startDppEnrolleeInitiator(ifaceName, peerBootstrapId,
2507                 ownBootstrapId);
2508     }
2509 
2510     /**
2511      * Callback to notify about DPP success, failure and progress events.
2512      */
2513     public interface DppEventCallback {
2514         /**
2515          * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
2516          * peer DPP configurator.
2517          *
2518          * @param newWifiConfiguration New Wi-Fi configuration received from the configurator
2519          */
2520         void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration);
2521 
2522         /**
2523          * DPP Success event.
2524          *
2525          * @param dppStatusCode Status code of the success event.
2526          */
2527         void onSuccess(int dppStatusCode);
2528 
2529         /**
2530          * DPP Progress event.
2531          *
2532          * @param dppStatusCode Status code of the progress event.
2533          */
2534         void onProgress(int dppStatusCode);
2535 
2536         /**
2537          * DPP Failure event.
2538          *
2539          * @param dppStatusCode Status code of the failure event.
2540          * @param ssid SSID of the network the Enrollee tried to connect to.
2541          * @param channelList List of channels the Enrollee scanned for the network.
2542          * @param bandList List of bands the Enrollee supports.
2543          */
2544         void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList);
2545     }
2546 
2547     /**
2548      * Registers DPP event callbacks.
2549      *
2550      * @param dppEventCallback Callback object.
2551      */
2552     public void registerDppEventCallback(DppEventCallback dppEventCallback) {
2553         mSupplicantStaIfaceHal.registerDppCallback(dppEventCallback);
2554     }
2555 
2556     /********************************************************
2557      * Vendor HAL operations
2558      ********************************************************/
2559     /**
2560      * Callback to notify vendor HAL death.
2561      */
2562     public interface VendorHalDeathEventHandler {
2563         /**
2564          * Invoked when the vendor HAL dies.
2565          */
2566         void onDeath();
2567     }
2568 
2569     /**
2570      * Callback to notify when vendor HAL detects that a change in radio mode.
2571      */
2572     public interface VendorHalRadioModeChangeEventHandler {
2573         /**
2574          * Invoked when the vendor HAL detects a change to MCC mode.
2575          * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band,
2576          * different channels, same radios.
2577          *
2578          * @param band Band on which MCC is detected (specified by one of the
2579          *             WifiScanner.WIFI_BAND_* constants)
2580          */
2581         void onMcc(int band);
2582         /**
2583          * Invoked when the vendor HAL detects a change to SCC mode.
2584          * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same
2585          * channels, same radios.
2586          *
2587          * @param band Band on which SCC is detected (specified by one of the
2588          *             WifiScanner.WIFI_BAND_* constants)
2589          */
2590         void onScc(int band);
2591         /**
2592          * Invoked when the vendor HAL detects a change to SBS mode.
2593          * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band,
2594          * different channels, different radios.
2595          *
2596          * @param band Band on which SBS is detected (specified by one of the
2597          *             WifiScanner.WIFI_BAND_* constants)
2598          */
2599         void onSbs(int band);
2600         /**
2601          * Invoked when the vendor HAL detects a change to DBS mode.
2602          * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands,
2603          * different channels, different radios.
2604          */
2605         void onDbs();
2606     }
2607 
2608     /**
2609      * Tests whether the HAL is running or not
2610      */
2611     public boolean isHalStarted() {
2612         return mWifiVendorHal.isHalStarted();
2613     }
2614 
2615     // TODO: Change variable names to camel style.
2616     public static class ScanCapabilities {
2617         public int  max_scan_cache_size;
2618         public int  max_scan_buckets;
2619         public int  max_ap_cache_per_scan;
2620         public int  max_rssi_sample_size;
2621         public int  max_scan_reporting_threshold;
2622     }
2623 
2624     /**
2625      * Gets the scan capabilities
2626      *
2627      * @param ifaceName Name of the interface.
2628      * @param capabilities object to be filled in
2629      * @return true for success. false for failure
2630      */
2631     public boolean getBgScanCapabilities(
2632             @NonNull String ifaceName, ScanCapabilities capabilities) {
2633         return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities);
2634     }
2635 
2636     public static class ChannelSettings {
2637         public int frequency;
2638         public int dwell_time_ms;
2639         public boolean passive;
2640     }
2641 
2642     public static class BucketSettings {
2643         public int bucket;
2644         public int band;
2645         public int period_ms;
2646         public int max_period_ms;
2647         public int step_count;
2648         public int report_events;
2649         public int num_channels;
2650         public ChannelSettings[] channels;
2651     }
2652 
2653     /**
2654      * Network parameters for hidden networks to be scanned for.
2655      */
2656     public static class HiddenNetwork {
2657         public String ssid;
2658 
2659         @Override
2660         public boolean equals(Object otherObj) {
2661             if (this == otherObj) {
2662                 return true;
2663             } else if (otherObj == null || getClass() != otherObj.getClass()) {
2664                 return false;
2665             }
2666             HiddenNetwork other = (HiddenNetwork) otherObj;
2667             return Objects.equals(ssid, other.ssid);
2668         }
2669 
2670         @Override
2671         public int hashCode() {
2672             return Objects.hash(ssid);
2673         }
2674     }
2675 
2676     public static class ScanSettings {
2677         /**
2678          * Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
2679          * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
2680          */
2681         @WifiAnnotations.ScanType
2682         public int scanType;
2683         public int base_period_ms;
2684         public int max_ap_per_scan;
2685         public int report_threshold_percent;
2686         public int report_threshold_num_scans;
2687         public int num_buckets;
2688         /* Not used for bg scans. Only works for single scans. */
2689         public HiddenNetwork[] hiddenNetworks;
2690         public BucketSettings[] buckets;
2691     }
2692 
2693     /**
2694      * Network parameters to start PNO scan.
2695      */
2696     public static class PnoNetwork {
2697         public String ssid;
2698         public byte flags;
2699         public byte auth_bit_field;
2700         public int[] frequencies;
2701 
2702         @Override
2703         public boolean equals(Object otherObj) {
2704             if (this == otherObj) {
2705                 return true;
2706             } else if (otherObj == null || getClass() != otherObj.getClass()) {
2707                 return false;
2708             }
2709             PnoNetwork other = (PnoNetwork) otherObj;
2710             return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags)
2711                     && (auth_bit_field == other.auth_bit_field))
2712                     && Arrays.equals(frequencies, other.frequencies);
2713         }
2714 
2715         @Override
2716         public int hashCode() {
2717             return Objects.hash(ssid, flags, auth_bit_field, frequencies);
2718         }
2719 
2720         android.net.wifi.nl80211.PnoNetwork toNativePnoNetwork() {
2721             android.net.wifi.nl80211.PnoNetwork nativePnoNetwork =
2722                     new android.net.wifi.nl80211.PnoNetwork();
2723             nativePnoNetwork.setHidden(
2724                     (flags & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0);
2725             try {
2726                 nativePnoNetwork.setSsid(
2727                         NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)));
2728             } catch (IllegalArgumentException e) {
2729                 Log.e(TAG, "Illegal argument " + ssid, e);
2730                 return null;
2731             }
2732             nativePnoNetwork.setFrequenciesMhz(frequencies);
2733             return nativePnoNetwork;
2734         }
2735     }
2736 
2737     /**
2738      * Parameters to start PNO scan. This holds the list of networks which are going to used for
2739      * PNO scan.
2740      */
2741     public static class PnoSettings {
2742         public int min5GHzRssi;
2743         public int min24GHzRssi;
2744         public int min6GHzRssi;
2745         public int periodInMs;
2746         public boolean isConnected;
2747         public PnoNetwork[] networkList;
2748 
2749         android.net.wifi.nl80211.PnoSettings toNativePnoSettings() {
2750             android.net.wifi.nl80211.PnoSettings nativePnoSettings =
2751                     new android.net.wifi.nl80211.PnoSettings();
2752             nativePnoSettings.setIntervalMillis(periodInMs);
2753             nativePnoSettings.setMin2gRssiDbm(min24GHzRssi);
2754             nativePnoSettings.setMin5gRssiDbm(min5GHzRssi);
2755             nativePnoSettings.setMin6gRssiDbm(min6GHzRssi);
2756 
2757             List<android.net.wifi.nl80211.PnoNetwork> pnoNetworks = new ArrayList<>();
2758             if (networkList != null) {
2759                 for (PnoNetwork network : networkList) {
2760                     android.net.wifi.nl80211.PnoNetwork nativeNetwork =
2761                             network.toNativePnoNetwork();
2762                     if (nativeNetwork != null) {
2763                         pnoNetworks.add(nativeNetwork);
2764                     }
2765                 }
2766             }
2767             nativePnoSettings.setPnoNetworks(pnoNetworks);
2768             return nativePnoSettings;
2769         }
2770     }
2771 
2772     public static interface ScanEventHandler {
2773         /**
2774          * Called for each AP as it is found with the entire contents of the beacon/probe response.
2775          * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
2776          */
2777         void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
2778         /**
2779          * Callback on an event during a gscan scan.
2780          * See WifiNative.WIFI_SCAN_* for possible values.
2781          */
2782         void onScanStatus(int event);
2783         /**
2784          * Called with the current cached scan results when gscan is paused.
2785          */
2786         void onScanPaused(WifiScanner.ScanData[] data);
2787         /**
2788          * Called with the current cached scan results when gscan is resumed.
2789          */
2790         void onScanRestarted();
2791     }
2792 
2793     /**
2794      * Handler to notify the occurrence of various events during PNO scan.
2795      */
2796     public interface PnoEventHandler {
2797         /**
2798          * Callback to notify when one of the shortlisted networks is found during PNO scan.
2799          * @param results List of Scan results received.
2800          */
2801         void onPnoNetworkFound(ScanResult[] results);
2802 
2803         /**
2804          * Callback to notify when the PNO scan schedule fails.
2805          */
2806         void onPnoScanFailed();
2807     }
2808 
2809     public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
2810     public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
2811     public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
2812     public static final int WIFI_SCAN_FAILED = 3;
2813 
2814     /**
2815      * Starts a background scan.
2816      * Any ongoing scan will be stopped first
2817      *
2818      * @param ifaceName Name of the interface.
2819      * @param settings     to control the scan
2820      * @param eventHandler to call with the results
2821      * @return true for success
2822      */
2823     public boolean startBgScan(
2824             @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) {
2825         return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler);
2826     }
2827 
2828     /**
2829      * Stops any ongoing backgound scan
2830      * @param ifaceName Name of the interface.
2831      */
2832     public void stopBgScan(@NonNull String ifaceName) {
2833         mWifiVendorHal.stopBgScan(ifaceName);
2834     }
2835 
2836     /**
2837      * Pauses an ongoing backgound scan
2838      * @param ifaceName Name of the interface.
2839      */
2840     public void pauseBgScan(@NonNull String ifaceName) {
2841         mWifiVendorHal.pauseBgScan(ifaceName);
2842     }
2843 
2844     /**
2845      * Restarts a paused scan
2846      * @param ifaceName Name of the interface.
2847      */
2848     public void restartBgScan(@NonNull String ifaceName) {
2849         mWifiVendorHal.restartBgScan(ifaceName);
2850     }
2851 
2852     /**
2853      * Gets the latest scan results received.
2854      * @param ifaceName Name of the interface.
2855      */
2856     public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
2857         return mWifiVendorHal.getBgScanResults(ifaceName);
2858     }
2859 
2860     /**
2861      * Gets the latest link layer stats
2862      * @param ifaceName Name of the interface.
2863      */
2864     public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
2865         return mWifiVendorHal.getWifiLinkLayerStats(ifaceName);
2866     }
2867 
2868     /**
2869      * Returns whether STA/AP concurrency is supported or not.
2870      */
2871     public boolean isStaApConcurrencySupported() {
2872         synchronized (mLock) {
2873             return mWifiVendorHal.isStaApConcurrencySupported();
2874         }
2875     }
2876 
2877     /**
2878      * Get the supported features
2879      *
2880      * @param ifaceName Name of the interface.
2881      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
2882      */
2883     public long getSupportedFeatureSet(@NonNull String ifaceName) {
2884         synchronized (mLock) {
2885             Iface iface = mIfaceMgr.getIface(ifaceName);
2886             if (iface == null) {
2887                 Log.e(TAG, "Could not get Iface object for interface " + ifaceName);
2888                 return 0;
2889             }
2890 
2891             return iface.featureSet;
2892         }
2893     }
2894 
2895     /**
2896      * Get the supported features
2897      *
2898      * @param ifaceName Name of the interface.
2899      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
2900      */
2901     private long getSupportedFeatureSetInternal(@NonNull String ifaceName) {
2902         return mSupplicantStaIfaceHal.getAdvancedKeyMgmtCapabilities(ifaceName)
2903                 | mWifiVendorHal.getSupportedFeatureSet(ifaceName)
2904                 | mSupplicantStaIfaceHal.getWpaDriverFeatureSet(ifaceName);
2905     }
2906 
2907     /**
2908      * Class to retrieve connection capability parameters after association
2909      */
2910     public static class ConnectionCapabilities {
2911         public @WifiAnnotations.WifiStandard int wifiStandard;
2912         public int channelBandwidth;
2913         public int maxNumberTxSpatialStreams;
2914         public int maxNumberRxSpatialStreams;
2915         ConnectionCapabilities() {
2916             wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN;
2917             channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ;
2918             maxNumberTxSpatialStreams = 1;
2919             maxNumberRxSpatialStreams = 1;
2920         }
2921     }
2922 
2923     /**
2924      * Returns connection capabilities of the current network
2925      *
2926      * @param ifaceName Name of the interface.
2927      * @return connection capabilities of the current network
2928      */
2929     public ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
2930         return mSupplicantStaIfaceHal.getConnectionCapabilities(ifaceName);
2931     }
2932 
2933     /**
2934      * Get the APF (Android Packet Filter) capabilities of the device
2935      * @param ifaceName Name of the interface.
2936      */
2937     public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
2938         return mWifiVendorHal.getApfCapabilities(ifaceName);
2939     }
2940 
2941     /**
2942      * Installs an APF program on this iface, replacing any existing program.
2943      *
2944      * @param ifaceName Name of the interface
2945      * @param filter is the android packet filter program
2946      * @return true for success
2947      */
2948     public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
2949         return mWifiVendorHal.installPacketFilter(ifaceName, filter);
2950     }
2951 
2952     /**
2953      * Reads the APF program and data buffer for this iface.
2954      *
2955      * @param ifaceName Name of the interface
2956      * @return the buffer returned by the driver, or null in case of an error
2957      */
2958     public byte[] readPacketFilter(@NonNull String ifaceName) {
2959         return mWifiVendorHal.readPacketFilter(ifaceName);
2960     }
2961 
2962     /**
2963      * Set country code for this AP iface.
2964      * @param ifaceName Name of the interface.
2965      * @param countryCode - two-letter country code (as ISO 3166)
2966      * @return true for success
2967      */
2968     public boolean setCountryCodeHal(@NonNull String ifaceName, String countryCode) {
2969         return mWifiVendorHal.setCountryCodeHal(ifaceName, countryCode);
2970     }
2971 
2972     //---------------------------------------------------------------------------------
2973     /* Wifi Logger commands/events */
2974     public static interface WifiLoggerEventHandler {
2975         void onRingBufferData(RingBufferStatus status, byte[] buffer);
2976         void onWifiAlert(int errorCode, byte[] buffer);
2977     }
2978 
2979     /**
2980      * Registers the logger callback and enables alerts.
2981      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
2982      *
2983      * @param handler Callback to be invoked.
2984      * @return true on success, false otherwise.
2985      */
2986     public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
2987         return mWifiVendorHal.setLoggingEventHandler(handler);
2988     }
2989 
2990     /**
2991      * Control debug data collection
2992      *
2993      * @param verboseLevel 0 to 3, inclusive. 0 stops logging.
2994      * @param flags        Ignored.
2995      * @param maxInterval  Maximum interval between reports; ignore if 0.
2996      * @param minDataSize  Minimum data size in buffer for report; ignore if 0.
2997      * @param ringName     Name of the ring for which data collection is to start.
2998      * @return true for success, false otherwise.
2999      */
3000     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
3001             int minDataSize, String ringName){
3002         return mWifiVendorHal.startLoggingRingBuffer(
3003                 verboseLevel, flags, maxInterval, minDataSize, ringName);
3004     }
3005 
3006     /**
3007      * Logger features exposed.
3008      * This is a no-op now, will always return -1.
3009      *
3010      * @return true on success, false otherwise.
3011      */
3012     public int getSupportedLoggerFeatureSet() {
3013         return mWifiVendorHal.getSupportedLoggerFeatureSet();
3014     }
3015 
3016     /**
3017      * Stops all logging and resets the logger callback.
3018      * This stops both the alerts and ring buffer data collection.
3019      * @return true on success, false otherwise.
3020      */
3021     public boolean resetLogHandler() {
3022         return mWifiVendorHal.resetLogHandler();
3023     }
3024 
3025     /**
3026      * Vendor-provided wifi driver version string
3027      *
3028      * @return String returned from the HAL.
3029      */
3030     public String getDriverVersion() {
3031         return mWifiVendorHal.getDriverVersion();
3032     }
3033 
3034     /**
3035      * Vendor-provided wifi firmware version string
3036      *
3037      * @return String returned from the HAL.
3038      */
3039     public String getFirmwareVersion() {
3040         return mWifiVendorHal.getFirmwareVersion();
3041     }
3042 
3043     public static class RingBufferStatus{
3044         String name;
3045         int flag;
3046         int ringBufferId;
3047         int ringBufferByteSize;
3048         int verboseLevel;
3049         int writtenBytes;
3050         int readBytes;
3051         int writtenRecords;
3052 
3053         // Bit masks for interpreting |flag|
3054         public static final int HAS_BINARY_ENTRIES = (1 << 0);
3055         public static final int HAS_ASCII_ENTRIES = (1 << 1);
3056         public static final int HAS_PER_PACKET_ENTRIES = (1 << 2);
3057 
3058         @Override
3059         public String toString() {
3060             return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
3061                     " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
3062                     " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
3063                     " writtenRecords: " + writtenRecords;
3064         }
3065     }
3066 
3067     /**
3068      * API to get the status of all ring buffers supported by driver
3069      */
3070     public RingBufferStatus[] getRingBufferStatus() {
3071         return mWifiVendorHal.getRingBufferStatus();
3072     }
3073 
3074     /**
3075      * Indicates to driver that all the data has to be uploaded urgently
3076      *
3077      * @param ringName Name of the ring buffer requested.
3078      * @return true on success, false otherwise.
3079      */
3080     public boolean getRingBufferData(String ringName) {
3081         return mWifiVendorHal.getRingBufferData(ringName);
3082     }
3083 
3084     /**
3085      * Request hal to flush ring buffers to files
3086      *
3087      * @return true on success, false otherwise.
3088      */
3089     public boolean flushRingBufferData() {
3090         return mWifiVendorHal.flushRingBufferData();
3091     }
3092 
3093     /**
3094      * Request vendor debug info from the firmware
3095      *
3096      * @return Raw data obtained from the HAL.
3097      */
3098     public byte[] getFwMemoryDump() {
3099         return mWifiVendorHal.getFwMemoryDump();
3100     }
3101 
3102     /**
3103      * Request vendor debug info from the driver
3104      *
3105      * @return Raw data obtained from the HAL.
3106      */
3107     public byte[] getDriverStateDump() {
3108         return mWifiVendorHal.getDriverStateDump();
3109     }
3110 
3111     //---------------------------------------------------------------------------------
3112     /* Packet fate API */
3113 
3114     @Immutable
3115     abstract static class FateReport {
3116         final static int USEC_PER_MSEC = 1000;
3117         // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
3118         // maximal value of a driver timestamp in milliseconds.
3119         final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
3120         final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
3121 
3122         final byte mFate;
3123         final long mDriverTimestampUSec;
3124         final byte mFrameType;
3125         final byte[] mFrameBytes;
3126         final long mEstimatedWallclockMSec;
3127 
3128         FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3129             mFate = fate;
3130             mDriverTimestampUSec = driverTimestampUSec;
3131             mEstimatedWallclockMSec =
3132                     convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
3133             mFrameType = frameType;
3134             mFrameBytes = frameBytes;
3135         }
3136 
3137         public String toTableRowString() {
3138             StringWriter sw = new StringWriter();
3139             PrintWriter pw = new PrintWriter(sw);
3140             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3141             dateFormatter.setTimeZone(TimeZone.getDefault());
3142             pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3143                     mDriverTimestampUSec,
3144                     dateFormatter.format(new Date(mEstimatedWallclockMSec)),
3145                     directionToString(), fateToString(), parser.mMostSpecificProtocolString,
3146                     parser.mTypeString, parser.mResultString);
3147             return sw.toString();
3148         }
3149 
3150         public String toVerboseStringWithPiiAllowed() {
3151             StringWriter sw = new StringWriter();
3152             PrintWriter pw = new PrintWriter(sw);
3153             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3154             pw.format("Frame direction: %s\n", directionToString());
3155             pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
3156             pw.format("Frame fate: %s\n", fateToString());
3157             pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
3158             pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
3159             pw.format("Frame protocol type: %s\n", parser.mTypeString);
3160             pw.format("Frame length: %d\n", mFrameBytes.length);
3161             pw.append("Frame bytes");
3162             pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
3163             pw.append("\n");
3164             return sw.toString();
3165         }
3166 
3167         /* Returns a header to match the output of toTableRowString(). */
3168         public static String getTableHeader() {
3169             StringWriter sw = new StringWriter();
3170             PrintWriter pw = new PrintWriter(sw);
3171             pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3172                     "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
3173             pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3174                     "---------", "--------", "---------", "----", "--------", "----", "------");
3175             return sw.toString();
3176         }
3177 
3178         protected abstract String directionToString();
3179 
3180         protected abstract String fateToString();
3181 
3182         private static String frameTypeToString(byte frameType) {
3183             switch (frameType) {
3184                 case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
3185                     return "unknown";
3186                 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
3187                     return "data";
3188                 case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
3189                     return "802.11 management";
3190                 default:
3191                     return Byte.toString(frameType);
3192             }
3193         }
3194 
3195         /**
3196          * Converts a driver timestamp to a wallclock time, based on the current
3197          * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
3198          * microseconds, with the same base as BOOTTIME.
3199          */
3200         private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
3201             final long wallclockMillisNow = System.currentTimeMillis();
3202             final long boottimeMillisNow = SystemClock.elapsedRealtime();
3203             final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
3204 
3205             long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
3206             if (boottimeTimestampMillis < driverTimestampMillis) {
3207                 // The 32-bit microsecond count has wrapped between the time that the driver
3208                 // recorded the packet, and the call to this function. Adjust the BOOTTIME
3209                 // timestamp, to compensate.
3210                 //
3211                 // Note that overflow is not a concern here, since the result is less than
3212                 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
3213                 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
3214                 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
3215                 // within a long.
3216                 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
3217             }
3218 
3219             final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
3220             return wallclockMillisNow - millisSincePacketTimestamp;
3221         }
3222     }
3223 
3224     /**
3225      * Represents the fate information for one outbound packet.
3226      */
3227     @Immutable
3228     public static final class TxFateReport extends FateReport {
3229         TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3230             super(fate, driverTimestampUSec, frameType, frameBytes);
3231         }
3232 
3233         @Override
3234         protected String directionToString() {
3235             return "TX";
3236         }
3237 
3238         @Override
3239         protected String fateToString() {
3240             switch (mFate) {
3241                 case WifiLoggerHal.TX_PKT_FATE_ACKED:
3242                     return "acked";
3243                 case WifiLoggerHal.TX_PKT_FATE_SENT:
3244                     return "sent";
3245                 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
3246                     return "firmware queued";
3247                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
3248                     return "firmware dropped (invalid frame)";
3249                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
3250                     return "firmware dropped (no bufs)";
3251                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
3252                     return "firmware dropped (other)";
3253                 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
3254                     return "driver queued";
3255                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
3256                     return "driver dropped (invalid frame)";
3257                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
3258                     return "driver dropped (no bufs)";
3259                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
3260                     return "driver dropped (other)";
3261                 default:
3262                     return Byte.toString(mFate);
3263             }
3264         }
3265     }
3266 
3267     /**
3268      * Represents the fate information for one inbound packet.
3269      */
3270     @Immutable
3271     public static final class RxFateReport extends FateReport {
3272         RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3273             super(fate, driverTimestampUSec, frameType, frameBytes);
3274         }
3275 
3276         @Override
3277         protected String directionToString() {
3278             return "RX";
3279         }
3280 
3281         @Override
3282         protected String fateToString() {
3283             switch (mFate) {
3284                 case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
3285                     return "success";
3286                 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
3287                     return "firmware queued";
3288                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
3289                     return "firmware dropped (filter)";
3290                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
3291                     return "firmware dropped (invalid frame)";
3292                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
3293                     return "firmware dropped (no bufs)";
3294                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
3295                     return "firmware dropped (other)";
3296                 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
3297                     return "driver queued";
3298                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
3299                     return "driver dropped (filter)";
3300                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
3301                     return "driver dropped (invalid frame)";
3302                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
3303                     return "driver dropped (no bufs)";
3304                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
3305                     return "driver dropped (other)";
3306                 default:
3307                     return Byte.toString(mFate);
3308             }
3309         }
3310     }
3311 
3312     /**
3313      * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
3314      *
3315      * @param ifaceName Name of the interface.
3316      * @return true for success, false otherwise.
3317      */
3318     public boolean startPktFateMonitoring(@NonNull String ifaceName) {
3319         return mWifiVendorHal.startPktFateMonitoring(ifaceName);
3320     }
3321 
3322     /**
3323      * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
3324      *
3325      * @param ifaceName Name of the interface.
3326      * @return true for success, false otherwise.
3327      */
3328     public boolean getTxPktFates(@NonNull String ifaceName, TxFateReport[] reportBufs) {
3329         return mWifiVendorHal.getTxPktFates(ifaceName, reportBufs);
3330     }
3331 
3332     /**
3333      * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
3334      * @param ifaceName Name of the interface.
3335      */
3336     public boolean getRxPktFates(@NonNull String ifaceName, RxFateReport[] reportBufs) {
3337         return mWifiVendorHal.getRxPktFates(ifaceName, reportBufs);
3338     }
3339 
3340     /**
3341      * Get the tx packet counts for the interface.
3342      *
3343      * @param ifaceName Name of the interface.
3344      * @return tx packet counts
3345      */
3346     public long getTxPackets(@NonNull String ifaceName) {
3347         return TrafficStats.getTxPackets(ifaceName);
3348     }
3349 
3350     /**
3351      * Get the rx packet counts for the interface.
3352      *
3353      * @param ifaceName Name of the interface
3354      * @return rx packet counts
3355      */
3356     public long getRxPackets(@NonNull String ifaceName) {
3357         return TrafficStats.getRxPackets(ifaceName);
3358     }
3359 
3360     /**
3361      * Start sending the specified keep alive packets periodically.
3362      *
3363      * @param ifaceName Name of the interface.
3364      * @param slot Integer used to identify each request.
3365      * @param dstMac Destination MAC Address
3366      * @param packet Raw packet contents to send.
3367      * @param protocol The ethernet protocol type
3368      * @param period Period to use for sending these packets.
3369      * @return 0 for success, -1 for error
3370      */
3371     public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot,
3372             byte[] dstMac, byte[] packet, int protocol, int period) {
3373         byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName));
3374         return mWifiVendorHal.startSendingOffloadedPacket(
3375                 ifaceName, slot, srcMac, dstMac, packet, protocol, period);
3376     }
3377 
3378     /**
3379      * Stop sending the specified keep alive packets.
3380      *
3381      * @param ifaceName Name of the interface.
3382      * @param slot id - same as startSendingOffloadedPacket call.
3383      * @return 0 for success, -1 for error
3384      */
3385     public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
3386         return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot);
3387     }
3388 
3389     public static interface WifiRssiEventHandler {
3390         void onRssiThresholdBreached(byte curRssi);
3391     }
3392 
3393     /**
3394      * Start RSSI monitoring on the currently connected access point.
3395      *
3396      * @param ifaceName        Name of the interface.
3397      * @param maxRssi          Maximum RSSI threshold.
3398      * @param minRssi          Minimum RSSI threshold.
3399      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
3400      * @return 0 for success, -1 for failure
3401      */
3402     public int startRssiMonitoring(
3403             @NonNull String ifaceName, byte maxRssi, byte minRssi,
3404             WifiRssiEventHandler rssiEventHandler) {
3405         return mWifiVendorHal.startRssiMonitoring(
3406                 ifaceName, maxRssi, minRssi, rssiEventHandler);
3407     }
3408 
3409     /**
3410      * Stop RSSI monitoring on the currently connected access point.
3411      *
3412      * @param ifaceName Name of the interface.
3413      * @return 0 for success, -1 for failure
3414      */
3415     public int stopRssiMonitoring(@NonNull String ifaceName) {
3416         return mWifiVendorHal.stopRssiMonitoring(ifaceName);
3417     }
3418 
3419     /**
3420      * Fetch the host wakeup reasons stats from wlan driver.
3421      *
3422      * @return the |WlanWakeReasonAndCounts| object retrieved from the wlan driver.
3423      */
3424     public WlanWakeReasonAndCounts getWlanWakeReasonCount() {
3425         return mWifiVendorHal.getWlanWakeReasonCount();
3426     }
3427 
3428     /**
3429      * Enable/Disable Neighbour discovery offload functionality in the firmware.
3430      *
3431      * @param ifaceName Name of the interface.
3432      * @param enabled true to enable, false to disable.
3433      * @return true for success, false otherwise.
3434      */
3435     public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
3436         return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled);
3437     }
3438 
3439     // Firmware roaming control.
3440 
3441     /**
3442      * Class to retrieve firmware roaming capability parameters.
3443      */
3444     public static class RoamingCapabilities {
3445         public int  maxBlacklistSize;
3446         public int  maxWhitelistSize;
3447     }
3448 
3449     /**
3450      * Query the firmware roaming capabilities.
3451      * @param ifaceName Name of the interface.
3452      * @return true for success, false otherwise.
3453      */
3454     public boolean getRoamingCapabilities(
3455             @NonNull String ifaceName, RoamingCapabilities capabilities) {
3456         return mWifiVendorHal.getRoamingCapabilities(ifaceName, capabilities);
3457     }
3458 
3459     /**
3460      * Macros for controlling firmware roaming.
3461      */
3462     public static final int DISABLE_FIRMWARE_ROAMING = 0;
3463     public static final int ENABLE_FIRMWARE_ROAMING = 1;
3464 
3465     /**
3466      * Indicates success for enableFirmwareRoaming
3467      */
3468     public static final int SET_FIRMWARE_ROAMING_SUCCESS = 0;
3469 
3470     /**
3471      * Indicates failure for enableFirmwareRoaming
3472      */
3473     public static final int SET_FIRMWARE_ROAMING_FAILURE = 1;
3474 
3475     /**
3476      * Indicates temporary failure for enableFirmwareRoaming - try again later
3477      */
3478     public static final int SET_FIRMWARE_ROAMING_BUSY = 2;
3479 
3480     /**
3481      * Enable/disable firmware roaming.
3482      *
3483      * @param ifaceName Name of the interface.
3484      * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE,
3485      *         or SET_FIRMWARE_ROAMING_BUSY
3486      */
3487     public int enableFirmwareRoaming(@NonNull String ifaceName, int state) {
3488         return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state);
3489     }
3490 
3491     /**
3492      * Class for specifying the roaming configurations.
3493      */
3494     public static class RoamingConfig {
3495         public ArrayList<String> blacklistBssids;
3496         public ArrayList<String> whitelistSsids;
3497     }
3498 
3499     /**
3500      * Set firmware roaming configurations.
3501      * @param ifaceName Name of the interface.
3502      */
3503     public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) {
3504         return mWifiVendorHal.configureRoaming(ifaceName, config);
3505     }
3506 
3507     /**
3508      * Reset firmware roaming configuration.
3509      * @param ifaceName Name of the interface.
3510      */
3511     public boolean resetRoamingConfiguration(@NonNull String ifaceName) {
3512         // Pass in an empty RoamingConfig object which translates to zero size
3513         // blacklist and whitelist to reset the firmware roaming configuration.
3514         return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig());
3515     }
3516 
3517     /**
3518      * Select one of the pre-configured transmit power level scenarios or reset it back to normal.
3519      * Primarily used for meeting SAR requirements.
3520      *
3521      * @param sarInfo The collection of inputs used to select the SAR scenario.
3522      * @return true for success; false for failure or if the HAL version does not support this API.
3523      */
3524     public boolean selectTxPowerScenario(SarInfo sarInfo) {
3525         return mWifiVendorHal.selectTxPowerScenario(sarInfo);
3526     }
3527 
3528     /**
3529      * Set MBO cellular data status
3530      *
3531      * @param ifaceName Name of the interface.
3532      * @param available cellular data status,
3533      *        true means cellular data available, false otherwise.
3534      */
3535     public void setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
3536         mSupplicantStaIfaceHal.setMboCellularDataStatus(ifaceName, available);
3537         return;
3538     }
3539 
3540     /**
3541      * Query of support of Wi-Fi standard
3542      *
3543      * @param ifaceName name of the interface to check support on
3544      * @param standard the wifi standard to check on
3545      * @return true if the wifi standard is supported on this interface, false otherwise.
3546      */
3547     public boolean isWifiStandardSupported(@NonNull String ifaceName,
3548             @WifiAnnotations.WifiStandard int standard) {
3549         synchronized (mLock) {
3550             Iface iface = mIfaceMgr.getIface(ifaceName);
3551             if (iface == null || iface.phyCapabilities == null) {
3552                 return false;
3553             }
3554             return iface.phyCapabilities.isWifiStandardSupported(standard);
3555         }
3556     }
3557 
3558     /**
3559      * Get the Wiphy capabilities of a device for a given interface
3560      * If the interface is not associated with one,
3561      * it will be read from the device through wificond
3562      *
3563      * @param ifaceName name of the interface
3564      * @return the device capabilities for this interface
3565      */
3566     public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
3567         synchronized (mLock) {
3568             Iface iface = mIfaceMgr.getIface(ifaceName);
3569             if (iface == null) {
3570                 Log.e(TAG, "Failed to get device capabilities, interface not found: " + ifaceName);
3571                 return null;
3572             }
3573             if (iface.phyCapabilities == null) {
3574                 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName);
3575             }
3576             return iface.phyCapabilities;
3577         }
3578     }
3579 
3580     /**
3581      * Set the Wiphy capabilities of a device for a given interface
3582      *
3583      * @param ifaceName name of the interface
3584      * @param capabilities the wiphy capabilities to set for this interface
3585      */
3586     public void setDeviceWiphyCapabilities(@NonNull String ifaceName,
3587             DeviceWiphyCapabilities capabilities) {
3588         synchronized (mLock) {
3589             Iface iface = mIfaceMgr.getIface(ifaceName);
3590             if (iface == null) {
3591                 Log.e(TAG, "Failed to set device capabilities, interface not found: " + ifaceName);
3592                 return;
3593             }
3594             iface.phyCapabilities = capabilities;
3595         }
3596     }
3597 }
3598