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 static android.net.wifi.WifiManager.WIFI_FEATURE_CONTROL_ROAMING;
20
21import android.util.Log;
22
23import com.android.internal.annotations.VisibleForTesting;
24
25import 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 WifiStateMachine thread.
33 */
34public 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
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     */
57    public boolean getFirmwareRoamingInfo() {
58        mFirmwareRoamingSupported = false;
59        mMaxNumBlacklistBssid = INVALID_LIST_SIZE;
60        mMaxNumWhitelistSsid = INVALID_LIST_SIZE;
61
62        int fwFeatureSet = mWifiNative.getSupportedFeatureSet(mWifiNative.getClientInterfaceName());
63        Log.d(TAG, "Firmware supported feature set: " + Integer.toHexString(fwFeatureSet));
64
65        if ((fwFeatureSet & WIFI_FEATURE_CONTROL_ROAMING) == 0) {
66            Log.d(TAG, "Firmware roaming is not supported");
67            return true;
68        }
69
70        WifiNative.RoamingCapabilities roamingCap = new WifiNative.RoamingCapabilities();
71        if (mWifiNative.getRoamingCapabilities(mWifiNative.getClientInterfaceName(), roamingCap)) {
72            if (roamingCap.maxBlacklistSize < 0 || roamingCap.maxWhitelistSize < 0) {
73                Log.e(TAG, "Invalid firmware roaming capabilities: max num blacklist bssid="
74                        + roamingCap.maxBlacklistSize + " max num whitelist ssid="
75                        + roamingCap.maxWhitelistSize);
76            } else {
77                mFirmwareRoamingSupported = true;
78                mMaxNumBlacklistBssid = roamingCap.maxBlacklistSize;
79                mMaxNumWhitelistSsid = roamingCap.maxWhitelistSize;
80                Log.d(TAG, "Firmware roaming supported with capabilities: max num blacklist bssid="
81                        + mMaxNumBlacklistBssid + " max num whitelist ssid="
82                        + mMaxNumWhitelistSsid);
83                return true;
84            }
85        } else {
86            Log.e(TAG, "Failed to get firmware roaming capabilities");
87        }
88
89        return false;
90    }
91
92    /**
93     * Return if firmware roaming is supported.
94     */
95    public boolean isFirmwareRoamingSupported() {
96        return mFirmwareRoamingSupported;
97    }
98
99    /**
100     * Get the maximum size of BSSID blacklist firmware supports.
101     *
102     * @return INVALID_LIST_SIZE if firmware roaming is not supported, or
103     * maximum size of the BSSID blacklist firmware supports.
104     */
105    public int getMaxNumBlacklistBssid() {
106        if (mFirmwareRoamingSupported) {
107            return mMaxNumBlacklistBssid;
108        } else {
109            Log.e(TAG, "getMaxNumBlacklistBssid: Firmware roaming is not supported");
110            return INVALID_LIST_SIZE;
111        }
112    }
113
114    /**
115     * Get the maximum size of SSID whitelist firmware supports.
116     *
117     * @return INVALID_LIST_SIZE if firmware roaming is not supported, or
118     * maximum size of the SSID whitelist firmware supports.
119     */
120    public int getMaxNumWhitelistSsid() {
121        if (mFirmwareRoamingSupported) {
122            return mMaxNumWhitelistSsid;
123        } else {
124            Log.e(TAG, "getMaxNumWhitelistSsid: Firmware roaming is not supported");
125            return INVALID_LIST_SIZE;
126        }
127    }
128
129    /**
130     * Write firmware roaming configuration to firmware.
131     *
132     * @param blacklistBssids BSSIDs to be blacklisted
133     * @param whitelistSsids  SSIDs to be whitelisted
134     * @return true if succeeded, false otherwise.
135     */
136    public boolean setFirmwareRoamingConfiguration(ArrayList<String> blacklistBssids,
137            ArrayList<String> whitelistSsids) {
138        if (!mFirmwareRoamingSupported) {
139            Log.e(TAG, "Firmware roaming is not supported");
140            return false;
141        }
142
143        if (blacklistBssids == null || whitelistSsids == null) {
144            Log.e(TAG, "Invalid firmware roaming configuration settings");
145            return false;
146        }
147
148        int blacklistSize = blacklistBssids.size();
149        int whitelistSize = whitelistSsids.size();
150
151        if (blacklistSize > mMaxNumBlacklistBssid || whitelistSize > mMaxNumWhitelistSsid) {
152            Log.e(TAG, "Invalid BSSID blacklist size " + blacklistSize + " SSID whitelist size "
153                    + whitelistSize + ". Max blacklist size: " + mMaxNumBlacklistBssid
154                    + ", max whitelist size: " + mMaxNumWhitelistSsid);
155            return false;
156        }
157
158        WifiNative.RoamingConfig roamConfig = new WifiNative.RoamingConfig();
159        roamConfig.blacklistBssids = blacklistBssids;
160        roamConfig.whitelistSsids = whitelistSsids;
161
162        return mWifiNative.configureRoaming(mWifiNative.getClientInterfaceName(), roamConfig);
163    }
164
165    /**
166     * Remove the request |networkId| from supplicant if it's the current network,
167     * if the current configured network matches |networkId|.
168     *
169     * @param networkId network id of the network to be removed from supplicant.
170     */
171    public void removeNetworkIfCurrent(int networkId) {
172        mWifiNative.removeNetworkIfCurrent(mWifiNative.getClientInterfaceName(), networkId);
173    }
174}
175