WificondControl.java revision f4b53ff21ce0aa25131222d0cd15cc4a5e8c0c4f
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
17package com.android.server.wifi;
18
19import android.net.wifi.IApInterface;
20import android.net.wifi.IClientInterface;
21import android.net.wifi.IWifiScannerImpl;
22import android.net.wifi.IWificond;
23import android.net.wifi.ScanResult;
24import android.net.wifi.WifiSsid;
25import android.os.Binder;
26import android.os.RemoteException;
27import android.util.Log;
28
29import com.android.server.wifi.hotspot2.NetworkDetail;
30import com.android.server.wifi.util.InformationElementUtil;
31import com.android.server.wifi.util.NativeUtil;
32import com.android.server.wifi.wificond.NativeScanResult;
33
34import java.util.ArrayList;
35
36/**
37 * This class provides methods for WifiNative to send control commands to wificond.
38 * NOTE: This class should only be used from WifiNative.
39 */
40public class WificondControl {
41
42    private static final String TAG = "WificondControl";
43    private static final int MAC_ADDR_LEN = 6;
44    private IWificond mWificond;
45    private IClientInterface mClientInterface;
46    private IApInterface mApInterface;
47    private IWifiScannerImpl mWificondScanner;
48    private WifiInjector mWifiInjector;
49
50    WificondControl(WifiInjector wifiInjector) {
51        mWifiInjector = wifiInjector;
52    }
53
54    /**
55    * Setup driver for client mode via wificond.
56    * @return An IClientInterface as wificond client interface binder handler.
57    * Returns null on failure.
58    */
59    public IClientInterface setupDriverForClientMode() {
60        mWificond = mWifiInjector.makeWificond();
61        if (mWificond == null) {
62            Log.e(TAG, "Failed to get reference to wificond");
63            return null;
64        }
65
66        IClientInterface clientInterface = null;
67        try {
68            clientInterface = mWificond.createClientInterface();
69        } catch (RemoteException e1) {
70            Log.e(TAG, "Failed to get IClientInterface due to remote exception");
71            return null;
72        }
73
74        if (clientInterface == null) {
75            Log.e(TAG, "Could not get IClientInterface instance from wificond");
76            return null;
77        }
78        Binder.allowBlocking(clientInterface.asBinder());
79
80        // Refresh Handlers
81        mClientInterface = clientInterface;
82        try {
83            mWificondScanner = mClientInterface.getWifiScannerImpl();
84        } catch (RemoteException e) {
85            Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
86        }
87
88        return clientInterface;
89    }
90
91    /**
92    * Setup driver for softAp mode via wificond.
93    * @return An IApInterface as wificond Ap interface binder handler.
94    * Returns null on failure.
95    */
96    public IApInterface setupDriverForSoftApMode() {
97        mWificond = mWifiInjector.makeWificond();
98        if (mWificond == null) {
99            Log.e(TAG, "Failed to get reference to wificond");
100            return null;
101        }
102
103        IApInterface apInterface = null;
104        try {
105            apInterface = mWificond.createApInterface();
106        } catch (RemoteException e1) {
107            Log.e(TAG, "Failed to get IApInterface due to remote exception");
108            return null;
109        }
110
111        if (apInterface == null) {
112            Log.e(TAG, "Could not get IApInterface instance from wificond");
113            return null;
114        }
115        Binder.allowBlocking(apInterface.asBinder());
116
117        // Refresh Handlers
118        mApInterface = apInterface;
119        mWificondScanner = null;
120
121        return apInterface;
122    }
123
124    /**
125    * Teardown all interfaces configured in wificond.
126    * @return Returns true on success.
127    */
128    public boolean tearDownInterfaces() {
129        // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
130        // could be used to cleanup before we setup any interfaces.
131        mWificond = mWifiInjector.makeWificond();
132        if (mWificond == null) {
133            Log.e(TAG, "Failed to get reference to wificond");
134            return false;
135        }
136
137        try {
138            mWificond.tearDownInterfaces();
139            return true;
140        } catch (RemoteException e) {
141            Log.e(TAG, "Failed to tear down interfaces due to remote exception");
142        }
143        return false;
144    }
145
146    /**
147    * Disable wpa_supplicant via wificond.
148    * @return Returns true on success.
149    */
150    public boolean disableSupplicant() {
151        if (mClientInterface == null) {
152            Log.e(TAG, "No valid wificond client interface handler");
153            return false;
154        }
155        try {
156            return mClientInterface.disableSupplicant();
157        } catch (RemoteException e) {
158            Log.e(TAG, "Failed to disable supplicant due to remote exception");
159        }
160        return false;
161    }
162
163    /**
164    * Enable wpa_supplicant via wificond.
165    * @return Returns true on success.
166    */
167    public boolean enableSupplicant() {
168        if (mClientInterface == null) {
169            Log.e(TAG, "No valid wificond client interface handler");
170            return false;
171        }
172
173        try {
174            return mClientInterface.enableSupplicant();
175        } catch (RemoteException e) {
176            Log.e(TAG, "Failed to enable supplicant due to remote exception");
177        }
178        return false;
179    }
180
181    /**
182    * Request signal polling to wificond.
183    * Returns an SignalPollResult object.
184    * Returns null on failure.
185    */
186    public WifiNative.SignalPollResult signalPoll() {
187        if (mClientInterface == null) {
188            Log.e(TAG, "No valid wificond client interface handler");
189            return null;
190        }
191
192        int[] resultArray;
193        try {
194            resultArray = mClientInterface.signalPoll();
195            if (resultArray == null || resultArray.length != 3) {
196                Log.e(TAG, "Invalid signal poll result from wificond");
197                return null;
198            }
199        } catch (RemoteException e) {
200            Log.e(TAG, "Failed to do signal polling  due to remote exception");
201            return null;
202        }
203        WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult();
204        pollResult.currentRssi = resultArray[0];
205        pollResult.txBitrate = resultArray[1];
206        pollResult.associationFrequency = resultArray[2];
207        return pollResult;
208    }
209
210    /**
211    * Fetch TX packet counters on current connection from wificond.
212    * Returns an TxPacketCounters object.
213    * Returns null on failure.
214    */
215    public WifiNative.TxPacketCounters getTxPacketCounters() {
216        if (mClientInterface == null) {
217            Log.e(TAG, "No valid wificond client interface handler");
218            return null;
219        }
220
221        int[] resultArray;
222        try {
223            resultArray = mClientInterface.getPacketCounters();
224            if (resultArray == null || resultArray.length != 2) {
225                Log.e(TAG, "Invalid signal poll result from wificond");
226                return null;
227            }
228        } catch (RemoteException e) {
229            Log.e(TAG, "Failed to do signal polling  due to remote exception");
230            return null;
231        }
232        WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters();
233        counters.txSucceeded = resultArray[0];
234        counters.txFailed = resultArray[1];
235        return counters;
236    }
237
238    /**
239    * Fetch the latest scan result from kernel via wificond.
240    * @return Returns an ArrayList of ScanDetail.
241    * Returns an empty ArrayList on failure.
242    */
243    public ArrayList<ScanDetail> getScanResults() {
244        ArrayList<ScanDetail> results = new ArrayList<>();
245        if (mWificondScanner == null) {
246            Log.e(TAG, "No valid wificond scanner interface handler");
247            return results;
248        }
249        try {
250            NativeScanResult[] nativeResults = mWificondScanner.getScanResults();
251            for (NativeScanResult result : nativeResults) {
252                WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(new String(result.ssid));
253                String bssid = NativeUtil.macAddressFromByteArray(result.bssid);
254                ScanResult.InformationElement[] ies =
255                        InformationElementUtil.parseInformationElements(result.infoElement);
256                InformationElementUtil.Capabilities capabilities =
257                        new InformationElementUtil.Capabilities();
258                capabilities.from(ies, result.capability);
259                String flags = capabilities.generateCapabilitiesString();
260                NetworkDetail networkDetail =
261                        new NetworkDetail(bssid, ies, null, result.frequency);
262
263                if (!wifiSsid.toString().equals(networkDetail.getTrimmedSSID())) {
264                    Log.e(TAG, "Inconsistent SSID on BSSID: " + bssid);
265                    continue;
266                }
267                ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
268                        result.signalMbm / 100, result.frequency, result.tsf, ies, null);
269                results.add(scanDetail);
270            }
271        } catch (RemoteException e1) {
272            Log.e(TAG, "Failed to create ScanDetail ArrayList");
273        }
274        return results;
275    }
276}
277