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