MBO-OCE feature support (phase 3)
This commit does the following:
1. Save mbo cellular data preference attribute and association retry delay
attribute in wpa_supplicant interface structure.
2. Notify framework about BSS transition request frame
handling status.
Bug: 139474288
Test: VTS test
Test: Manual
Change-Id: Icff9f89ee9eae8db62e777cf685fe8cb78879d49
diff --git a/wpa_supplicant/hidl/1.3/hidl.cpp b/wpa_supplicant/hidl/1.3/hidl.cpp
index a3efde4..4c2d434 100644
--- a/wpa_supplicant/hidl/1.3/hidl.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl.cpp
@@ -861,3 +861,17 @@
hidl_manager->notifyPmkCacheAdded(wpa_s, pmksa_entry);
}
+
+void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying BSS transition status");
+
+ hidl_manager->notifyBssTmStatus(wpa_s);
+}
diff --git a/wpa_supplicant/hidl/1.3/hidl.h b/wpa_supplicant/hidl/1.3/hidl.h
index 0db90a1..304a4d6 100644
--- a/wpa_supplicant/hidl/1.3/hidl.h
+++ b/wpa_supplicant/hidl/1.3/hidl.h
@@ -119,6 +119,7 @@
const char *channel_list, unsigned short band_list[], int size);
void wpas_hidl_notify_pmk_cache_added(
struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
+ void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
#else // CONFIG_CTRL_IFACE_HIDL
static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -258,6 +259,8 @@
static void wpas_hidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
struct rsn_pmksa_cache_entry *pmksa_entry)
{}
+void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{}
#endif // CONFIG_CTRL_IFACE_HIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.cpp b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
index 8b2be11..793757b 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
@@ -1597,6 +1597,158 @@
callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
}
+#ifdef CONFIG_WNM
+V1_3::ISupplicantStaIfaceCallback::BssTmStatusCode convertSupplicantBssTmStatusToHidl(
+ enum bss_trans_mgmt_status_code bss_tm_status)
+{
+ switch (bss_tm_status) {
+ case WNM_BSS_TM_ACCEPT:
+ return V1_3::ISupplicantStaIfaceCallback::BssTmStatusCode::ACCEPT;
+ case WNM_BSS_TM_REJECT_UNSPECIFIED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_UNSPECIFIED;
+ case WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_INSUFFICIENT_BEACON;
+ case WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_INSUFFICIENT_CAPABITY;
+ case WNM_BSS_TM_REJECT_UNDESIRED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_BSS_TERMINATION_UNDESIRED;
+ case WNM_BSS_TM_REJECT_DELAY_REQUEST:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_BSS_TERMINATION_DELAY_REQUEST;
+ case WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_STA_CANDIDATE_LIST_PROVIDED;
+ case WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_NO_SUITABLE_CANDIDATES;
+ case WNM_BSS_TM_REJECT_LEAVING_ESS:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_LEAVING_ESS;
+ default:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_UNSPECIFIED;
+ }
+}
+
+uint32_t setBssTmDataFlagsMask(struct wpa_supplicant *wpa_s)
+{
+ uint32_t flags = 0;
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_BSS_TERMINATION_INCLUDED;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_ESS_DISASSOCIATION_IMMINENT;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_DISASSOCIATION_IMMINENT;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ABRIDGED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_ABRIDGED;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED;
+ }
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_assoc_retry_delay_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_ASSOC_RETRY_DELAY_INCLUDED;
+ }
+ if (wpa_s->wnm_mbo_trans_reason_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_TRANSITION_REASON_CODE_INCLUDED;
+ }
+ if (wpa_s->wnm_mbo_cell_pref_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED;
+ }
+#endif
+ return flags;
+}
+
+uint32_t getBssTmDataAssocRetryDelayMs(struct wpa_supplicant *wpa_s)
+{
+ uint32_t beacon_int;
+ uint32_t duration_ms = 0;
+
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ //wnm_bss_termination_duration contains 12 bytes of BSS
+ //termination duration subelement. Format of IE is
+ // Sub eid | Length | BSS termination TSF | Duration
+ // 1 1 8 2
+ // Duration indicates number of minutes for which BSS is not
+ // present.
+ duration_ms = WPA_GET_LE16(wpa_s->wnm_bss_termination_duration + 10);
+ // minutes to milliseconds
+ duration_ms = duration_ms * 60 * 1000;
+ } else if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT)
+ || (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)) {
+ // number of tbtts to milliseconds
+ duration_ms = wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125;
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_assoc_retry_delay_present) {
+ // number of seconds to milliseconds
+ duration_ms = wpa_s->wnm_mbo_assoc_retry_delay_sec * 1000;
+ }
+#endif
+ }
+
+ return duration_ms;
+}
+#endif
+
+/**
+ * Notify listener about the status of BSS transition management
+ * request frame handling.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ */
+void HidlManager::notifyBssTmStatus(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ std::string hidl_ifname = wpa_s->ifname;
+ V1_3::ISupplicantStaIfaceCallback::BssTmData hidl_bsstm_data = {};
+
+ hidl_bsstm_data.status = convertSupplicantBssTmStatusToHidl(wpa_s->bss_tm_status);
+ hidl_bsstm_data.flags = setBssTmDataFlagsMask(wpa_s);
+ hidl_bsstm_data.assocRetryDelayMs = getBssTmDataAssocRetryDelayMs(wpa_s);
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_cell_pref_present) {
+ hidl_bsstm_data.mboCellPreference = static_cast
+ <V1_3::ISupplicantStaIfaceCallback::MboCellularDataConnectionPrefValue>
+ (wpa_s->wnm_mbo_cell_preference);
+ }
+ if (wpa_s->wnm_mbo_trans_reason_present) {
+ hidl_bsstm_data.mboTransitionReason =
+ static_cast<V1_3::ISupplicantStaIfaceCallback::MboTransitionReasonCode>
+ (wpa_s->wnm_mbo_transition_reason);
+ }
+#endif
+
+ const std::function<
+ Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_3::ISupplicantStaIfaceCallback::onBssTmHandlingDone,
+ std::placeholders::_1, hidl_bsstm_data);
+ callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
+#endif
+}
+
/**
* Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
* ifname.
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.h b/wpa_supplicant/hidl/1.3/hidl_manager.h
index 61601bd..e49e28d 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.h
@@ -144,6 +144,7 @@
android::hardware::wifi::supplicant::V1_3::DppProgressCode code);
void notifyPmkCacheAdded(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *pmksa_entry);
+ void notifyBssTmStatus(struct wpa_supplicant *wpa_s);
// Methods called from hidl objects.
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 3df86ef..8ac73ef 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -464,9 +464,8 @@
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
size_t len)
{
- const u8 *pos, *cell_pref = NULL;
+ const u8 *pos;
u8 id, elen;
- u16 disallowed_sec = 0;
if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
mbo_ie[3] != MBO_OUI_TYPE)
@@ -489,11 +488,14 @@
goto fail;
if (wpa_s->conf->mbo_cell_capa ==
- MBO_CELL_CAPA_AVAILABLE)
- cell_pref = pos;
- else
+ MBO_CELL_CAPA_AVAILABLE) {
+ wpa_s->wnm_mbo_cell_pref_present = 1;
+ wpa_s->wnm_mbo_cell_preference = *pos;
+ } else {
wpa_printf(MSG_DEBUG,
- "MBO: Station does not support Cellular data connection");
+ "MBO: Station does not support "
+ "Cellular data connection");
+ }
break;
case MBO_ATTR_ID_TRANSITION_REASON:
if (elen != 1)
@@ -509,17 +511,20 @@
if (wpa_s->wnm_mode &
WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
wpa_printf(MSG_DEBUG,
- "MBO: Unexpected association retry delay, BSS is terminating");
+ "MBO: Unexpected association retry delay, "
+ "BSS is terminating");
goto fail;
} else if (wpa_s->wnm_mode &
WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
- disallowed_sec = WPA_GET_LE16(pos);
+ wpa_s->wnm_mbo_assoc_retry_delay_present = 1;
+ wpa_s->wnm_mbo_assoc_retry_delay_sec = WPA_GET_LE16(pos);
wpa_printf(MSG_DEBUG,
"MBO: Association retry delay: %u",
- disallowed_sec);
+ wpa_s->wnm_mbo_assoc_retry_delay_sec);
} else {
wpa_printf(MSG_DEBUG,
- "MBO: Association retry delay attribute not in disassoc imminent mode");
+ "MBO: Association retry delay attribute "
+ "not in disassoc imminent mode");
}
break;
@@ -542,17 +547,17 @@
len -= elen;
}
- if (cell_pref)
+ if (wpa_s->wnm_mbo_cell_pref_present)
wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
- *cell_pref);
+ wpa_s->wnm_mbo_cell_preference);
if (wpa_s->wnm_mbo_trans_reason_present)
wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
wpa_s->wnm_mbo_transition_reason);
- if (disallowed_sec && wpa_s->current_bss)
+ if (wpa_s->wnm_mbo_assoc_retry_delay_sec && wpa_s->current_bss)
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
- disallowed_sec, 0);
+ wpa_s->wnm_mbo_assoc_retry_delay_sec, 0);
return;
fail:
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 206b488..56eb62a 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -198,6 +198,10 @@
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS);
+
+#ifdef CONFIG_WNM
+ wpas_hidl_notify_bss_tm_status(wpa_s);
+#endif
}
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 270be9e..1c0399f 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -1378,6 +1378,10 @@
#ifdef CONFIG_MBO
wpa_s->wnm_mbo_trans_reason_present = 0;
wpa_s->wnm_mbo_transition_reason = 0;
+ wpa_s->wnm_mbo_cell_pref_present = 0;
+ wpa_s->wnm_mbo_cell_preference = 0;
+ wpa_s->wnm_mbo_assoc_retry_delay_present = 0;
+ wpa_s->wnm_mbo_assoc_retry_delay_sec = 0;
#endif /* CONFIG_MBO */
if (wpa_s->current_bss)
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index c5d2535..b6fb491 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1093,7 +1093,11 @@
u8 coloc_intf_timeout;
#ifdef CONFIG_MBO
unsigned int wnm_mbo_trans_reason_present:1;
+ unsigned int wnm_mbo_cell_pref_present:1;
+ unsigned int wnm_mbo_assoc_retry_delay_present:1;
u8 wnm_mbo_transition_reason;
+ u8 wnm_mbo_cell_preference;
+ u16 wnm_mbo_assoc_retry_delay_sec;
#endif /* CONFIG_MBO */
#endif /* CONFIG_WNM */