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