wifi: Send MBO-OCE association rejection info

Parse association response for MBO association
disallowed indication and OCE RSSI based association
rejection info and send it to framework in association
rejection event.

Bug: 162542063
Test: vts test - VtsHalWifiSupplicantV1_4TargetTest

Change-Id: Ie6b9d81491274e06a9521a2e45feb9bf2feabeb5
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 85c7190..01f1ecd 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -4526,8 +4526,8 @@
 			data->assoc_reject.timeout_reason ?
 			data->assoc_reject.timeout_reason : "");
 	wpa_s->assoc_status_code = data->assoc_reject.status_code;
-	wpas_notify_assoc_status_code(wpa_s,
-				      bssid, data->assoc_reject.timed_out);
+	wpas_notify_assoc_status_code(wpa_s, bssid, data->assoc_reject.timed_out,
+				    data->assoc_reject.resp_ies, data->assoc_reject.resp_ies_len);
 
 #ifdef CONFIG_OWE
 	if (data->assoc_reject.status_code ==
diff --git a/wpa_supplicant/hidl/1.4/hidl.cpp b/wpa_supplicant/hidl/1.4/hidl.cpp
index 0145576..fc464b6 100644
--- a/wpa_supplicant/hidl/1.4/hidl.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl.cpp
@@ -300,7 +300,7 @@
 }
 
 void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
-    const u8 *bssid, u8 timed_out)
+    const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
 {
 	if (!wpa_s)
 		return;
@@ -313,7 +313,7 @@
 	if (!hidl_manager)
 		return;
 
-	hidl_manager->notifyAssocReject(wpa_s, bssid, timed_out);
+	hidl_manager->notifyAssocReject(wpa_s, bssid, timed_out, assoc_resp_ie, assoc_resp_ie_len);
 }
 
 void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
diff --git a/wpa_supplicant/hidl/1.4/hidl.h b/wpa_supplicant/hidl/1.4/hidl.h
index 671dd41..9f9da17 100644
--- a/wpa_supplicant/hidl/1.4/hidl.h
+++ b/wpa_supplicant/hidl/1.4/hidl.h
@@ -52,8 +52,8 @@
 	void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
 			struct wpa_supplicant *wpa_s, const char *url);
 	void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
-	void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
-	    const u8 *bssid, u8 timed_out);
+	void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+	    u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
 	void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_wps_event_fail(
@@ -172,8 +172,8 @@
 		struct wpa_supplicant *wpa_s, const char *url)
 {}
 static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
-    const u8 *bssid, u8 timed_out) {}
+static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+    u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) {}
 static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
 static void wpas_hidl_notify_wps_event_fail(
     struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.cpp b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
index 8325311..1a00275 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
@@ -1019,24 +1019,91 @@
  * @param bssid bssid of AP that rejected the association.
  * @param timed_out flag to indicate failure is due to timeout
  * (auth, assoc, ...) rather than explicit rejection response from the AP.
+ * @param assoc_resp_ie Association response IE.
+ * @param assoc_resp_ie_len Association response IE length.
  */
 void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s,
-    const u8 *bssid, u8 timed_out)
+    const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
 {
+	std::string hidl_ifname = wpa_s->ifname;
+#ifdef CONFIG_MBO
+	struct wpa_bss *reject_bss;
+#endif /* CONFIG_MBO */
+	V1_4::ISupplicantStaIfaceCallback::AssociationRejectionData hidl_assoc_reject_data = {};
+
 	if (!wpa_s)
 		return;
 
 	if (sta_iface_object_map_.find(wpa_s->ifname) ==
 	    sta_iface_object_map_.end())
 		return;
+	if (wpa_s->current_ssid) {
+		std::vector < uint8_t > hidl_ssid;
+		hidl_ssid.assign(
+		    wpa_s->current_ssid->ssid,
+		    wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+		hidl_assoc_reject_data.ssid = hidl_ssid;
+	}
+	hidl_assoc_reject_data.bssid = bssid;
+	hidl_assoc_reject_data.statusCode = static_cast<ISupplicantStaIfaceCallback::StatusCode>(
+					    wpa_s->assoc_status_code);
+	if (timed_out) {
+		hidl_assoc_reject_data.timedOut = true;
+	}
+#ifdef CONFIG_MBO
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+		reject_bss = wpa_s->current_bss;
+	} else {
+		reject_bss = wpa_bss_get_bssid(wpa_s, bssid);
+	}
+	if (reject_bss && assoc_resp_ie && assoc_resp_ie_len > 0) {
+		if (wpa_s->assoc_status_code ==
+		    WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) {
+			const u8 *rssi_rej;
+			rssi_rej = mbo_get_attr_from_ies(
+				    assoc_resp_ie,
+				    assoc_resp_ie_len,
+				    OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+			if (rssi_rej && rssi_rej[1] == 2) {
+				wpa_printf(MSG_INFO,
+					   "OCE: RSSI-based association rejection from "
+					   MACSTR " Delta RSSI: %u, Retry Delay: %u bss rssi: %d",
+					   MAC2STR(reject_bss->bssid),
+					   rssi_rej[2], rssi_rej[3], reject_bss->level);
+				hidl_assoc_reject_data.isOceRssiBasedAssocRejectAttrPresent = true;
+				hidl_assoc_reject_data.oceRssiBasedAssocRejectData.deltaRssi
+					    = rssi_rej[2];
+				hidl_assoc_reject_data.oceRssiBasedAssocRejectData.retryDelayS
+					    = rssi_rej[3];
+			}
+		} else if (wpa_s->assoc_status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
+			  || wpa_s->assoc_status_code == WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA) {
+			const u8 *assoc_disallowed;
+			assoc_disallowed = mbo_get_attr_from_ies(
+						    assoc_resp_ie,
+						    assoc_resp_ie_len,
+						    MBO_ATTR_ID_ASSOC_DISALLOW);
+			if (assoc_disallowed && assoc_disallowed[1] == 1) {
+				wpa_printf(MSG_INFO,
+				    "MBO: association disallowed indication from "
+				    MACSTR " Reason: %d",
+				    MAC2STR(reject_bss->bssid),
+				    assoc_disallowed[2]);
+				hidl_assoc_reject_data.isMboAssocDisallowedReasonCodePresent = true;
+				hidl_assoc_reject_data.mboAssocDisallowedReason
+				    = static_cast<V1_4::ISupplicantStaIfaceCallback
+					    ::MboAssocDisallowedReasonCode>(assoc_disallowed[2]);
+			}
+		}
+	}
+#endif /* CONFIG_MBO */
 
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onAssociationRejected,
-		std::placeholders::_1, bssid,
-		static_cast<ISupplicantStaIfaceCallback::StatusCode>(
-		    wpa_s->assoc_status_code), timed_out == 1));
+	const std::function<
+		    Return<void>(android::sp<V1_4::ISupplicantStaIfaceCallback>)>
+		    func = std::bind(
+		    &V1_4::ISupplicantStaIfaceCallback::onAssociationRejected_1_4,
+		    std::placeholders::_1, hidl_assoc_reject_data);
+	callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
 }
 
 void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.h b/wpa_supplicant/hidl/1.4/hidl_manager.h
index f027676..ff59277 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.h
@@ -106,8 +106,8 @@
 	void notifyHs20RxTermsAndConditionsAcceptance(
 			struct wpa_supplicant *wpa_s, const char *url);
 	void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
-	void notifyAssocReject(struct wpa_supplicant *wpa_s,
-	    const u8 *bssid, u8 timed_out);
+	void notifyAssocReject(struct wpa_supplicant *wpa_s, const u8 *bssid,
+	    u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
 	void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
 	void notifyBssidChanged(struct wpa_supplicant *wpa_s);
 	void notifyWpsEventFail(
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ac40074..bcfdb90 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -149,14 +149,15 @@
 
 
 void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
-				   const u8 *bssid, u8 timed_out)
+				   const u8 *bssid, u8 timed_out,
+				   const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
 {
 	if (wpa_s->p2p_mgmt)
 		return;
 
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
 
-	wpas_hidl_notify_assoc_reject(wpa_s, bssid, timed_out);
+	wpas_hidl_notify_assoc_reject(wpa_s, bssid, timed_out, assoc_resp_ie, assoc_resp_ie_len);
 }
 
 void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s) {
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index d75bc77..a1a5d6b 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -28,8 +28,8 @@
 			       enum wpa_states old_state);
 void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
-void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
-				   const u8 *bssid, u8 timed_out);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out,
+				   const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
 void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
 void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6ab5485..e1b4b4e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3845,7 +3845,7 @@
 			 */
 			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
 			wpa_s->assoc_status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			wpas_notify_assoc_status_code(wpa_s, wpa_s->pending_bssid, 0);
+			wpas_notify_assoc_status_code(wpa_s, wpa_s->pending_bssid, 0, NULL, 0);
 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
 			return;