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