• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.NonNull;
22 import android.app.AlarmManager;
23 import android.net.wifi.IApInterface;
24 import android.net.wifi.IApInterfaceEventCallback;
25 import android.net.wifi.IClientInterface;
26 import android.net.wifi.IPnoScanEvent;
27 import android.net.wifi.IScanEvent;
28 import android.net.wifi.ISendMgmtFrameEvent;
29 import android.net.wifi.IWifiScannerImpl;
30 import android.net.wifi.IWificond;
31 import android.net.wifi.ScanResult;
32 import android.net.wifi.WifiScanner;
33 import android.net.wifi.WifiSsid;
34 import android.os.Binder;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.Looper;
38 import android.os.RemoteException;
39 import android.util.Log;
40 
41 import com.android.server.wifi.WifiNative.SendMgmtFrameCallback;
42 import com.android.server.wifi.WifiNative.SoftApListener;
43 import com.android.server.wifi.hotspot2.NetworkDetail;
44 import com.android.server.wifi.util.InformationElementUtil;
45 import com.android.server.wifi.util.NativeUtil;
46 import com.android.server.wifi.util.ScanResultUtil;
47 import com.android.server.wifi.wificond.ChannelSettings;
48 import com.android.server.wifi.wificond.HiddenNetwork;
49 import com.android.server.wifi.wificond.NativeScanResult;
50 import com.android.server.wifi.wificond.PnoNetwork;
51 import com.android.server.wifi.wificond.PnoSettings;
52 import com.android.server.wifi.wificond.RadioChainInfo;
53 import com.android.server.wifi.wificond.SingleScanSettings;
54 
55 import java.util.ArrayList;
56 import java.util.HashMap;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Set;
60 import java.util.concurrent.atomic.AtomicBoolean;
61 
62 /**
63  * This class provides methods for WifiNative to send control commands to wificond.
64  * NOTE: This class should only be used from WifiNative.
65  */
66 public class WificondControl implements IBinder.DeathRecipient {
67     private boolean mVerboseLoggingEnabled = false;
68 
69     /**
70      * The {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
71      * timeout, in milliseconds, after which
72      * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
73      * {@link WifiNative#SEND_MGMT_FRAME_ERROR_TIMEOUT}.
74      */
75     public static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
76 
77     private static final String TAG = "WificondControl";
78 
79     private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
80 
81     /* Get scan results for a single scan */
82     public static final int SCAN_TYPE_SINGLE_SCAN = 0;
83 
84     /* Get scan results for Pno Scan */
85     public static final int SCAN_TYPE_PNO_SCAN = 1;
86 
87     private WifiInjector mWifiInjector;
88     private WifiMonitor mWifiMonitor;
89     private final CarrierNetworkConfig mCarrierNetworkConfig;
90     private AlarmManager mAlarmManager;
91     private Handler mEventHandler;
92     private Clock mClock;
93     private WifiNative mWifiNative = null;
94 
95     // Cached wificond binder handlers.
96     private IWificond mWificond;
97     private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
98     private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
99     private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>();
100     private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>();
101     private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>();
102     private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>();
103     private WifiNative.WificondDeathEventHandler mDeathEventHandler;
104     /**
105      * Ensures that no more than one sendMgmtFrame operation runs concurrently.
106      */
107     private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
108     private boolean mIsEnhancedOpenSupportedInitialized = false;
109     private boolean mIsEnhancedOpenSupported;
110 
111     private class ScanEventHandler extends IScanEvent.Stub {
112         private String mIfaceName;
113 
ScanEventHandler(@onNull String ifaceName)114         ScanEventHandler(@NonNull String ifaceName) {
115             mIfaceName = ifaceName;
116         }
117 
118         @Override
OnScanResultReady()119         public void OnScanResultReady() {
120             Log.d(TAG, "Scan result ready event");
121             mWifiMonitor.broadcastScanResultEvent(mIfaceName);
122         }
123 
124         @Override
OnScanFailed()125         public void OnScanFailed() {
126             Log.d(TAG, "Scan failed event");
127             mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
128         }
129     }
130 
WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, CarrierNetworkConfig carrierNetworkConfig, AlarmManager alarmManager, Looper looper, Clock clock)131     WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor,
132             CarrierNetworkConfig carrierNetworkConfig, AlarmManager alarmManager, Looper looper,
133             Clock clock) {
134         mWifiInjector = wifiInjector;
135         mWifiMonitor = wifiMonitor;
136         mCarrierNetworkConfig = carrierNetworkConfig;
137         mAlarmManager = alarmManager;
138         mEventHandler = new Handler(looper);
139         mClock = clock;
140     }
141 
142     private class PnoScanEventHandler extends IPnoScanEvent.Stub {
143         private String mIfaceName;
144 
PnoScanEventHandler(@onNull String ifaceName)145         PnoScanEventHandler(@NonNull String ifaceName) {
146             mIfaceName = ifaceName;
147         }
148 
149         @Override
OnPnoNetworkFound()150         public void OnPnoNetworkFound() {
151             Log.d(TAG, "Pno scan result event");
152             mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName);
153             mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount();
154         }
155 
156         @Override
OnPnoScanFailed()157         public void OnPnoScanFailed() {
158             Log.d(TAG, "Pno Scan failed event");
159             mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
160         }
161 
162         @Override
OnPnoScanOverOffloadStarted()163         public void OnPnoScanOverOffloadStarted() {
164             Log.d(TAG, "Pno scan over offload started");
165             mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount();
166         }
167 
168         @Override
OnPnoScanOverOffloadFailed(int reason)169         public void OnPnoScanOverOffloadFailed(int reason) {
170             Log.d(TAG, "Pno scan over offload failed");
171             mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount();
172         }
173     }
174 
175     /**
176      * Listener for AP Interface events.
177      */
178     private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
179         private SoftApListener mSoftApListener;
180 
ApInterfaceEventCallback(SoftApListener listener)181         ApInterfaceEventCallback(SoftApListener listener) {
182             mSoftApListener = listener;
183         }
184 
185         @Override
onNumAssociatedStationsChanged(int numStations)186         public void onNumAssociatedStationsChanged(int numStations) {
187             mSoftApListener.onNumAssociatedStationsChanged(numStations);
188         }
189 
190         @Override
onSoftApChannelSwitched(int frequency, int bandwidth)191         public void onSoftApChannelSwitched(int frequency, int bandwidth) {
192             mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth);
193         }
194     }
195 
196     /**
197      * Callback triggered by wificond.
198      */
199     private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
200         private SendMgmtFrameCallback mCallback;
201         private AlarmManager.OnAlarmListener mTimeoutCallback;
202         /**
203          * ensures that mCallback is only called once
204          */
205         private boolean mWasCalled;
206 
runIfFirstCall(Runnable r)207         private void runIfFirstCall(Runnable r) {
208             if (mWasCalled) return;
209             mWasCalled = true;
210 
211             mSendMgmtFrameInProgress.set(false);
212             r.run();
213         }
214 
SendMgmtFrameEvent(@onNull SendMgmtFrameCallback callback)215         SendMgmtFrameEvent(@NonNull SendMgmtFrameCallback callback) {
216             mCallback = callback;
217             // called in main thread
218             mTimeoutCallback = () -> runIfFirstCall(() -> {
219                 if (mVerboseLoggingEnabled) {
220                     Log.e(TAG, "Timed out waiting for ACK");
221                 }
222                 mCallback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_TIMEOUT);
223             });
224             mWasCalled = false;
225 
226             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
227                     mClock.getElapsedSinceBootMillis() + SEND_MGMT_FRAME_TIMEOUT_MS,
228                     TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler);
229         }
230 
231         // called in binder thread
232         @Override
OnAck(int elapsedTimeMs)233         public void OnAck(int elapsedTimeMs) {
234             // post to main thread
235             mEventHandler.post(() -> runIfFirstCall(() -> {
236                 mAlarmManager.cancel(mTimeoutCallback);
237                 mCallback.onAck(elapsedTimeMs);
238             }));
239         }
240 
241         // called in binder thread
242         @Override
OnFailure(int reason)243         public void OnFailure(int reason) {
244             // post to main thread
245             mEventHandler.post(() -> runIfFirstCall(() -> {
246                 mAlarmManager.cancel(mTimeoutCallback);
247                 mCallback.onFailure(reason);
248             }));
249         }
250     }
251 
252     /**
253      * Called by the binder subsystem upon remote object death.
254      * Invoke all the register death handlers and clear state.
255      */
256     @Override
binderDied()257     public void binderDied() {
258         mEventHandler.post(() -> {
259             Log.e(TAG, "Wificond died!");
260             clearState();
261             // Invalidate the global wificond handle on death. Will be refreshed
262             // on the next setup call.
263             mWificond = null;
264             if (mDeathEventHandler != null) {
265                 mDeathEventHandler.onDeath();
266             }
267         });
268     }
269 
270     /** Enable or disable verbose logging of WificondControl.
271      *  @param enable True to enable verbose logging. False to disable verbose logging.
272      */
enableVerboseLogging(boolean enable)273     public void enableVerboseLogging(boolean enable) {
274         mVerboseLoggingEnabled = enable;
275     }
276 
277     /**
278      * Initializes wificond & registers a death notification for wificond.
279      * This method clears any existing state in wificond daemon.
280      *
281      * @return Returns true on success.
282      */
initialize(@onNull WifiNative.WificondDeathEventHandler handler)283     public boolean initialize(@NonNull WifiNative.WificondDeathEventHandler handler) {
284         if (mDeathEventHandler != null) {
285             Log.e(TAG, "Death handler already present");
286         }
287         mDeathEventHandler = handler;
288         tearDownInterfaces();
289         return true;
290     }
291 
292     /**
293      * Helper method to retrieve the global wificond handle and register for
294      * death notifications.
295      */
retrieveWificondAndRegisterForDeath()296     private boolean retrieveWificondAndRegisterForDeath() {
297         if (mWificond != null) {
298             if (mVerboseLoggingEnabled) {
299                 Log.d(TAG, "Wificond handle already retrieved");
300             }
301             // We already have a wificond handle.
302             return true;
303         }
304         mWificond = mWifiInjector.makeWificond();
305         if (mWificond == null) {
306             Log.e(TAG, "Failed to get reference to wificond");
307             return false;
308         }
309         try {
310             mWificond.asBinder().linkToDeath(this, 0);
311         } catch (RemoteException e) {
312             Log.e(TAG, "Failed to register death notification for wificond");
313             // The remote has already died.
314             return false;
315         }
316         return true;
317     }
318 
319     /**
320     * Setup interface for client mode via wificond.
321     * @return An IClientInterface as wificond client interface binder handler.
322     * Returns null on failure.
323     */
setupInterfaceForClientMode(@onNull String ifaceName)324     public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) {
325         Log.d(TAG, "Setting up interface for client mode");
326         if (!retrieveWificondAndRegisterForDeath()) {
327             return null;
328         }
329 
330         IClientInterface clientInterface = null;
331         try {
332             clientInterface = mWificond.createClientInterface(ifaceName);
333         } catch (RemoteException e1) {
334             Log.e(TAG, "Failed to get IClientInterface due to remote exception");
335             return null;
336         }
337 
338         if (clientInterface == null) {
339             Log.e(TAG, "Could not get IClientInterface instance from wificond");
340             return null;
341         }
342         Binder.allowBlocking(clientInterface.asBinder());
343 
344         // Refresh Handlers
345         mClientInterfaces.put(ifaceName, clientInterface);
346         try {
347             IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
348             if (wificondScanner == null) {
349                 Log.e(TAG, "Failed to get WificondScannerImpl");
350                 return null;
351             }
352             mWificondScanners.put(ifaceName, wificondScanner);
353             Binder.allowBlocking(wificondScanner.asBinder());
354             ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName);
355             mScanEventHandlers.put(ifaceName,  scanEventHandler);
356             wificondScanner.subscribeScanEvents(scanEventHandler);
357             PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName);
358             mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
359             wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
360         } catch (RemoteException e) {
361             Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
362         }
363 
364         return clientInterface;
365     }
366 
367     /**
368      * Teardown a specific STA interface configured in wificond.
369      *
370      * @return Returns true on success.
371      */
tearDownClientInterface(@onNull String ifaceName)372     public boolean tearDownClientInterface(@NonNull String ifaceName) {
373         if (getClientInterface(ifaceName) == null) {
374             Log.e(TAG, "No valid wificond client interface handler");
375             return false;
376         }
377         try {
378             IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName);
379             if (scannerImpl != null) {
380                 scannerImpl.unsubscribeScanEvents();
381                 scannerImpl.unsubscribePnoScanEvents();
382             }
383         } catch (RemoteException e) {
384             Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception");
385             return false;
386         }
387 
388         boolean success;
389         try {
390             success = mWificond.tearDownClientInterface(ifaceName);
391         } catch (RemoteException e1) {
392             Log.e(TAG, "Failed to teardown client interface due to remote exception");
393             return false;
394         }
395         if (!success) {
396             Log.e(TAG, "Failed to teardown client interface");
397             return false;
398         }
399 
400         mClientInterfaces.remove(ifaceName);
401         mWificondScanners.remove(ifaceName);
402         mScanEventHandlers.remove(ifaceName);
403         mPnoScanEventHandlers.remove(ifaceName);
404         return true;
405     }
406 
407     /**
408     * Setup interface for softAp mode via wificond.
409     * @return An IApInterface as wificond Ap interface binder handler.
410     * Returns null on failure.
411     */
setupInterfaceForSoftApMode(@onNull String ifaceName)412     public IApInterface setupInterfaceForSoftApMode(@NonNull String ifaceName) {
413         Log.d(TAG, "Setting up interface for soft ap mode");
414         if (!retrieveWificondAndRegisterForDeath()) {
415             return null;
416         }
417 
418         IApInterface apInterface = null;
419         try {
420             apInterface = mWificond.createApInterface(ifaceName);
421         } catch (RemoteException e1) {
422             Log.e(TAG, "Failed to get IApInterface due to remote exception");
423             return null;
424         }
425 
426         if (apInterface == null) {
427             Log.e(TAG, "Could not get IApInterface instance from wificond");
428             return null;
429         }
430         Binder.allowBlocking(apInterface.asBinder());
431 
432         // Refresh Handlers
433         mApInterfaces.put(ifaceName, apInterface);
434         return apInterface;
435     }
436 
437     /**
438      * Teardown a specific AP interface configured in wificond.
439      *
440      * @return Returns true on success.
441      */
tearDownSoftApInterface(@onNull String ifaceName)442     public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
443         if (getApInterface(ifaceName) == null) {
444             Log.e(TAG, "No valid wificond ap interface handler");
445             return false;
446         }
447         boolean success;
448         try {
449             success = mWificond.tearDownApInterface(ifaceName);
450         } catch (RemoteException e1) {
451             Log.e(TAG, "Failed to teardown AP interface due to remote exception");
452             return false;
453         }
454         if (!success) {
455             Log.e(TAG, "Failed to teardown AP interface");
456             return false;
457         }
458         mApInterfaces.remove(ifaceName);
459         mApInterfaceListeners.remove(ifaceName);
460         return true;
461     }
462 
463     /**
464     * Teardown all interfaces configured in wificond.
465     * @return Returns true on success.
466     */
tearDownInterfaces()467     public boolean tearDownInterfaces() {
468         Log.d(TAG, "tearing down interfaces in wificond");
469         // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
470         // could be used to cleanup before we setup any interfaces.
471         if (!retrieveWificondAndRegisterForDeath()) {
472             return false;
473         }
474 
475         try {
476             for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) {
477                 entry.getValue().unsubscribeScanEvents();
478                 entry.getValue().unsubscribePnoScanEvents();
479             }
480             mWificond.tearDownInterfaces();
481             clearState();
482             return true;
483         } catch (RemoteException e) {
484             Log.e(TAG, "Failed to tear down interfaces due to remote exception");
485         }
486 
487         return false;
488     }
489 
490     /** Helper function to look up the interface handle using name */
getClientInterface(@onNull String ifaceName)491     private IClientInterface getClientInterface(@NonNull String ifaceName) {
492         return mClientInterfaces.get(ifaceName);
493     }
494 
495     /**
496      * Request signal polling to wificond.
497      * @param ifaceName Name of the interface.
498      * Returns an SignalPollResult object.
499      * Returns null on failure.
500      */
signalPoll(@onNull String ifaceName)501     public WifiNative.SignalPollResult signalPoll(@NonNull String ifaceName) {
502         IClientInterface iface = getClientInterface(ifaceName);
503         if (iface == null) {
504             Log.e(TAG, "No valid wificond client interface handler");
505             return null;
506         }
507 
508         int[] resultArray;
509         try {
510             resultArray = iface.signalPoll();
511             if (resultArray == null || resultArray.length != 4) {
512                 Log.e(TAG, "Invalid signal poll result from wificond");
513                 return null;
514             }
515         } catch (RemoteException e) {
516             Log.e(TAG, "Failed to do signal polling due to remote exception");
517             return null;
518         }
519         WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult();
520         pollResult.currentRssi = resultArray[0];
521         pollResult.txBitrate = resultArray[1];
522         pollResult.associationFrequency = resultArray[2];
523         pollResult.rxBitrate = resultArray[3];
524         return pollResult;
525     }
526 
527     /**
528      * Fetch TX packet counters on current connection from wificond.
529      * @param ifaceName Name of the interface.
530      * Returns an TxPacketCounters object.
531      * Returns null on failure.
532      */
getTxPacketCounters(@onNull String ifaceName)533     public WifiNative.TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
534         IClientInterface iface = getClientInterface(ifaceName);
535         if (iface == null) {
536             Log.e(TAG, "No valid wificond client interface handler");
537             return null;
538         }
539 
540         int[] resultArray;
541         try {
542             resultArray = iface.getPacketCounters();
543             if (resultArray == null || resultArray.length != 2) {
544                 Log.e(TAG, "Invalid signal poll result from wificond");
545                 return null;
546             }
547         } catch (RemoteException e) {
548             Log.e(TAG, "Failed to do signal polling due to remote exception");
549             return null;
550         }
551         WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters();
552         counters.txSucceeded = resultArray[0];
553         counters.txFailed = resultArray[1];
554         return counters;
555     }
556 
557     /** Helper function to look up the scanner impl handle using name */
getScannerImpl(@onNull String ifaceName)558     private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) {
559         return mWificondScanners.get(ifaceName);
560     }
561 
562     /**
563     * Fetch the latest scan result from kernel via wificond.
564     * @param ifaceName Name of the interface.
565     * @return Returns an ArrayList of ScanDetail.
566     * Returns an empty ArrayList on failure.
567     */
getScanResults(@onNull String ifaceName, int scanType)568     public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
569         ArrayList<ScanDetail> results = new ArrayList<>();
570         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
571         if (scannerImpl == null) {
572             Log.e(TAG, "No valid wificond scanner interface handler");
573             return results;
574         }
575         try {
576             NativeScanResult[] nativeResults;
577             if (scanType == SCAN_TYPE_SINGLE_SCAN) {
578                 nativeResults = scannerImpl.getScanResults();
579             } else {
580                 nativeResults = scannerImpl.getPnoScanResults();
581             }
582             for (NativeScanResult result : nativeResults) {
583                 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
584                 String bssid;
585                 try {
586                     bssid = NativeUtil.macAddressFromByteArray(result.bssid);
587                 } catch (IllegalArgumentException e) {
588                     Log.e(TAG, "Illegal argument " + result.bssid, e);
589                     continue;
590                 }
591                 if (bssid == null) {
592                     Log.e(TAG, "Illegal null bssid");
593                     continue;
594                 }
595                 ScanResult.InformationElement[] ies =
596                         InformationElementUtil.parseInformationElements(result.infoElement);
597                 InformationElementUtil.Capabilities capabilities =
598                         new InformationElementUtil.Capabilities();
599                 capabilities.from(ies, result.capability, isEnhancedOpenSupported());
600                 String flags = capabilities.generateCapabilitiesString();
601                 NetworkDetail networkDetail;
602                 try {
603                     networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
604                 } catch (IllegalArgumentException e) {
605                     Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
606                     continue;
607                 }
608 
609                 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
610                         result.signalMbm / 100, result.frequency, result.tsf, ies, null);
611                 ScanResult scanResult = scanDetail.getScanResult();
612                 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
613                 // network and it uses EAP.
614                 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
615                         && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
616                     scanResult.isCarrierAp = true;
617                     scanResult.carrierApEapType =
618                             mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
619                     scanResult.carrierName =
620                             mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
621                 }
622                 // Fill up the radio chain info.
623                 if (result.radioChainInfos != null) {
624                     scanResult.radioChainInfos =
625                         new ScanResult.RadioChainInfo[result.radioChainInfos.size()];
626                     int idx = 0;
627                     for (RadioChainInfo nativeRadioChainInfo : result.radioChainInfos) {
628                         scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
629                         scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.chainId;
630                         scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.level;
631                         idx++;
632                     }
633                 }
634                 results.add(scanDetail);
635             }
636         } catch (RemoteException e1) {
637             Log.e(TAG, "Failed to create ScanDetail ArrayList");
638         }
639         if (mVerboseLoggingEnabled) {
640             Log.d(TAG, "get " + results.size() + " scan results from wificond");
641         }
642 
643         return results;
644     }
645 
646     /**
647      * Return scan type for the parcelable {@link SingleScanSettings}
648      */
getScanType(int scanType)649     private static int getScanType(int scanType) {
650         switch (scanType) {
651             case WifiNative.SCAN_TYPE_LOW_LATENCY:
652                 return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN;
653             case WifiNative.SCAN_TYPE_LOW_POWER:
654                 return IWifiScannerImpl.SCAN_TYPE_LOW_POWER;
655             case WifiNative.SCAN_TYPE_HIGH_ACCURACY:
656                 return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
657             default:
658                 throw new IllegalArgumentException("Invalid scan type " + scanType);
659         }
660     }
661 
662     /**
663      * Start a scan using wificond for the given parameters.
664      * @param ifaceName Name of the interface.
665      * @param scanType Type of scan to perform.
666      * @param freqs list of frequencies to scan for, if null scan all supported channels.
667      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
668      * @return Returns true on success.
669      */
scan(@onNull String ifaceName, int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs)670     public boolean scan(@NonNull String ifaceName,
671                         int scanType,
672                         Set<Integer> freqs,
673                         List<String> hiddenNetworkSSIDs) {
674         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
675         if (scannerImpl == null) {
676             Log.e(TAG, "No valid wificond scanner interface handler");
677             return false;
678         }
679         SingleScanSettings settings = new SingleScanSettings();
680         try {
681             settings.scanType = getScanType(scanType);
682         } catch (IllegalArgumentException e) {
683             Log.e(TAG, "Invalid scan type ", e);
684             return false;
685         }
686         settings.channelSettings  = new ArrayList<>();
687         settings.hiddenNetworks  = new ArrayList<>();
688 
689         if (freqs != null) {
690             for (Integer freq : freqs) {
691                 ChannelSettings channel = new ChannelSettings();
692                 channel.frequency = freq;
693                 settings.channelSettings.add(channel);
694             }
695         }
696         if (hiddenNetworkSSIDs != null) {
697             for (String ssid : hiddenNetworkSSIDs) {
698                 HiddenNetwork network = new HiddenNetwork();
699                 try {
700                     network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid));
701                 } catch (IllegalArgumentException e) {
702                     Log.e(TAG, "Illegal argument " + ssid, e);
703                     continue;
704                 }
705                 // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
706                 // any performance issues.
707                 if (!settings.hiddenNetworks.contains(network)) {
708                     settings.hiddenNetworks.add(network);
709                 }
710             }
711         }
712 
713         try {
714             return scannerImpl.scan(settings);
715         } catch (RemoteException e1) {
716             Log.e(TAG, "Failed to request scan due to remote exception");
717         }
718         return false;
719     }
720 
721     /**
722      * Start PNO scan.
723      * @param ifaceName Name of the interface.
724      * @param pnoSettings Pno scan configuration.
725      * @return true on success.
726      */
startPnoScan(@onNull String ifaceName, WifiNative.PnoSettings pnoSettings)727     public boolean startPnoScan(@NonNull String ifaceName, WifiNative.PnoSettings pnoSettings) {
728         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
729         if (scannerImpl == null) {
730             Log.e(TAG, "No valid wificond scanner interface handler");
731             return false;
732         }
733         PnoSettings settings = new PnoSettings();
734         settings.pnoNetworks  = new ArrayList<>();
735         settings.intervalMs = pnoSettings.periodInMs;
736         settings.min2gRssi = pnoSettings.min24GHzRssi;
737         settings.min5gRssi = pnoSettings.min5GHzRssi;
738         if (pnoSettings.networkList != null) {
739             for (WifiNative.PnoNetwork network : pnoSettings.networkList) {
740                 PnoNetwork condNetwork = new PnoNetwork();
741                 condNetwork.isHidden = (network.flags
742                         & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0;
743                 try {
744                     condNetwork.ssid =
745                             NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid));
746                 } catch (IllegalArgumentException e) {
747                     Log.e(TAG, "Illegal argument " + network.ssid, e);
748                     continue;
749                 }
750                 condNetwork.frequencies = network.frequencies;
751                 settings.pnoNetworks.add(condNetwork);
752             }
753         }
754 
755         try {
756             boolean success = scannerImpl.startPnoScan(settings);
757             mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount();
758             if (!success) {
759                 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
760             }
761             return success;
762         } catch (RemoteException e1) {
763             Log.e(TAG, "Failed to start pno scan due to remote exception");
764         }
765         return false;
766     }
767 
768     /**
769      * Stop PNO scan.
770      * @param ifaceName Name of the interface.
771      * @return true on success.
772      */
stopPnoScan(@onNull String ifaceName)773     public boolean stopPnoScan(@NonNull String ifaceName) {
774         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
775         if (scannerImpl == null) {
776             Log.e(TAG, "No valid wificond scanner interface handler");
777             return false;
778         }
779         try {
780             return scannerImpl.stopPnoScan();
781         } catch (RemoteException e1) {
782             Log.e(TAG, "Failed to stop pno scan due to remote exception");
783         }
784         return false;
785     }
786 
787     /**
788      * Abort ongoing single scan.
789      * @param ifaceName Name of the interface.
790      */
abortScan(@onNull String ifaceName)791     public void abortScan(@NonNull String ifaceName) {
792         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
793         if (scannerImpl == null) {
794             Log.e(TAG, "No valid wificond scanner interface handler");
795             return;
796         }
797         try {
798             scannerImpl.abortScan();
799         } catch (RemoteException e1) {
800             Log.e(TAG, "Failed to request abortScan due to remote exception");
801         }
802     }
803 
804     /**
805      * Query the list of valid frequencies for the provided band.
806      * The result depends on the on the country code that has been set.
807      *
808      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
809      * The following bands are supported:
810      * WifiScanner.WIFI_BAND_24_GHZ
811      * WifiScanner.WIFI_BAND_5_GHZ
812      * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
813      * @return frequencies vector of valid frequencies (MHz), or null for error.
814      * @throws IllegalArgumentException if band is not recognized.
815      */
getChannelsForBand(int band)816     public int [] getChannelsForBand(int band) {
817         if (mWificond == null) {
818             Log.e(TAG, "No valid wificond scanner interface handler");
819             return null;
820         }
821         try {
822             switch (band) {
823                 case WifiScanner.WIFI_BAND_24_GHZ:
824                     return mWificond.getAvailable2gChannels();
825                 case WifiScanner.WIFI_BAND_5_GHZ:
826                     return mWificond.getAvailable5gNonDFSChannels();
827                 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
828                     return mWificond.getAvailableDFSChannels();
829                 default:
830                     throw new IllegalArgumentException("unsupported band " + band);
831             }
832         } catch (RemoteException e1) {
833             Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
834         }
835         return null;
836     }
837 
838     /** Helper function to look up the interface handle using name */
getApInterface(@onNull String ifaceName)839     private IApInterface getApInterface(@NonNull String ifaceName) {
840         return mApInterfaces.get(ifaceName);
841     }
842 
843     /**
844      * Register the provided listener for SoftAp events.
845      *
846      * @param ifaceName Name of the interface.
847      * @param listener Callback for AP events.
848      * @return true on success, false otherwise.
849      */
registerApListener(@onNull String ifaceName, SoftApListener listener)850     public boolean registerApListener(@NonNull String ifaceName, SoftApListener listener) {
851         IApInterface iface = getApInterface(ifaceName);
852         if (iface == null) {
853             Log.e(TAG, "No valid ap interface handler");
854             return false;
855         }
856         try {
857             IApInterfaceEventCallback  callback = new ApInterfaceEventCallback(listener);
858             mApInterfaceListeners.put(ifaceName, callback);
859             boolean success = iface.registerCallback(callback);
860             if (!success) {
861                 Log.e(TAG, "Failed to register ap callback.");
862                 return false;
863             }
864         } catch (RemoteException e) {
865             Log.e(TAG, "Exception in registering AP callback: " + e);
866             return false;
867         }
868         return true;
869     }
870 
871     /**
872      * See {@link WifiNative#sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int)}
873      */
sendMgmtFrame(@onNull String ifaceName, @NonNull byte[] frame, @NonNull SendMgmtFrameCallback callback, int mcs)874     public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
875             @NonNull SendMgmtFrameCallback callback, int mcs) {
876 
877         if (callback == null) {
878             Log.e(TAG, "callback cannot be null!");
879             return;
880         }
881 
882         if (frame == null) {
883             Log.e(TAG, "frame cannot be null!");
884             callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN);
885             return;
886         }
887 
888         // TODO (b/112029045) validate mcs
889         IClientInterface clientInterface = getClientInterface(ifaceName);
890         if (clientInterface == null) {
891             Log.e(TAG, "No valid wificond client interface handler");
892             callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN);
893             return;
894         }
895 
896         if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
897             Log.e(TAG, "An existing management frame transmission is in progress!");
898             callback.onFailure(WifiNative.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
899             return;
900         }
901 
902         SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(callback);
903         try {
904             clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
905         } catch (RemoteException e) {
906             Log.e(TAG, "Exception while starting link probe: " + e);
907             // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that
908             // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer.
909             sendMgmtFrameEvent.OnFailure(WifiNative.SEND_MGMT_FRAME_ERROR_UNKNOWN);
910         }
911     }
912 
913     /**
914      * Clear all internal handles.
915      */
clearState()916     private void clearState() {
917         // Refresh handlers
918         mClientInterfaces.clear();
919         mWificondScanners.clear();
920         mPnoScanEventHandlers.clear();
921         mScanEventHandlers.clear();
922         mApInterfaces.clear();
923         mApInterfaceListeners.clear();
924         mSendMgmtFrameInProgress.set(false);
925     }
926 
927     /**
928      * Check if OWE (Enhanced Open) is supported on the device
929      *
930      * @return true if OWE is supported
931      */
isEnhancedOpenSupported()932     private boolean isEnhancedOpenSupported() {
933         if (mIsEnhancedOpenSupportedInitialized) {
934             return mIsEnhancedOpenSupported;
935         }
936 
937         // WifiNative handle might be null, check this here
938         if (mWifiNative == null) {
939             mWifiNative = mWifiInjector.getWifiNative();
940             if (mWifiNative == null) {
941                 return false;
942             }
943         }
944 
945         String iface = mWifiNative.getClientInterfaceName();
946         if (iface == null) {
947             // Client interface might not be initialized during boot or Wi-Fi off
948             return false;
949         }
950 
951         mIsEnhancedOpenSupportedInitialized = true;
952         mIsEnhancedOpenSupported = (mWifiNative.getSupportedFeatureSet(iface)
953                 & WIFI_FEATURE_OWE) != 0;
954         return mIsEnhancedOpenSupported;
955     }
956 }
957