• 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 android.net.wifi.IApInterface;
20 import android.net.wifi.IClientInterface;
21 import android.net.wifi.IPnoScanEvent;
22 import android.net.wifi.IScanEvent;
23 import android.net.wifi.IWifiScannerImpl;
24 import android.net.wifi.IWificond;
25 import android.net.wifi.ScanResult;
26 import android.net.wifi.WifiScanner;
27 import android.net.wifi.WifiSsid;
28 import android.os.Binder;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 import com.android.server.wifi.hotspot2.NetworkDetail;
33 import com.android.server.wifi.util.InformationElementUtil;
34 import com.android.server.wifi.util.NativeUtil;
35 import com.android.server.wifi.util.ScanResultUtil;
36 import com.android.server.wifi.wificond.ChannelSettings;
37 import com.android.server.wifi.wificond.HiddenNetwork;
38 import com.android.server.wifi.wificond.NativeScanResult;
39 import com.android.server.wifi.wificond.PnoNetwork;
40 import com.android.server.wifi.wificond.PnoSettings;
41 import com.android.server.wifi.wificond.SingleScanSettings;
42 
43 import java.util.ArrayList;
44 import java.util.Set;
45 
46 /**
47  * This class provides methods for WifiNative to send control commands to wificond.
48  * NOTE: This class should only be used from WifiNative.
49  */
50 public class WificondControl {
51     private boolean mVerboseLoggingEnabled = false;
52 
53     private static final String TAG = "WificondControl";
54 
55     /* Get scan results for a single scan */
56     public static final int SCAN_TYPE_SINGLE_SCAN = 0;
57 
58     /* Get scan results for Pno Scan */
59     public static final int SCAN_TYPE_PNO_SCAN = 1;
60 
61     private WifiInjector mWifiInjector;
62     private WifiMonitor mWifiMonitor;
63     private final CarrierNetworkConfig mCarrierNetworkConfig;
64 
65     // Cached wificond binder handlers.
66     private IWificond mWificond;
67     private IClientInterface mClientInterface;
68     private IApInterface mApInterface;
69     private IWifiScannerImpl mWificondScanner;
70     private IScanEvent mScanEventHandler;
71     private IPnoScanEvent mPnoScanEventHandler;
72 
73     private String mClientInterfaceName;
74 
75 
76     private class ScanEventHandler extends IScanEvent.Stub {
77         @Override
OnScanResultReady()78         public void OnScanResultReady() {
79             Log.d(TAG, "Scan result ready event");
80             mWifiMonitor.broadcastScanResultEvent(mClientInterfaceName);
81         }
82 
83         @Override
OnScanFailed()84         public void OnScanFailed() {
85             Log.d(TAG, "Scan failed event");
86             mWifiMonitor.broadcastScanFailedEvent(mClientInterfaceName);
87         }
88     }
89 
WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, CarrierNetworkConfig carrierNetworkConfig)90     WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor,
91             CarrierNetworkConfig carrierNetworkConfig) {
92         mWifiInjector = wifiInjector;
93         mWifiMonitor = wifiMonitor;
94         mCarrierNetworkConfig = carrierNetworkConfig;
95     }
96 
97     private class PnoScanEventHandler extends IPnoScanEvent.Stub {
98         @Override
OnPnoNetworkFound()99         public void OnPnoNetworkFound() {
100             Log.d(TAG, "Pno scan result event");
101             mWifiMonitor.broadcastPnoScanResultEvent(mClientInterfaceName);
102             mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount();
103         }
104 
105         @Override
OnPnoScanFailed()106         public void OnPnoScanFailed() {
107             Log.d(TAG, "Pno Scan failed event");
108             mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
109         }
110 
111         @Override
OnPnoScanOverOffloadStarted()112         public void OnPnoScanOverOffloadStarted() {
113             Log.d(TAG, "Pno scan over offload started");
114             mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount();
115         }
116 
117         @Override
OnPnoScanOverOffloadFailed(int reason)118         public void OnPnoScanOverOffloadFailed(int reason) {
119             Log.d(TAG, "Pno scan over offload failed");
120             mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount();
121         }
122     }
123 
124     /** Enable or disable verbose logging of WificondControl.
125      *  @param enable True to enable verbose logging. False to disable verbose logging.
126      */
enableVerboseLogging(boolean enable)127     public void enableVerboseLogging(boolean enable) {
128         mVerboseLoggingEnabled = enable;
129     }
130 
131     /**
132     * Setup driver for client mode via wificond.
133     * @return An IClientInterface as wificond client interface binder handler.
134     * Returns null on failure.
135     */
setupDriverForClientMode()136     public IClientInterface setupDriverForClientMode() {
137         Log.d(TAG, "Setting up driver for client mode");
138         mWificond = mWifiInjector.makeWificond();
139         if (mWificond == null) {
140             Log.e(TAG, "Failed to get reference to wificond");
141             return null;
142         }
143 
144         IClientInterface clientInterface = null;
145         try {
146             clientInterface = mWificond.createClientInterface();
147         } catch (RemoteException e1) {
148             Log.e(TAG, "Failed to get IClientInterface due to remote exception");
149             return null;
150         }
151 
152         if (clientInterface == null) {
153             Log.e(TAG, "Could not get IClientInterface instance from wificond");
154             return null;
155         }
156         Binder.allowBlocking(clientInterface.asBinder());
157 
158         // Refresh Handlers
159         mClientInterface = clientInterface;
160         try {
161             mClientInterfaceName = clientInterface.getInterfaceName();
162             mWificondScanner = mClientInterface.getWifiScannerImpl();
163             if (mWificondScanner == null) {
164                 Log.e(TAG, "Failed to get WificondScannerImpl");
165                 return null;
166             }
167             Binder.allowBlocking(mWificondScanner.asBinder());
168             mScanEventHandler = new ScanEventHandler();
169             mWificondScanner.subscribeScanEvents(mScanEventHandler);
170             mPnoScanEventHandler = new PnoScanEventHandler();
171             mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler);
172         } catch (RemoteException e) {
173             Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
174         }
175 
176         return clientInterface;
177     }
178 
179     /**
180     * Setup driver for softAp mode via wificond.
181     * @return An IApInterface as wificond Ap interface binder handler.
182     * Returns null on failure.
183     */
setupDriverForSoftApMode()184     public IApInterface setupDriverForSoftApMode() {
185         Log.d(TAG, "Setting up driver for soft ap mode");
186         mWificond = mWifiInjector.makeWificond();
187         if (mWificond == null) {
188             Log.e(TAG, "Failed to get reference to wificond");
189             return null;
190         }
191 
192         IApInterface apInterface = null;
193         try {
194             apInterface = mWificond.createApInterface();
195         } catch (RemoteException e1) {
196             Log.e(TAG, "Failed to get IApInterface due to remote exception");
197             return null;
198         }
199 
200         if (apInterface == null) {
201             Log.e(TAG, "Could not get IApInterface instance from wificond");
202             return null;
203         }
204         Binder.allowBlocking(apInterface.asBinder());
205 
206         // Refresh Handlers
207         mApInterface = apInterface;
208 
209         return apInterface;
210     }
211 
212     /**
213     * Teardown all interfaces configured in wificond.
214     * @return Returns true on success.
215     */
tearDownInterfaces()216     public boolean tearDownInterfaces() {
217         Log.d(TAG, "tearing down interfaces in wificond");
218         // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
219         // could be used to cleanup before we setup any interfaces.
220         mWificond = mWifiInjector.makeWificond();
221         if (mWificond == null) {
222             Log.e(TAG, "Failed to get reference to wificond");
223             return false;
224         }
225 
226         try {
227             if (mWificondScanner != null) {
228                 mWificondScanner.unsubscribeScanEvents();
229                 mWificondScanner.unsubscribePnoScanEvents();
230             }
231             mWificond.tearDownInterfaces();
232 
233             // Refresh handlers
234             mClientInterface = null;
235             mWificondScanner = null;
236             mPnoScanEventHandler = null;
237             mScanEventHandler = null;
238             mApInterface = null;
239 
240             return true;
241         } catch (RemoteException e) {
242             Log.e(TAG, "Failed to tear down interfaces due to remote exception");
243         }
244 
245         return false;
246     }
247 
248     /**
249     * Disable wpa_supplicant via wificond.
250     * @return Returns true on success.
251     */
disableSupplicant()252     public boolean disableSupplicant() {
253         if (mClientInterface == null) {
254             Log.e(TAG, "No valid wificond client interface handler");
255             return false;
256         }
257         try {
258             return mClientInterface.disableSupplicant();
259         } catch (RemoteException e) {
260             Log.e(TAG, "Failed to disable supplicant due to remote exception");
261         }
262         return false;
263     }
264 
265     /**
266     * Enable wpa_supplicant via wificond.
267     * @return Returns true on success.
268     */
enableSupplicant()269     public boolean enableSupplicant() {
270         if (mClientInterface == null) {
271             Log.e(TAG, "No valid wificond client interface handler");
272             return false;
273         }
274 
275         try {
276             return mClientInterface.enableSupplicant();
277         } catch (RemoteException e) {
278             Log.e(TAG, "Failed to enable supplicant due to remote exception");
279         }
280         return false;
281     }
282 
283     /**
284     * Request signal polling to wificond.
285     * Returns an SignalPollResult object.
286     * Returns null on failure.
287     */
signalPoll()288     public WifiNative.SignalPollResult signalPoll() {
289         if (mClientInterface == null) {
290             Log.e(TAG, "No valid wificond client interface handler");
291             return null;
292         }
293 
294         int[] resultArray;
295         try {
296             resultArray = mClientInterface.signalPoll();
297             if (resultArray == null || resultArray.length != 3) {
298                 Log.e(TAG, "Invalid signal poll result from wificond");
299                 return null;
300             }
301         } catch (RemoteException e) {
302             Log.e(TAG, "Failed to do signal polling due to remote exception");
303             return null;
304         }
305         WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult();
306         pollResult.currentRssi = resultArray[0];
307         pollResult.txBitrate = resultArray[1];
308         pollResult.associationFrequency = resultArray[2];
309         return pollResult;
310     }
311 
312     /**
313     * Fetch TX packet counters on current connection from wificond.
314     * Returns an TxPacketCounters object.
315     * Returns null on failure.
316     */
getTxPacketCounters()317     public WifiNative.TxPacketCounters getTxPacketCounters() {
318         if (mClientInterface == null) {
319             Log.e(TAG, "No valid wificond client interface handler");
320             return null;
321         }
322 
323         int[] resultArray;
324         try {
325             resultArray = mClientInterface.getPacketCounters();
326             if (resultArray == null || resultArray.length != 2) {
327                 Log.e(TAG, "Invalid signal poll result from wificond");
328                 return null;
329             }
330         } catch (RemoteException e) {
331             Log.e(TAG, "Failed to do signal polling due to remote exception");
332             return null;
333         }
334         WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters();
335         counters.txSucceeded = resultArray[0];
336         counters.txFailed = resultArray[1];
337         return counters;
338     }
339 
340     /**
341     * Fetch the latest scan result from kernel via wificond.
342     * @return Returns an ArrayList of ScanDetail.
343     * Returns an empty ArrayList on failure.
344     */
getScanResults(int scanType)345     public ArrayList<ScanDetail> getScanResults(int scanType) {
346         ArrayList<ScanDetail> results = new ArrayList<>();
347         if (mWificondScanner == null) {
348             Log.e(TAG, "No valid wificond scanner interface handler");
349             return results;
350         }
351         try {
352             NativeScanResult[] nativeResults;
353             if (scanType == SCAN_TYPE_SINGLE_SCAN) {
354                 nativeResults = mWificondScanner.getScanResults();
355             } else {
356                 nativeResults = mWificondScanner.getPnoScanResults();
357             }
358             for (NativeScanResult result : nativeResults) {
359                 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
360                 String bssid;
361                 try {
362                     bssid = NativeUtil.macAddressFromByteArray(result.bssid);
363                 } catch (IllegalArgumentException e) {
364                     Log.e(TAG, "Illegal argument " + result.bssid, e);
365                     continue;
366                 }
367                 if (bssid == null) {
368                     Log.e(TAG, "Illegal null bssid");
369                     continue;
370                 }
371                 ScanResult.InformationElement[] ies =
372                         InformationElementUtil.parseInformationElements(result.infoElement);
373                 InformationElementUtil.Capabilities capabilities =
374                         new InformationElementUtil.Capabilities();
375                 capabilities.from(ies, result.capability);
376                 String flags = capabilities.generateCapabilitiesString();
377                 NetworkDetail networkDetail;
378                 try {
379                     networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
380                 } catch (IllegalArgumentException e) {
381                     Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
382                     continue;
383                 }
384 
385                 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
386                         result.signalMbm / 100, result.frequency, result.tsf, ies, null);
387                 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
388                 // network and it uses EAP.
389                 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
390                         && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
391                     scanDetail.getScanResult().isCarrierAp = true;
392                     scanDetail.getScanResult().carrierApEapType =
393                             mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
394                     scanDetail.getScanResult().carrierName =
395                             mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
396                 }
397                 results.add(scanDetail);
398             }
399         } catch (RemoteException e1) {
400             Log.e(TAG, "Failed to create ScanDetail ArrayList");
401         }
402         if (mVerboseLoggingEnabled) {
403             Log.d(TAG, "get " + results.size() + " scan results from wificond");
404         }
405 
406         return results;
407     }
408 
409     /**
410      * Start a scan using wificond for the given parameters.
411      * @param freqs list of frequencies to scan for, if null scan all supported channels.
412      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
413      * @return Returns true on success.
414      */
scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs)415     public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
416         if (mWificondScanner == null) {
417             Log.e(TAG, "No valid wificond scanner interface handler");
418             return false;
419         }
420         SingleScanSettings settings = new SingleScanSettings();
421         settings.channelSettings  = new ArrayList<>();
422         settings.hiddenNetworks  = new ArrayList<>();
423 
424         if (freqs != null) {
425             for (Integer freq : freqs) {
426                 ChannelSettings channel = new ChannelSettings();
427                 channel.frequency = freq;
428                 settings.channelSettings.add(channel);
429             }
430         }
431         if (hiddenNetworkSSIDs != null) {
432             for (String ssid : hiddenNetworkSSIDs) {
433                 HiddenNetwork network = new HiddenNetwork();
434                 try {
435                     network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid));
436                 } catch (IllegalArgumentException e) {
437                     Log.e(TAG, "Illegal argument " + ssid, e);
438                     continue;
439                 }
440                 settings.hiddenNetworks.add(network);
441             }
442         }
443 
444         try {
445             return mWificondScanner.scan(settings);
446         } catch (RemoteException e1) {
447             Log.e(TAG, "Failed to request scan due to remote exception");
448         }
449         return false;
450     }
451 
452     /**
453      * Start PNO scan.
454      * @param pnoSettings Pno scan configuration.
455      * @return true on success.
456      */
startPnoScan(WifiNative.PnoSettings pnoSettings)457     public boolean startPnoScan(WifiNative.PnoSettings pnoSettings) {
458         if (mWificondScanner == null) {
459             Log.e(TAG, "No valid wificond scanner interface handler");
460             return false;
461         }
462         PnoSettings settings = new PnoSettings();
463         settings.pnoNetworks  = new ArrayList<>();
464         settings.intervalMs = pnoSettings.periodInMs;
465         settings.min2gRssi = pnoSettings.min24GHzRssi;
466         settings.min5gRssi = pnoSettings.min5GHzRssi;
467         if (pnoSettings.networkList != null) {
468             for (WifiNative.PnoNetwork network : pnoSettings.networkList) {
469                 PnoNetwork condNetwork = new PnoNetwork();
470                 condNetwork.isHidden = (network.flags
471                         & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0;
472                 try {
473                     condNetwork.ssid =
474                             NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid));
475                 } catch (IllegalArgumentException e) {
476                     Log.e(TAG, "Illegal argument " + network.ssid, e);
477                     continue;
478                 }
479                 settings.pnoNetworks.add(condNetwork);
480             }
481         }
482 
483         try {
484             boolean success = mWificondScanner.startPnoScan(settings);
485             mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount();
486             if (!success) {
487                 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
488             }
489             return success;
490         } catch (RemoteException e1) {
491             Log.e(TAG, "Failed to start pno scan due to remote exception");
492         }
493         return false;
494     }
495 
496     /**
497      * Stop PNO scan.
498      * @return true on success.
499      */
stopPnoScan()500     public boolean stopPnoScan() {
501         if (mWificondScanner == null) {
502             Log.e(TAG, "No valid wificond scanner interface handler");
503             return false;
504         }
505         try {
506             return mWificondScanner.stopPnoScan();
507         } catch (RemoteException e1) {
508             Log.e(TAG, "Failed to stop pno scan due to remote exception");
509         }
510         return false;
511     }
512 
513     /**
514      * Abort ongoing single scan.
515      */
abortScan()516     public void abortScan() {
517         if (mWificondScanner == null) {
518             Log.e(TAG, "No valid wificond scanner interface handler");
519             return;
520         }
521         try {
522             mWificondScanner.abortScan();
523         } catch (RemoteException e1) {
524             Log.e(TAG, "Failed to request abortScan due to remote exception");
525         }
526     }
527 
528 }
529