summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorSunil Ravi <sunilravi@google.com>2019-12-05 01:36:00 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-12-05 01:36:00 +0000
commite50385adb9258315e69e880d2c8a475016c114c9 (patch)
tree41902918696b0de54a3b405ed384a962ce9afb01 /service
parentc2f16d91bb409bb2145b2e28f6ac88125bd68d1e (diff)
parent6eaf2cc4ac4454dc664a3b27386ebea73eb77c65 (diff)
Merge "wifi: MBO-OCE feature support (phase 2)"
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/MboOceConstants.java67
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkSelector.java19
-rw-r--r--service/java/com/android/server/wifi/hotspot2/NetworkDetail.java21
-rw-r--r--service/java/com/android/server/wifi/util/InformationElementUtil.java90
4 files changed, 192 insertions, 5 deletions
diff --git a/service/java/com/android/server/wifi/MboOceConstants.java b/service/java/com/android/server/wifi/MboOceConstants.java
new file mode 100644
index 000000000..a7f5fefab
--- /dev/null
+++ b/service/java/com/android/server/wifi/MboOceConstants.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * MBO-OCE related constants
+ */
+public class MboOceConstants {
+
+ public static final int MBO_OCE_ATTRIBUTE_NOT_PRESENT = -1;
+
+ /** MBO-OCE attribute Ids */
+ public static final int MBO_OCE_AID_MBO_AP_CAPABILITY_INDICATION = 0x01;
+ public static final int MBO_OCE_AID_NON_PREFERRED_CHANNEL_REPORT = 0x02;
+ public static final int MBO_OCE_AID_CELLULAR_DATA_CAPABILITIES = 0x03;
+ public static final int MBO_OCE_AID_ASSOCIATION_DISALLOWED = 0x04;
+ public static final int MBO_OCE_AID_CELLULAR_DATA_CONNECTION_PREFERENCE = 0x05;
+ public static final int MBO_OCE_AID_TRANSITION_REASON_CODE = 0x06;
+ public static final int MBO_OCE_AID_TRANSITION_REJECTION_REASON_CODE = 0x07;
+ public static final int MBO_OCE_AID_ASSOCIATION_RETRY_DELAY = 0x08;
+ public static final int MBO_OCE_AID_OCE_AP_CAPABILITY_INDICATION = 0x65;
+ public static final int MBO_OCE_AID_RSSI_BASED_ASSOCIATION_REJECTION = 0x66;
+ public static final int MBO_OCE_AID_REDUCED_WAN_METRICS = 0x67;
+ public static final int MBO_OCE_AID_RNR_COMPLETENESS = 0x68;
+ public static final int MBO_OCE_AID_PROBE_SUPPRESSION_BSSIDS = 0x69;
+ public static final int MBO_OCE_AID_PROBE_SUPPRESSION_SSIDS = 0x6A;
+
+ @IntDef(prefix = { "MBO_OCE_AID_" }, value = {
+ MBO_OCE_AID_MBO_AP_CAPABILITY_INDICATION,
+ MBO_OCE_AID_NON_PREFERRED_CHANNEL_REPORT,
+ MBO_OCE_AID_CELLULAR_DATA_CAPABILITIES,
+ MBO_OCE_AID_ASSOCIATION_DISALLOWED,
+ MBO_OCE_AID_CELLULAR_DATA_CONNECTION_PREFERENCE,
+ MBO_OCE_AID_TRANSITION_REASON_CODE,
+ MBO_OCE_AID_TRANSITION_REJECTION_REASON_CODE,
+ MBO_OCE_AID_ASSOCIATION_RETRY_DELAY,
+ MBO_OCE_AID_OCE_AP_CAPABILITY_INDICATION,
+ MBO_OCE_AID_RSSI_BASED_ASSOCIATION_REJECTION,
+ MBO_OCE_AID_REDUCED_WAN_METRICS,
+ MBO_OCE_AID_RNR_COMPLETENESS,
+ MBO_OCE_AID_PROBE_SUPPRESSION_BSSIDS,
+ MBO_OCE_AID_PROBE_SUPPRESSION_SSIDS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MboOceAid{}
+
+ public static final int MBO_AP_CAP_IND_ATTR_CELL_DATA_AWARE = 0x40;
+}
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index c8384614a..433fd0b01 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -36,6 +36,7 @@ import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.proto.nano.WifiMetricsProto;
import com.android.server.wifi.util.InformationElementUtil.BssLoad;
import com.android.server.wifi.util.ScanResultUtil;
@@ -384,6 +385,7 @@ public class WifiNetworkSelector {
StringBuffer noValidSsid = new StringBuffer();
StringBuffer blacklistedBssid = new StringBuffer();
StringBuffer lowRssi = new StringBuffer();
+ StringBuffer mboAssociationDisallowedBssid = new StringBuffer();
boolean scanResultsHaveCurrentBssid = false;
for (ScanDetail scanDetail : scanDetails) {
@@ -414,6 +416,18 @@ public class WifiNetworkSelector {
continue;
}
+ // Skip BSS which is not accepting new connections.
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+ if (networkDetail != null) {
+ if (networkDetail.getMboAssociationDisallowedReasonCode()
+ != MboOceConstants.MBO_OCE_ATTRIBUTE_NOT_PRESENT) {
+ mboAssociationDisallowedBssid.append(scanId).append("(")
+ .append(networkDetail.getMboAssociationDisallowedReasonCode())
+ .append(")").append(" / ");
+ continue;
+ }
+ }
+
validScanDetails.add(scanDetail);
}
@@ -440,6 +454,11 @@ public class WifiNetworkSelector {
localLog("Networks filtered out due to low signal strength: " + lowRssi);
}
+ if (mboAssociationDisallowedBssid.length() != 0) {
+ localLog("Networks filtered out due to mbo association disallowed indication: "
+ + mboAssociationDisallowedBssid);
+ }
+
return validScanDetails;
}
diff --git a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
index b456ef486..743bc76ac 100644
--- a/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
+++ b/service/java/com/android/server/wifi/hotspot2/NetworkDetail.java
@@ -119,6 +119,13 @@ public class NetworkDetail {
private final Map<Constants.ANQPElementType, ANQPElement> mANQPElements;
+ /*
+ * From Wi-Fi Alliance MBO-OCE Information element.
+ * mMboAssociationDisallowedReasonCode is the reason code for AP not accepting new connections
+ * and is set to -1 if association disallowed attribute is not present in the element.
+ */
+ private final int mMboAssociationDisallowedReasonCode;
+
public NetworkDetail(String bssid, ScanResult.InformationElement[] infoElements,
List<String> anqpLines, int freq) {
if (infoElements == null) {
@@ -279,6 +286,7 @@ public class NetworkDetail {
mInternet = interworking.internet;
mHSRelease = vsa.hsRelease;
mAnqpDomainID = vsa.anqpDomainID;
+ mMboAssociationDisallowedReasonCode = vsa.mboAssociationDisallowedReasonCode;
mAnqpOICount = roamingConsortium.anqpOICount;
mRoamingConsortiums = roamingConsortium.getRoamingConsortiums();
mExtendedCapabilities = extendedCapabilities;
@@ -356,14 +364,16 @@ public class NetworkDetail {
}
if (DBG) {
Log.d(TAG, mSSID + "ChannelWidth is: " + mChannelWidth + " PrimaryFreq: "
- + mPrimaryFreq + " mCenterfreq0: " + mCenterfreq0 + " mCenterfreq1: "
+ + mPrimaryFreq + " Centerfreq0: " + mCenterfreq0 + " Centerfreq1: "
+ mCenterfreq1 + (extendedCapabilities.is80211McRTTResponder()
? " Support RTT responder" : " Do not support RTT responder")
- + " mMaxNumberSpatialStreams: " + mMaxNumberSpatialStreams);
+ + " MaxNumberSpatialStreams: " + mMaxNumberSpatialStreams
+ + " MboAssociationDisallowedReasonCode: "
+ + mMboAssociationDisallowedReasonCode);
Log.v("WifiMode", mSSID
+ ", WifiMode: " + InformationElementUtil.WifiMode.toString(mWifiMode)
+ ", Freq: " + mPrimaryFreq
- + ", mMaxRate: " + mMaxRate
+ + ", MaxRate: " + mMaxRate
+ ", HE: " + String.valueOf(heOperation.isPresent())
+ ", VHT: " + String.valueOf(vhtOperation.isPresent())
+ ", HT: " + String.valueOf(htOperation.isPresent())
@@ -406,6 +416,7 @@ public class NetworkDetail {
mWifiMode = base.mWifiMode;
mMaxRate = base.mMaxRate;
mMaxNumberSpatialStreams = base.mMaxNumberSpatialStreams;
+ mMboAssociationDisallowedReasonCode = base.mMboAssociationDisallowedReasonCode;
}
public NetworkDetail complete(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
@@ -609,4 +620,8 @@ public class NetworkDetail {
}
return sb.toString();
}
+
+ public int getMboAssociationDisallowedReasonCode() {
+ return mMboAssociationDisallowedReasonCode;
+ }
}
diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java
index 14f6a9f3e..0aff20432 100644
--- a/service/java/com/android/server/wifi/util/InformationElementUtil.java
+++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java
@@ -20,6 +20,7 @@ import android.net.wifi.ScanResult.InformationElement;
import android.util.Log;
import com.android.server.wifi.ByteBufferReader;
+import com.android.server.wifi.MboOceConstants;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.anqp.Constants;
@@ -693,13 +694,65 @@ public class InformationElementUtil {
public static class Vsa {
private static final int ANQP_DOMID_BIT = 0x04;
+ private static final int OUI_WFA_ALLIANCE = 0x506F9a;
+ private static final int OUI_TYPE_HS20 = 0x10;
+ private static final int OUI_TYPE_MBO_OCE = 0x16;
public NetworkDetail.HSRelease hsRelease = null;
public int anqpDomainID = 0; // No domain ID treated the same as a 0; unique info per AP.
- public void from(InformationElement ie) {
+ public boolean IsMboCapable = false;
+ public boolean IsMboApCellularDataAware = false;
+ public boolean IsOceCapable = false;
+ public int mboAssociationDisallowedReasonCode =
+ MboOceConstants.MBO_OCE_ATTRIBUTE_NOT_PRESENT;
+
+ private void parseVsaMboOce(InformationElement ie) {
+ ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN);
+
+ // skip WFA OUI and type parsing as parseVsaMboOce() is called after identifying
+ // MBO-OCE OUI type.
+ data.getInt();
+
+ while (data.remaining() > 1) {
+ int attrId = data.get() & Constants.BYTE_MASK;
+ int attrLen = data.get() & Constants.BYTE_MASK;
+
+ if ((attrLen == 0) || (attrLen > data.remaining())) {
+ return;
+ }
+ byte[] attrBytes = new byte[attrLen];
+ data.get(attrBytes);
+ switch (attrId) {
+ case MboOceConstants.MBO_OCE_AID_MBO_AP_CAPABILITY_INDICATION:
+ IsMboCapable = true;
+ IsMboApCellularDataAware = (attrBytes[0]
+ & MboOceConstants.MBO_AP_CAP_IND_ATTR_CELL_DATA_AWARE) != 0;
+ break;
+ case MboOceConstants.MBO_OCE_AID_ASSOCIATION_DISALLOWED:
+ mboAssociationDisallowedReasonCode = attrBytes[0] & Constants.BYTE_MASK;
+ break;
+ case MboOceConstants.MBO_OCE_AID_OCE_AP_CAPABILITY_INDICATION:
+ IsOceCapable = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (DBG) {
+ Log.e(TAG, ":parseMboOce MBO: " + IsMboCapable + " cellDataAware: "
+ + IsMboApCellularDataAware + " AssocDisAllowRC: "
+ + mboAssociationDisallowedReasonCode + " :OCE: " + IsOceCapable);
+ }
+ }
+
+ private void parseVsaHs20(InformationElement ie) {
ByteBuffer data = ByteBuffer.wrap(ie.bytes).order(ByteOrder.LITTLE_ENDIAN);
- if (ie.bytes.length >= 5 && data.getInt() == Constants.HS20_FRAME_PREFIX) {
+ if (ie.bytes.length >= 5) {
+ // skip WFA OUI and type parsing as parseVsaHs20() is called after identifying
+ // HS20 OUI type.
+ data.getInt();
+
int hsConf = data.get() & Constants.BYTE_MASK;
switch ((hsConf >> 4) & Constants.NIBBLE_MASK) {
case 0:
@@ -721,6 +774,39 @@ public class InformationElementUtil {
}
}
}
+
+ /**
+ * Parse the vendor specific information element to build
+ * InformationElemmentUtil.vsa object.
+ *
+ * @param ie -- Information Element
+ */
+ public void from(InformationElement ie) {
+ if (ie.bytes.length < 3) {
+ if (DBG) {
+ Log.w(TAG, "Invalid vendor specific element len: " + ie.bytes.length);
+ }
+ return;
+ }
+
+ int oui = (((ie.bytes[0] & Constants.BYTE_MASK) << 16)
+ | ((ie.bytes[1] & Constants.BYTE_MASK) << 8)
+ | ((ie.bytes[2] & Constants.BYTE_MASK)));
+
+ if (oui == OUI_WFA_ALLIANCE && ie.bytes.length >= 4) {
+ int ouiType = ie.bytes[3];
+ switch (ouiType) {
+ case OUI_TYPE_HS20:
+ parseVsaHs20(ie);
+ break;
+ case OUI_TYPE_MBO_OCE:
+ parseVsaMboOce(ie);
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
/**