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_CONTROL_ROAMING;
20 
21 import android.util.Log;
22 
23 import com.android.internal.annotations.VisibleForTesting;
24 
25 import java.util.ArrayList;
26 
27 /**
28  * This class provides helper functions for Wifi connectivity related modules to
29  * access WifiNative. It starts with firmware roaming. TODO(b/34819513): Move operations
30  * such as connection to network and legacy framework roaming here.
31  *
32  * NOTE: This class is not thread safe and should only be used from the ClientModeImpl thread.
33  */
34 public class WifiConnectivityHelper {
35     private static final String TAG = "WifiConnectivityHelper";
36     @VisibleForTesting
37     public static int INVALID_LIST_SIZE = -1;
38     private final WifiNative mWifiNative;
39     private boolean mFirmwareRoamingSupported = false;
40     private int mMaxNumBlacklistBssid = INVALID_LIST_SIZE;
41     private int mMaxNumWhitelistSsid = INVALID_LIST_SIZE;
42 
WifiConnectivityHelper(WifiNative wifiNative)43     WifiConnectivityHelper(WifiNative wifiNative) {
44         mWifiNative = wifiNative;
45     }
46 
47     /**
48      * Query firmware if it supports
49      * {@link android.net.wifi.WifiManager#WIFI_FEATURE_CONTROL_ROAMING}. If yes, get the firmware
50      * roaming capabilities. If firmware roaming is supported but we fail to get the roaming
51      * capabilities or the returned capability values are invalid, we fall back to framework
52      * roaming.
53      *
54      * @return true if succeed, false if firmware roaming is supported but fail to get valid
55      * roaming capabilities.
56      */
getFirmwareRoamingInfo()57     public boolean getFirmwareRoamingInfo() {
58         mFirmwareRoamingSupported = false;
59         mMaxNumBlacklistBssid = INVALID_LIST_SIZE;
60         mMaxNumWhitelistSsid = INVALID_LIST_SIZE;
61 
62         long fwFeatureSet =
63                 mWifiNative.getSupportedFeatureSet(mWifiNative.getClientInterfaceName());
64         Log.d(TAG, "Firmware supported feature set: " + Long.toHexString(fwFeatureSet));
65 
66         if ((fwFeatureSet & WIFI_FEATURE_CONTROL_ROAMING) == 0) {
67             Log.d(TAG, "Firmware roaming is not supported");
68             return true;
69         }
70 
71         WifiNative.RoamingCapabilities roamingCap = new WifiNative.RoamingCapabilities();
72         if (mWifiNative.getRoamingCapabilities(mWifiNative.getClientInterfaceName(), roamingCap)) {
73             if (roamingCap.maxBlocklistSize < 0 || roamingCap.maxAllowlistSize < 0) {
74                 Log.e(TAG, "Invalid firmware roaming capabilities: max num blacklist bssid="
75                         + roamingCap.maxBlocklistSize + " max num whitelist ssid="
76                         + roamingCap.maxAllowlistSize);
77             } else {
78                 mFirmwareRoamingSupported = true;
79                 mMaxNumBlacklistBssid = roamingCap.maxBlocklistSize;
80                 mMaxNumWhitelistSsid = roamingCap.maxAllowlistSize;
81                 Log.d(TAG, "Firmware roaming supported with capabilities: max num blacklist bssid="
82                         + mMaxNumBlacklistBssid + " max num whitelist ssid="
83                         + mMaxNumWhitelistSsid);
84                 return true;
85             }
86         } else {
87             Log.e(TAG, "Failed to get firmware roaming capabilities");
88         }
89 
90         return false;
91     }
92 
93     /**
94      * Return if firmware roaming is supported.
95      */
isFirmwareRoamingSupported()96     public boolean isFirmwareRoamingSupported() {
97         return mFirmwareRoamingSupported;
98     }
99 
100     /**
101      * Get the maximum size of BSSID blacklist firmware supports.
102      *
103      * @return INVALID_LIST_SIZE if firmware roaming is not supported, or
104      * maximum size of the BSSID blacklist firmware supports.
105      */
getMaxNumBlacklistBssid()106     public int getMaxNumBlacklistBssid() {
107         if (mFirmwareRoamingSupported) {
108             return mMaxNumBlacklistBssid;
109         } else {
110             Log.e(TAG, "getMaxNumBlacklistBssid: Firmware roaming is not supported");
111             return INVALID_LIST_SIZE;
112         }
113     }
114 
115     /**
116      * Get the maximum size of SSID whitelist firmware supports.
117      *
118      * @return INVALID_LIST_SIZE if firmware roaming is not supported, or
119      * maximum size of the SSID whitelist firmware supports.
120      */
getMaxNumWhitelistSsid()121     public int getMaxNumWhitelistSsid() {
122         if (mFirmwareRoamingSupported) {
123             return mMaxNumWhitelistSsid;
124         } else {
125             Log.e(TAG, "getMaxNumWhitelistSsid: Firmware roaming is not supported");
126             return INVALID_LIST_SIZE;
127         }
128     }
129 
130     /**
131      * Write firmware roaming configuration to firmware.
132      *
133      * @param blacklistBssids BSSIDs to be blacklisted
134      * @param whitelistSsids  SSIDs to be whitelisted
135      * @return true if succeeded, false otherwise.
136      */
setFirmwareRoamingConfiguration(ArrayList<String> blacklistBssids, ArrayList<String> whitelistSsids)137     public boolean setFirmwareRoamingConfiguration(ArrayList<String> blacklistBssids,
138             ArrayList<String> whitelistSsids) {
139         if (!mFirmwareRoamingSupported) {
140             Log.e(TAG, "Firmware roaming is not supported");
141             return false;
142         }
143 
144         if (blacklistBssids == null || whitelistSsids == null) {
145             Log.e(TAG, "Invalid firmware roaming configuration settings");
146             return false;
147         }
148 
149         int blacklistSize = blacklistBssids.size();
150         int whitelistSize = whitelistSsids.size();
151 
152         if (blacklistSize > mMaxNumBlacklistBssid || whitelistSize > mMaxNumWhitelistSsid) {
153             Log.e(TAG, "Invalid BSSID blacklist size " + blacklistSize + " SSID whitelist size "
154                     + whitelistSize + ". Max blacklist size: " + mMaxNumBlacklistBssid
155                     + ", max whitelist size: " + mMaxNumWhitelistSsid);
156             return false;
157         }
158 
159         WifiNative.RoamingConfig roamConfig = new WifiNative.RoamingConfig();
160         roamConfig.blocklistBssids = blacklistBssids;
161         roamConfig.allowlistSsids = whitelistSsids;
162 
163         return mWifiNative.configureRoaming(mWifiNative.getClientInterfaceName(), roamConfig);
164     }
165 
166     /**
167      * Remove the request |networkId| from supplicant if it's the current network,
168      * if the current configured network matches |networkId|.
169      *
170      * @param networkId network id of the network to be removed from supplicant.
171      */
removeNetworkIfCurrent(int networkId)172     public void removeNetworkIfCurrent(int networkId) {
173         mWifiNative.removeNetworkIfCurrent(mWifiNative.getClientInterfaceName(), networkId);
174     }
175 }
176