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