1 /* 2 * Copyright (C) 2019 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_MBO; 20 import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE; 21 22 import android.telephony.PhoneStateListener; 23 import android.telephony.TelephonyManager; 24 import android.util.Log; 25 26 import com.android.server.wifi.SupplicantStaIfaceHal.MboAssocDisallowedReasonCode; 27 28 import java.util.BitSet; 29 30 /** 31 * MboOceController is responsible for controlling MBO and OCE operations. 32 */ 33 public class MboOceController { 34 private static final String TAG = "MboOceController"; 35 36 /** State of MBO/OCE module. */ 37 private boolean mEnabled = false; 38 private boolean mIsMboSupported = false; 39 private boolean mIsOceSupported = false; 40 private boolean mVerboseLoggingEnabled = false; 41 42 private final TelephonyManager mTelephonyManager; 43 private final ActiveModeWarden mActiveModeWarden; 44 private final WifiThreadRunner mWifiThreadRunner; 45 46 /** 47 * Create new instance of MboOceController. 48 */ MboOceController(TelephonyManager telephonyManager, ActiveModeWarden activeModeWarden, WifiThreadRunner wifiThreadRunner)49 public MboOceController(TelephonyManager telephonyManager, ActiveModeWarden activeModeWarden, 50 WifiThreadRunner wifiThreadRunner) { 51 mTelephonyManager = telephonyManager; 52 mActiveModeWarden = activeModeWarden; 53 mWifiThreadRunner = wifiThreadRunner; 54 } 55 56 /** 57 * Enable MBO and OCE functionality. 58 */ enable()59 public void enable() { 60 ClientModeManager clientModeManager = 61 mActiveModeWarden.getPrimaryClientModeManagerNullable(); 62 if (clientModeManager == null) { 63 return; 64 } 65 BitSet supportedFeatures = clientModeManager.getSupportedFeaturesBitSet(); 66 mIsMboSupported = supportedFeatures.get(WIFI_FEATURE_MBO); 67 mIsOceSupported = supportedFeatures.get(WIFI_FEATURE_OCE); 68 mEnabled = true; 69 if (mVerboseLoggingEnabled) { 70 Log.d(TAG, "Enable MBO-OCE MBO support: " + mIsMboSupported 71 + " OCE support: " + mIsOceSupported); 72 } 73 if (mIsMboSupported) { 74 // Register for data connection state change events (Cellular). 75 mTelephonyManager.listen(mDataConnectionStateListener, 76 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); 77 } 78 } 79 80 /** 81 * Disable MBO and OCE functionality. 82 */ disable()83 public void disable() { 84 if (mVerboseLoggingEnabled) { 85 Log.d(TAG, "Disable MBO-OCE"); 86 } 87 if (mIsMboSupported) { 88 // Un-register for data connection state change events (Cellular). 89 mTelephonyManager.listen(mDataConnectionStateListener, PhoneStateListener.LISTEN_NONE); 90 } 91 mEnabled = false; 92 } 93 94 /** 95 * Enable/Disable verbose logging. 96 * 97 * @param verbose true to enable and false to disable. 98 */ enableVerboseLogging(boolean verbose)99 public void enableVerboseLogging(boolean verbose) { 100 mVerboseLoggingEnabled = verbose; 101 } 102 103 /** 104 * Listen for changes to the data connection state (Cellular). 105 */ 106 private PhoneStateListener mDataConnectionStateListener = new PhoneStateListener(){ 107 public void onDataConnectionStateChanged(int state, int networkType) { 108 mWifiThreadRunner.post( 109 () -> { 110 boolean dataAvailable; 111 ClientModeManager clientModeManager = 112 mActiveModeWarden.getPrimaryClientModeManagerNullable(); 113 if (clientModeManager == null) { 114 return; 115 } 116 if (!mEnabled) { 117 Log.e(TAG, "onDataConnectionStateChanged called when MBO is " 118 + "disabled!!"); 119 return; 120 } 121 if (state == TelephonyManager.DATA_CONNECTED) { 122 dataAvailable = true; 123 } else if (state == TelephonyManager.DATA_DISCONNECTED) { 124 dataAvailable = false; 125 } else { 126 Log.e(TAG, "onDataConnectionStateChanged unexpected State: " + state); 127 return; 128 } 129 if (mVerboseLoggingEnabled) { 130 Log.d(TAG, "Cell Data: " + dataAvailable); 131 } 132 clientModeManager.setMboCellularDataStatus(dataAvailable); 133 }, TAG + "#onDataConnectionStateChanged" 134 ); 135 } 136 }; 137 138 /** 139 * BtmFrameData carries the data retried from received BTM 140 * request frame handled in supplicant. 141 */ 142 public static class BtmFrameData { 143 public @MboOceConstants.BtmResponseStatus int mStatus = 144 MboOceConstants.BTM_RESPONSE_STATUS_INVALID; 145 public int mBssTmDataFlagsMask = 0; 146 public long mBlockListDurationMs = 0; 147 public @MboOceConstants.MboTransitionReason int mTransitionReason = 148 MboOceConstants.MBO_TRANSITION_REASON_INVALID; 149 public @MboOceConstants.MboCellularDataConnectionPreference int mCellPreference = 150 MboOceConstants.MBO_CELLULAR_DATA_CONNECTION_INVALID; 151 152 @Override toString()153 public String toString() { 154 return new StringBuilder("BtmFrameData status=").append(mStatus).append( 155 ", flags=").append(mBssTmDataFlagsMask).append( 156 ", assocRetryDelay=").append(mBlockListDurationMs).append( 157 ", transitionReason=").append(mTransitionReason).append( 158 ", cellPref=").append(mCellPreference).toString(); 159 } 160 } 161 162 /** 163 * OceRssiBasedAssocRejectAttr is extracted from (Re-)Association response frame from an OCE AP 164 * to indicate that the AP has rejected the (Re-)Association request on the basis of 165 * insufficient RSSI. 166 * Refer OCE spec v1.0 section 4.2.2 Table 7. 167 */ 168 public static class OceRssiBasedAssocRejectAttr { 169 /* 170 * Delta RSSI - The difference in dB between the minimum RSSI at which 171 * the AP would accept a (Re-)Association request from the STA before 172 * Retry Delay expires and the AP's measurement of the RSSI at which the 173 * (Re-)Association request was received. 174 */ 175 public int mDeltaRssi; 176 /* 177 * Retry Delay - The time period in seconds for which the AP will not 178 * accept any subsequent (Re-)Association requests from the STA, unless 179 * the received RSSI has improved by Delta RSSI. 180 */ 181 public int mRetryDelayS; 182 OceRssiBasedAssocRejectAttr(int deltaRssi, int retryDelayS)183 public OceRssiBasedAssocRejectAttr(int deltaRssi, int retryDelayS) { 184 this.mDeltaRssi = deltaRssi; 185 this.mRetryDelayS = retryDelayS; 186 } 187 188 @Override toString()189 public String toString() { 190 return new StringBuilder("OceRssiBasedAssocRejectAttr Delta Rssi=") 191 .append(mDeltaRssi).append( 192 ", Retry Delay=").append(mRetryDelayS).toString(); 193 } 194 } 195 196 /** 197 * MboAssocDisallowedAttr is extracted from (Re-)Association response frame from the MBO AP 198 * to indicate that the AP is not accepting new associations. 199 * Refer MBO spec v1.2 section 4.2.4 Table 13 for the details of reason code. 200 */ 201 public static class MboAssocDisallowedAttr { 202 /* 203 * Reason Code - The reason why the AP is not accepting new 204 * associations. 205 */ 206 public @MboOceConstants.MboAssocDisallowedReasonCode int mReasonCode; 207 MboAssocDisallowedAttr(int reasonCode)208 public MboAssocDisallowedAttr(int reasonCode) { 209 mReasonCode = halToFrameworkMboAssocRDisallowedReasonCode(reasonCode); 210 } 211 212 @Override toString()213 public String toString() { 214 return new StringBuilder("MboAssocDisallowedAttr Reason code=") 215 .append(mReasonCode).toString(); 216 } 217 218 private @MboOceConstants.MboAssocDisallowedReasonCode int halToFrameworkMboAssocRDisallowedReasonCode(int reasonCode)219 halToFrameworkMboAssocRDisallowedReasonCode(int reasonCode) { 220 switch (reasonCode) { 221 case MboAssocDisallowedReasonCode.RESERVED: 222 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_RESERVED_0; 223 case MboAssocDisallowedReasonCode.UNSPECIFIED: 224 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_UNSPECIFIED; 225 case MboAssocDisallowedReasonCode.MAX_NUM_STA_ASSOCIATED: 226 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_MAX_NUM_STA_ASSOCIATED; 227 case MboAssocDisallowedReasonCode.AIR_INTERFACE_OVERLOADED: 228 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_AIR_INTERFACE_OVERLOADED; 229 case MboAssocDisallowedReasonCode.AUTH_SERVER_OVERLOADED: 230 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_AUTH_SERVER_OVERLOADED; 231 case MboAssocDisallowedReasonCode.INSUFFICIENT_RSSI: 232 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_INSUFFICIENT_RSSI; 233 default: 234 return MboOceConstants.MBO_ASSOC_DISALLOWED_REASON_RESERVED; 235 } 236 } 237 } 238 } 239