Browse Source

qcacld-3.0: Add reason codes for internal disconnections

Currently, host driver sends disconnect reason code as UNSPECIFIED
to kernel in most of the disconnection scenarios. Correct the same
to send proper reason code received from peer in case of peer
initiated disconnections.
Introduce new reason codes for internal disconnections and assign
proper reason code for each possible disconnect scenario.

Change-Id: I99bf4573b59dc810e0a1529fcd48061d10acae4e
CRs-Fixed: 2622310
Srinivas Dasari 5 years ago
parent
commit
644dbc18c1

+ 37 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -59,10 +59,14 @@ struct wlan_ies {
  *                   originated from driver
  * @peer_discon_ies: Disconnect IEs received in deauth/disassoc frames
  *                       from peer
+ * @discon_reason: Disconnect reason as per enum eSirMacReasonCodes
+ * @from_ap: True if the disconnection is initiated from AP
  */
 struct wlan_disconnect_info {
 	struct wlan_ies self_discon_ies;
 	struct wlan_ies peer_discon_ies;
+	uint32_t discon_reason;
+	bool from_ap;
 };
 
 /**
@@ -360,6 +364,39 @@ void mlme_set_peer_pmf_status(struct wlan_objmgr_peer *peer,
  */
 bool mlme_get_peer_pmf_status(struct wlan_objmgr_peer *peer);
 
+/**
+ * mlme_set_discon_reason_n_from_ap() - set disconnect reason and from ap flag
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ * @from_ap: True if the disconnect is initiated from peer.
+ *           False otherwise.
+ * @reason_code: The disconnect code received from peer or internally generated.
+ *
+ * Set the reason code and from_ap.
+ *
+ * Return: void
+ */
+void mlme_set_discon_reason_n_from_ap(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, bool from_ap,
+				      uint32_t reason_code);
+
+/**
+ * mlme_get_discon_reason_n_from_ap() - Get disconnect reason and from ap flag
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ * @from_ap: Get the from_ap cached through mlme_set_discon_reason_n_from_ap
+ *           and copy to this buffer.
+ * @reason_code: Get the reason_code cached through
+ *               mlme_set_discon_reason_n_from_ap and copy to this buffer.
+ *
+ * Copy the contents of from_ap and reason_code to given buffers.
+ *
+ * Return: void
+ */
+void mlme_get_discon_reason_n_from_ap(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, bool *from_ap,
+				      uint32_t *reason_code);
+
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
 /**
  * mlme_get_supplicant_disabled_roaming() - Get supplicant disabled roaming

+ 54 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -2564,6 +2564,60 @@ bool mlme_get_peer_pmf_status(struct wlan_objmgr_peer *peer)
 	return peer_priv->is_pmf_enabled;
 }
 
+void mlme_set_discon_reason_n_from_ap(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, bool from_ap,
+				      uint32_t reason_code)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!psoc)
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_LEGACY_MAC_ID);
+	if (!vdev)
+		return;
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+		return;
+	}
+
+	mlme_priv->disconnect_info.from_ap = from_ap;
+	mlme_priv->disconnect_info.discon_reason = reason_code;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+}
+
+void mlme_get_discon_reason_n_from_ap(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, bool *from_ap,
+				      uint32_t *reason_code)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!psoc)
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_LEGACY_MAC_ID);
+	if (!vdev)
+		return;
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+		return;
+	}
+
+	*from_ap = mlme_priv->disconnect_info.from_ap;
+	*reason_code = mlme_priv->disconnect_info.discon_reason;
+	mlme_priv->disconnect_info.from_ap = false;
+	mlme_priv->disconnect_info.discon_reason = 0;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+}
+
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
 static
 const char *mlme_roam_state_to_string(enum roam_offload_state state)

+ 21 - 0
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -3993,4 +3993,25 @@ QDF_STATUS ucfg_mlme_get_peer_unmap_conf(struct wlan_objmgr_psoc *psoc)
 {
 	return wlan_mlme_get_peer_unmap_conf(psoc);
 }
+
+/**
+ * ucfg_mlme_get_discon_reason_n_from_ap() - Get disconnect reason and from ap
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ * @from_ap: Get the from_ap cached through mlme_set_discon_reason_n_from_ap
+ *           and copy to this buffer.
+ * @reason_code: Get the reason_code cached through
+ *               mlme_set_discon_reason_n_from_ap and copy to this buffer.
+ *
+ * Fetch the contents of from_ap and reason_codes.
+ *
+ * Return: void
+ */
+static inline void
+ucfg_mlme_get_discon_reason_n_from_ap(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, bool *from_ap,
+				      uint32_t *reason_code)
+{
+	mlme_get_discon_reason_n_from_ap(psoc, vdev_id, from_ap, reason_code);
+}
 #endif /* _WLAN_MLME_UCFG_API_H_ */

+ 3 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1039,6 +1039,8 @@ struct hdd_context;
  * @cache_sta_count: number of currently cached stations
  * @acs_complete_event: acs complete event
  * @latency_level: 0 - normal, 1 - moderate, 2 - low, 3 - ultralow
+ * @last_disconnect_reason: Last disconnected internal reason code
+ *                          as per enum eSirMacReasonCodes
  */
 struct hdd_adapter {
 	/* Magic cookie for adapter sanity verification.  Note that this
@@ -1312,6 +1314,7 @@ struct hdd_adapter {
 	bool motion_det_in_progress;
 	uint32_t motion_det_baseline_value;
 #endif /* WLAN_FEATURE_MOTION_DETECTION */
+	enum eSirMacReasonCodes last_disconnect_reason;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)

+ 16 - 7
core/hdd/src/wlan_hdd_assoc.c

@@ -424,7 +424,8 @@ void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx)
 		hdd_debug("Disconnecting STA on vdev: %d",
 			  sta_adapter->vdev_id);
 		status = wlan_hdd_disconnect(sta_adapter,
-					     eCSR_DISCONNECT_REASON_DEAUTH);
+					     eCSR_DISCONNECT_REASON_DEAUTH,
+					     eSIR_MAC_UNSPEC_FAILURE_REASON);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			hdd_err("wlan_hdd_disconnect failed, status: %d",
 				status);
@@ -1696,6 +1697,8 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 	bool sendDisconInd = true;
 	mac_handle_t mac_handle;
 	struct wlan_ies disconnect_ies = {0};
+	bool from_ap = false;
+	uint32_t reason_code = 0;
 
 	if (!dev) {
 		hdd_err("net_dev is released return");
@@ -1776,9 +1779,13 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 					pr_info("wlan: disconnected due to poor signal, rssi is %d dB\n",
 						roam_info->rxRssi);
 			}
+			ucfg_mlme_get_discon_reason_n_from_ap(hdd_ctx->psoc,
+							      adapter->vdev_id,
+							      &from_ap,
+							      &reason_code);
 			wlan_hdd_cfg80211_indicate_disconnect(
-							dev, false,
-							reason,
+							adapter, !from_ap,
+							reason_code,
 							disconnect_ies.data,
 							disconnect_ies.len);
 
@@ -3057,7 +3064,8 @@ hdd_association_completion_handler(struct hdd_adapter *adapter,
 				sme_roam_disconnect(
 					mac_handle,
 					adapter->vdev_id,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_UNSPEC_FAILURE_REASON);
 			}
 			return QDF_STATUS_E_FAILURE;
 		}
@@ -3116,9 +3124,10 @@ hdd_association_completion_handler(struct hdd_adapter *adapter,
 					 */
 					hdd_debug("Disconnecting...");
 					sme_roam_disconnect(
-					   mac_handle,
-					   adapter->vdev_id,
-					   eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					mac_handle,
+					adapter->vdev_id,
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_UNSPEC_FAILURE_REASON);
 				}
 				qdf_mem_free(reqRsnIe);
 				qdf_mem_free(rsp_rsn_ie);

+ 88 - 12
core/hdd/src/wlan_hdd_cfg80211.c

@@ -19395,7 +19395,8 @@ static int __wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy,
 	}
 
 	/*Try disconnecting if already in connected state */
-	status = wlan_hdd_try_disconnect(adapter);
+	status = wlan_hdd_try_disconnect(adapter,
+					 eSIR_MAC_UNSPEC_FAILURE_REASON);
 	if (0 > status) {
 		hdd_err("Failed to disconnect the existing IBSS connection");
 		return -EALREADY;
@@ -19570,7 +19571,8 @@ static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy,
 	INIT_COMPLETION(adapter->disconnect_comp_var);
 	status = sme_roam_disconnect(mac_handle,
 				     adapter->vdev_id,
-				     eCSR_DISCONNECT_REASON_IBSS_LEAVE);
+				     eCSR_DISCONNECT_REASON_IBSS_LEAVE,
+				     eSIR_MAC_UNSPEC_FAILURE_REASON);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
 		hdd_err("sme_roam_disconnect failed status: %d",
 		       status);
@@ -19840,7 +19842,8 @@ static void wlan_hdd_cfg80211_clear_privacy(struct hdd_adapter *adapter)
 
 static int wlan_hdd_wait_for_disconnect(mac_handle_t mac_handle,
 					struct hdd_adapter *adapter,
-					uint16_t reason)
+					uint16_t reason,
+					tSirMacReasonCodes mac_reason)
 {
 	eConnectionState prev_conn_state;
 	struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
@@ -19862,7 +19865,8 @@ static int wlan_hdd_wait_for_disconnect(mac_handle_t mac_handle,
 	prev_conn_state = sta_ctx->conn_info.conn_state;
 	hdd_conn_set_connection_state(adapter, eConnectionState_Disconnecting);
 
-	status = sme_roam_disconnect(mac_handle, adapter->vdev_id, reason);
+	status = sme_roam_disconnect(mac_handle, adapter->vdev_id, reason,
+				     mac_reason);
 	if (status == QDF_STATUS_CMD_NOT_QUEUED &&
 	    prev_conn_state == eConnectionState_Connecting) {
 		/*
@@ -19942,7 +19946,8 @@ static void wlan_hdd_wait_for_roaming(mac_handle_t mac_handle,
 	}
 }
 
-int wlan_hdd_try_disconnect(struct hdd_adapter *adapter)
+int wlan_hdd_try_disconnect(struct hdd_adapter *adapter,
+			    enum eSirMacReasonCodes reason)
 {
 	mac_handle_t mac_handle;
 
@@ -19950,7 +19955,8 @@ int wlan_hdd_try_disconnect(struct hdd_adapter *adapter)
 	wlan_hdd_wait_for_roaming(mac_handle, adapter);
 
 	return wlan_hdd_wait_for_disconnect(mac_handle, adapter,
-					    eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					    eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					    reason);
 }
 
 /**
@@ -20215,7 +20221,8 @@ static int __wlan_hdd_cfg80211_connect(struct wiphy *wiphy,
 		return status;
 
 	/* Try disconnecting if already in connected state */
-	status = wlan_hdd_try_disconnect(adapter);
+	status = wlan_hdd_try_disconnect(adapter,
+					 eSIR_MAC_UNSPEC_FAILURE_REASON);
 	if (0 > status) {
 		hdd_err("Failed to disconnect the existing connection");
 		return -EALREADY;
@@ -20274,7 +20281,75 @@ static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy,
 	return errno;
 }
 
-int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason)
+/**
+ * wlan_hdd_get_ieee80211_disconnect_reason() - Get ieee80211 disconnect reason
+ * @adapter: pointer to adapter structure
+ * @reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
+ *
+ * Reason codes that are greater than eSIR_MAC_REASON_PROP_START are internal
+ * reason codes. Cache the same in hdd_ctx and return UNSPECIFIED.
+ * Rest of the reason codes are valid ieee80211 reason codes.
+ *
+ * Return: Reason code of type ieee80211_reasoncode.
+ */
+static enum ieee80211_reasoncode
+wlan_hdd_get_cfg80211_disconnect_reason(struct hdd_adapter *adapter,
+					enum eSirMacReasonCodes reason)
+{
+	enum ieee80211_reasoncode ieee80211_reason = WLAN_REASON_UNSPECIFIED;
+
+	/*
+	 * Cache internal reason code in adapter. This can be sent to
+	 * userspace with a vendor event.
+	 */
+	if (reason >= eSIR_MAC_REASON_PROP_START)
+		adapter->last_disconnect_reason = reason;
+	else
+		ieee80211_reason = (enum ieee80211_reasoncode)reason;
+
+	return ieee80211_reason;
+}
+
+#if defined(CFG80211_DISCONNECTED_V2) || \
+(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+void
+wlan_hdd_cfg80211_indicate_disconnect(struct hdd_adapter *adapter,
+				      bool locally_generated,
+				      enum eSirMacReasonCodes reason,
+				      uint8_t *disconnect_ies,
+				      uint16_t disconnect_ies_len)
+{
+	enum ieee80211_reasoncode ieee80211_reason;
+
+	ieee80211_reason = wlan_hdd_get_cfg80211_disconnect_reason(adapter,
+								   reason);
+	hdd_debug("Disconnect reason code - MAC: %u, IEEE80211: %u locally_generated: %u",
+		  reason, ieee80211_reason, locally_generated);
+	cfg80211_disconnected(adapter->dev, ieee80211_reason, disconnect_ies,
+			      disconnect_ies_len, locally_generated,
+			      GFP_KERNEL);
+}
+#else
+void
+wlan_hdd_cfg80211_indicate_disconnect(struct hdd_adapter *adapter,
+				      bool locally_generated,
+				      enum eSirMacReasonCodes reason,
+				      uint8_t *disconnect_ies,
+				      uint16_t disconnect_ies_len)
+{
+	enum ieee80211_reasoncode ieee80211_reason;
+
+	ieee80211_reason = wlan_hdd_get_cfg80211_disconnect_reason(adapter,
+								   reason);
+	hdd_debug("Disconnect reason code - MAC: %u, IEEE80211: %u locally_generated: %u",
+		  reason, ieee80211_reason, locally_generated);
+	cfg80211_disconnected(adapter->dev, ieee80211_reason, disconnect_ies,
+			      disconnect_ies_len, GFP_KERNEL);
+}
+#endif
+
+int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason,
+			tSirMacReasonCodes mac_reason)
 {
 	int ret;
 	mac_handle_t mac_handle;
@@ -20287,15 +20362,16 @@ int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason)
 	wlan_hdd_netif_queue_control(adapter,
 		WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, WLAN_CONTROL_PATH);
 
-	ret = wlan_hdd_wait_for_disconnect(mac_handle, adapter, reason);
+	ret = wlan_hdd_wait_for_disconnect(mac_handle, adapter, reason,
+					   mac_reason);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
 	/* Sending disconnect event to userspace for kernel version < 3.11
 	 * is handled by __cfg80211_disconnect call to __cfg80211_disconnected
 	 */
 	hdd_debug("Send disconnected event to userspace");
-	wlan_hdd_cfg80211_indicate_disconnect(adapter->dev, true,
-					      WLAN_REASON_UNSPECIFIED, NULL, 0);
+	wlan_hdd_cfg80211_indicate_disconnect(adapter, true,
+					      mac_reason, NULL, 0);
 #endif
 
 	return ret;
@@ -20482,7 +20558,7 @@ static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy,
 
 		hdd_info("%s(vdevid-%d): Disconnect from userspace; reason:%d (%s)",
 			 dev->name, adapter->vdev_id, reason, hdd_ieee80211_reason_code_to_str(reason));
-		status = wlan_hdd_disconnect(adapter, reasonCode);
+		status = wlan_hdd_disconnect(adapter, reasonCode, reason);
 		if (0 != status) {
 			hdd_err("wlan_hdd_disconnect failed, status: %d", status);
 			hdd_set_disconnect_status(adapter, false);

+ 20 - 30
core/hdd/src/wlan_hdd_cfg80211.h

@@ -446,39 +446,25 @@ int wlan_hdd_cfg80211_update_band(struct hdd_context *hdd_ctx,
 				  enum band_info new_band);
 
 /**
- * wlan_hdd_try_disconnect() - try disconnnect from previous connection
+ * wlan_hdd_cfg80211_indicate_disconnect() - Indicate disconnnect to userspace
  * @adapter: Pointer to adapter
+ * @locally_generated: True if the disconnection is internally generated.
+ *                     False if the disconnection is received from peer.
+ * @reason: Disconnect reason as per @enum eSirMacReasonCodes
+ * @disconnect_ies: IEs received in Deauth/Disassoc from peer
+ * @disconnect_ies_len: Length of @disconnect_ies
  *
- * This function is used to disconnect from previous connection
+ * This function is indicate disconnect to the kernel which thus indicates
+ * to the userspace.
  *
- * Return: 0 for success, non-zero for failure
+ * Return: None
  */
-int wlan_hdd_try_disconnect(struct hdd_adapter *adapter);
-
-#if defined(CFG80211_DISCONNECTED_V2) || \
-(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
-static inline void
-wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
+void
+wlan_hdd_cfg80211_indicate_disconnect(struct hdd_adapter *adapter,
 				      bool locally_generated,
-				      int reason,
+				      enum eSirMacReasonCodes reason,
 				      uint8_t *disconnect_ies,
-				      uint16_t disconnect_ies_len)
-{
-	cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
-			      locally_generated, GFP_KERNEL);
-}
-#else
-static inline void
-wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
-				      bool locally_generated,
-				      int reason,
-				      uint8_t *disconnect_ies,
-				      uint16_t disconnect_ies_len)
-{
-	cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
-			      GFP_KERNEL);
-}
-#endif
+				      uint16_t disconnect_ies_len);
 
 /**
  * wlan_hdd_inform_bss_frame() - inform bss details to NL80211
@@ -546,23 +532,27 @@ uint8_t hdd_get_sap_operating_band(struct hdd_context *hdd_ctx);
 /**
  * wlan_hdd_try_disconnect() - try disconnnect from previous connection
  * @adapter: Pointer to adapter
+ * @reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
  *
  * This function is used to disconnect from previous connection
  *
  * Return: 0 for success, non-zero for failure
  */
-int wlan_hdd_try_disconnect(struct hdd_adapter *adapter);
+int wlan_hdd_try_disconnect(struct hdd_adapter *adapter,
+			    enum eSirMacReasonCodes reason);
 
 /**
  * wlan_hdd_disconnect() - hdd disconnect api
  * @adapter: Pointer to adapter
- * @reason: Disconnect reason code
+ * @reason: CSR disconnect reason code as per @enum eCsrRoamDisconnectReason
+ * @mac_reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
  *
  * This function is used to issue a disconnect request to SME
  *
  * Return: 0 for success, non-zero for failure
  */
-int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason);
+int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason,
+			tSirMacReasonCodes mac_reason);
 
 /**
  * wlan_hdd_get_adjacent_chan(): Gets next/previous channel

+ 6 - 4
core/hdd/src/wlan_hdd_hostapd.c

@@ -4648,8 +4648,9 @@ static int wlan_hdd_setup_driver_overrides(struct hdd_adapter *ap_adapter)
 		return 0;
 }
 
-void hdd_check_and_disconnect_sta_on_invalid_channel(
-		struct hdd_context *hdd_ctx)
+void
+hdd_check_and_disconnect_sta_on_invalid_channel(struct hdd_context *hdd_ctx,
+						tSirMacReasonCodes reason)
 {
 	struct hdd_adapter *sta_adapter;
 	uint32_t sta_chan_freq;
@@ -4676,7 +4677,7 @@ void hdd_check_and_disconnect_sta_on_invalid_channel(
 
 	hdd_err("chan %d not valid, issue disconnect", sta_chan_freq);
 	/* Issue Disconnect request */
-	wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH);
+	wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH, reason);
 }
 
 #ifdef DISABLE_CHANNEL_LIST
@@ -5094,7 +5095,8 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 		/* check if STA is on indoor channel*/
 		if (policy_mgr_is_force_scc(hdd_ctx->psoc))
 			hdd_check_and_disconnect_sta_on_invalid_channel(
-								       hdd_ctx);
+					hdd_ctx,
+					eSIR_MAC_OPER_CHANNEL_DISABLED_INDOOR);
 	}
 
 	beacon = adapter->session.ap.beacon;

+ 5 - 3
core/hdd/src/wlan_hdd_hostapd.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -267,14 +267,16 @@ int wlan_hdd_disable_channels(struct hdd_context *hdd_ctx);
  * hdd_check_and_disconnect_sta_on_invalid_channel() - Disconnect STA if it is
  * on invalid channel
  * @hdd_ctx: pointer to hdd context
+ * @reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
  *
  * STA should be disconnected before starting the SAP if it is on indoor
  * channel.
  *
  * Return: void
  */
-void hdd_check_and_disconnect_sta_on_invalid_channel(
-						struct hdd_context *hdd_ctx);
+void
+hdd_check_and_disconnect_sta_on_invalid_channel(struct hdd_context *hdd_ctx,
+						tSirMacReasonCodes reason);
 
 /**
  * hdd_stop_sap_due_to_invalid_channel() - to stop sap in case of invalid chnl

+ 6 - 3
core/hdd/src/wlan_hdd_ioctl.c

@@ -7262,6 +7262,7 @@ static bool check_disable_channels(struct hdd_context *hdd_ctx,
  * disconnect_sta_and_stop_sap() - Disconnect STA and stop SAP
  *
  * @hdd_ctx: Pointer to hdd context
+ * @reason: Disconnect reason code as per @enum eSirMacReasonCodes
  *
  * Disable channels provided by user and disconnect STA if it is
  * connected to any AP, stop SAP and send deauthentication request
@@ -7269,7 +7270,8 @@ static bool check_disable_channels(struct hdd_context *hdd_ctx,
  *
  * Return: None
  */
-static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx)
+static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx,
+					enum eSirMacReasonCodes reason)
 {
 	struct hdd_adapter *adapter, *next = NULL;
 	QDF_STATUS status;
@@ -7278,7 +7280,7 @@ static void disconnect_sta_and_stop_sap(struct hdd_context *hdd_ctx)
 	if (!hdd_ctx)
 		return;
 
-	hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx);
+	hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason);
 
 	status = hdd_get_front_adapter(hdd_ctx, &adapter);
 	while (adapter && (status == QDF_STATUS_SUCCESS)) {
@@ -7475,7 +7477,8 @@ mem_alloc_failed:
 		ret = wlan_hdd_disable_channels(hdd_ctx);
 		if (ret)
 			return ret;
-		disconnect_sta_and_stop_sap(hdd_ctx);
+		disconnect_sta_and_stop_sap(hdd_ctx,
+					    eSIR_MAC_OPER_CHANNEL_BAND_CHANGE);
 	}
 
 	hdd_exit();

+ 15 - 7
core/hdd/src/wlan_hdd_main.c

@@ -5965,6 +5965,7 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 	struct sap_config *sap_config;
 	mac_handle_t mac_handle;
 	struct wlan_objmgr_vdev *vdev;
+	enum eSirMacReasonCodes reason = eSIR_MAC_IFACE_DOWN;
 
 	hdd_enter();
 
@@ -6001,22 +6002,28 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 			INIT_COMPLETION(adapter->disconnect_comp_var);
 
 			roam_profile = hdd_roam_profile(adapter);
+			if (cds_is_driver_recovering())
+				reason = eSIR_MAC_DEVICE_RECOVERY;
+
 			/* For NDI do not use roam_profile */
 			if (adapter->device_mode == QDF_NDI_MODE)
 				status = sme_roam_disconnect(
 					mac_handle,
 					adapter->vdev_id,
-					eCSR_DISCONNECT_REASON_NDI_DELETE);
+					eCSR_DISCONNECT_REASON_NDI_DELETE,
+					reason);
 			else if (roam_profile->BSSType ==
 						eCSR_BSS_TYPE_START_IBSS)
 				status = sme_roam_disconnect(
 					mac_handle,
 					adapter->vdev_id,
-					eCSR_DISCONNECT_REASON_IBSS_LEAVE);
+					eCSR_DISCONNECT_REASON_IBSS_LEAVE,
+					reason);
 			else if (adapter->device_mode == QDF_STA_MODE) {
 				rc = wlan_hdd_disconnect(
 						adapter,
-						eCSR_DISCONNECT_REASON_DEAUTH);
+						eCSR_DISCONNECT_REASON_DEAUTH,
+						reason);
 				if (rc != 0 && ucfg_ipa_is_enabled()) {
 					hdd_err("STA disconnect failed");
 					ucfg_ipa_uc_cleanup_sta(hdd_ctx->pdev,
@@ -6026,7 +6033,8 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 				status = sme_roam_disconnect(
 					mac_handle,
 					adapter->vdev_id,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					reason);
 			}
 			/* success implies disconnect is queued */
 			if (QDF_IS_STATUS_SUCCESS(status) &&
@@ -7109,9 +7117,9 @@ QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx)
 
 				/* indicate disconnected event to nl80211 */
 				wlan_hdd_cfg80211_indicate_disconnect(
-						adapter->dev, false,
-						WLAN_REASON_UNSPECIFIED,
-						NULL, 0);
+					adapter, true,
+					eSIR_MAC_DEVICE_RECOVERY,
+					NULL, 0);
 			} else if (eConnectionState_Connecting == conn_state) {
 				/*
 				 * Indicate connect failure to supplicant if we

+ 3 - 2
core/hdd/src/wlan_hdd_nud_tracking.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -277,7 +277,8 @@ hdd_handle_nud_fail_non_sta(struct hdd_adapter *adapter)
 	hdd_debug("Disconnecting vdev with vdev id: %d",
 		  adapter->vdev_id);
 	/* Issue Disconnect */
-	status = wlan_hdd_disconnect(adapter, eCSR_DISCONNECT_REASON_DEAUTH);
+	status = wlan_hdd_disconnect(adapter, eCSR_DISCONNECT_REASON_DEAUTH,
+				     eSIR_MAC_GATEWAY_REACHABILITY_FAILURE);
 	if (0 != status) {
 		hdd_err("wlan_hdd_disconnect failed, status: %d",
 			status);

+ 2 - 1
core/hdd/src/wlan_hdd_regulatory.c

@@ -823,7 +823,8 @@ int hdd_reg_set_band(struct net_device *dev, u8 ui_band)
 			status = sme_roam_disconnect(
 					mac_handle,
 					adapter->vdev_id,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_OPER_CHANNEL_BAND_CHANGE);
 
 			if (QDF_STATUS_SUCCESS != status) {
 				hdd_err("sme_roam_disconnect failure, status: %d",

+ 2 - 0
core/mac/inc/sir_api.h

@@ -1251,6 +1251,7 @@ struct disassoc_ind {
 	struct qdf_mac_addr peer_macaddr;
 	uint16_t staId;
 	uint32_t reasonCode;
+	bool from_ap;
 };
 
 /* / Definition for Disassociation confirm */
@@ -1311,6 +1312,7 @@ struct deauth_ind {
 	uint16_t staId;
 	uint32_t reasonCode;
 	int8_t rssi;
+	bool from_ap;
 };
 
 /* / Definition for Deauthetication confirm */

+ 25 - 3
core/mac/inc/sir_mac_prot_def.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -439,7 +439,7 @@ typedef enum eSirMacReasonCodes {
 	eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON = 9,  /* Station requesting (re)association is not authenticated with responding station */
 	eSIR_MAC_PWR_CAPABILITY_BAD_REASON = 10,        /* Disassociated because the information in the Power Capability element is unacceptable */
 	eSIR_MAC_SPRTD_CHANNELS_BAD_REASON = 11,        /* Disassociated because the information in the Supported Channels element is unacceptable */
-	/* reserved                                        12 */
+	eSIR_MAC_BSS_TRANSITION_DISASSOC = 12,
 	eSIR_MAC_INVALID_IE_REASON = 13,        /* Invalid information element, i.e., an information element defined in this standard for */
 	/* which the content does not meet the specifications in Clause 7 */
 	eSIR_MAC_MIC_FAILURE_REASON = 14,       /* Message integrity code (MIC) failure */
@@ -475,7 +475,29 @@ typedef enum eSirMacReasonCodes {
 	eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON = 45,      /* Peer STA does not support the requested cipher suite */
 	eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON = 46, /* FT reason */
 	/* reserved                                         47 - 65535. */
-	eSIR_BEACON_MISSED = 65534,     /* We invented this to tell beacon missed case */
+
+	/*
+	 * Internal reason codes: Add any internal reason code just after
+	 * eSIR_MAC_REASON_PROP_START and decrease the value of
+	 * eSIR_MAC_REASON_PROP_START accordingly.
+	 */
+	eSIR_MAC_REASON_PROP_START = 65519,
+	eSIR_MAC_HOST_TRIGGERED_ROAM_FAILURE  = 65519,
+	eSIR_MAC_FW_TRIGGERED_ROAM_FAILURE = 65520,
+	eSIR_MAC_GATEWAY_REACHABILITY_FAILURE = 65521,
+	eSIR_MAC_UNSUPPORTED_CHANNEL_CSA = 65522,
+	eSIR_MAC_OPER_CHANNEL_DISABLED_INDOOR = 65523,
+	eSIR_MAC_OPER_CHANNEL_USER_DISABLED = 65524,
+	eSIR_MAC_DEVICE_RECOVERY = 65525,
+	eSIR_MAC_KEY_TIMEOUT = 65526,
+	eSIR_MAC_OPER_CHANNEL_BAND_CHANGE = 65527,
+	eSIR_MAC_IFACE_DOWN = 65528,
+	eSIR_MAC_PEER_XRETRY_FAIL = 65529,
+	eSIR_MAC_PEER_INACTIVITY = 65530,
+	eSIR_MAC_SA_QUERY_TIMEOUT = 65531,
+	eSIR_MAC_CHANNEL_SWITCH_FAILED = 65532,
+	eSIR_MAC_BEACON_MISSED = 65533,
+	eSIR_MAC_USER_TRIGGERED_ROAM_FAILURE = 65534,
 } tSirMacReasonCodes;
 
 /* / Frame control field format (2 bytes) */

+ 2 - 1
core/mac/src/pe/lim/lim_api.c

@@ -2241,7 +2241,8 @@ pe_disconnect_callback(struct mac_context *mac, uint8_t vdev_id,
 	}
 
 	lim_tear_down_link_with_ap(mac, session->peSessionId,
-				   reason_code);
+				   reason_code,
+				   eLIM_PEER_ENTITY_DEAUTH);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 13 - 26
core/mac/src/pe/lim/lim_link_monitoring_algo.c

@@ -228,7 +228,8 @@ void lim_delete_sta_context(struct mac_context *mac_ctx,
 				msg->addr2, session_entry, false);
 			lim_tear_down_link_with_ap(mac_ctx,
 				session_entry->peSessionId,
-				eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON);
+				eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON,
+				eLIM_LINK_MONITORING_DEAUTH);
 			/* only break for STA role (non TDLS) */
 			break;
 		}
@@ -256,7 +257,8 @@ void lim_delete_sta_context(struct mac_context *mac_ctx,
 				eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON,
 				session_entry->bssId, session_entry, false);
 		lim_tear_down_link_with_ap(mac_ctx, session_entry->peSessionId,
-					   eSIR_MAC_UNSPEC_FAILURE_REASON);
+					   eSIR_MAC_BSS_TRANSITION_DISASSOC,
+					   eLIM_LINK_MONITORING_DEAUTH);
 		break;
 
 	default:
@@ -323,26 +325,10 @@ lim_trigger_sta_deletion(struct mac_context *mac_ctx, tpDphHashNode sta_ds,
 	lim_send_sme_disassoc_ind(mac_ctx, sta_ds, session_entry);
 } /*** end lim_trigger_st_adeletion() ***/
 
-/**
- * lim_tear_down_link_with_ap()
- *
- ***FUNCTION:
- * This function is called when heartbeat (beacon reception)
- * fails on STA
- *
- ***LOGIC:
- *
- ***ASSUMPTIONS:
- *
- ***NOTE:
- *
- * @param  mac - Pointer to Global MAC structure
- * @return None
- */
-
 void
 lim_tear_down_link_with_ap(struct mac_context *mac, uint8_t sessionId,
-			   tSirMacReasonCodes reasonCode)
+			   tSirMacReasonCodes reasonCode,
+			   enum eLimDisassocTrigger trigger)
 {
 	tpDphHashNode sta = NULL;
 
@@ -361,8 +347,9 @@ lim_tear_down_link_with_ap(struct mac_context *mac, uint8_t sessionId,
 	 */
 	pe_session->pmmOffloadInfo.bcnmiss = false;
 
-	pe_info("No ProbeRsp from AP after HB failure for pe/sme id %d/%d reason code %d",
-		pe_session->peSessionId, pe_session->smeSessionId, reasonCode);
+	pe_info("Session %d Vdev %d reason code %d trigger %d",
+		pe_session->peSessionId, pe_session->vdev_id, reasonCode,
+		trigger);
 
 	/* Announce loss of link to Roaming algorithm */
 	/* and cleanup by sending SME_DISASSOC_REQ to SME */
@@ -388,8 +375,7 @@ lim_tear_down_link_with_ap(struct mac_context *mac, uint8_t sessionId,
 #endif
 
 		sta->mlmStaContext.disassocReason = reasonCode;
-		sta->mlmStaContext.cleanupTrigger =
-			eLIM_LINK_MONITORING_DEAUTH;
+		sta->mlmStaContext.cleanupTrigger = trigger;
 		/* / Issue Deauth Indication to SME. */
 		qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr,
 			     sta->staAddr, sizeof(tSirMacAddr));
@@ -401,7 +387,7 @@ lim_tear_down_link_with_ap(struct mac_context *mac, uint8_t sessionId,
 		 * connection, if we connect to same AP after HB failure.
 		 */
 		if (mac->mlme_cfg->sta.deauth_before_connection &&
-		    eSIR_BEACON_MISSED == reasonCode) {
+		    eSIR_MAC_BEACON_MISSED == reasonCode) {
 			int apCount = mac->lim.gLimHeartBeatApMacIndex;
 
 			if (mac->lim.gLimHeartBeatApMacIndex)
@@ -529,7 +515,8 @@ void lim_handle_heart_beat_failure(struct mac_context *mac_ctx,
 			 */
 			lim_tear_down_link_with_ap(mac_ctx,
 				session->peSessionId,
-				eSIR_BEACON_MISSED);
+				eSIR_MAC_BEACON_MISSED,
+				eLIM_LINK_MONITORING_DEAUTH);
 		}
 	} else {
 		/**

+ 16 - 0
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -772,6 +772,14 @@ error:
 						 (uint32_t *) pMsg);
 } /*** end lim_send_sme_disassoc_ntf() ***/
 
+static bool lim_is_disconnect_from_ap(enum eLimDisassocTrigger trigger)
+{
+	if (trigger == eLIM_PEER_ENTITY_DEAUTH ||
+	    trigger == eLIM_PEER_ENTITY_DISASSOC)
+		return true;
+
+	return false;
+}
 /** -----------------------------------------------------------------
    \brief lim_send_sme_disassoc_ind() - sends SME_DISASSOC_IND
 
@@ -808,6 +816,10 @@ lim_send_sme_disassoc_ind(struct mac_context *mac, tpDphHashNode sta,
 	qdf_mem_copy(pSirSmeDisassocInd->peer_macaddr.bytes, sta->staAddr,
 		     QDF_MAC_ADDR_SIZE);
 
+	if (LIM_IS_STA_ROLE(pe_session))
+		pSirSmeDisassocInd->from_ap =
+		lim_is_disconnect_from_ap(sta->mlmStaContext.cleanupTrigger);
+
 	mmhMsg.type = eWNI_SME_DISASSOC_IND;
 	mmhMsg.bodyptr = pSirSmeDisassocInd;
 	mmhMsg.bodyval = 0;
@@ -870,6 +882,10 @@ lim_send_sme_deauth_ind(struct mac_context *mac, tpDphHashNode sta,
 		sta->mlmStaContext.disassocReason)
 		pSirSmeDeauthInd->rssi = sta->del_sta_ctx_rssi;
 
+	if (LIM_IS_STA_ROLE(pe_session))
+		pSirSmeDeauthInd->from_ap =
+		lim_is_disconnect_from_ap(sta->mlmStaContext.cleanupTrigger);
+
 	mmhMsg.type = eWNI_SME_DEAUTH_IND;
 	mmhMsg.bodyptr = pSirSmeDeauthInd;
 	mmhMsg.bodyval = 0;

+ 15 - 2
core/mac/src/pe/lim/lim_types.h

@@ -769,8 +769,21 @@ static inline void lim_update_tdls_set_state_for_fw(struct pe_session
 /* / Function that handles heartbeat failure */
 void lim_handle_heart_beat_failure(struct mac_context *, struct pe_session *);
 
-/* / Function that triggers link tear down with AP upon HB failure */
-void lim_tear_down_link_with_ap(struct mac_context *, uint8_t, tSirMacReasonCodes);
+/**
+ * lim_tear_down_link_with_ap() - Tear down link with AP
+ * @mac: mac context
+ * @session_id: PE session id
+ * @reason_code: Disconnect reason code as per emun eSirMacReasonCodes
+ * @trigger: Disconnect trigger as per enum eLimDisassocTrigger
+ *
+ * Function that triggers link tear down with AP upon HB failure
+ *
+ * Return: None
+ */
+void lim_tear_down_link_with_ap(struct mac_context *mac,
+				uint8_t session_id,
+				tSirMacReasonCodes reason_code,
+				enum eLimDisassocTrigger trigger);
 
 /* / Function that defers the messages received */
 uint32_t lim_defer_msg(struct mac_context *, struct scheduler_msg *);

+ 4 - 2
core/mac/src/pe/lim/lim_utils.c

@@ -1874,7 +1874,8 @@ static void __lim_process_channel_switch_timeout(struct pe_session *pe_session)
 			lim_tear_down_link_with_ap(mac,
 					   mac->lim.lim_timers.
 					   gLimChannelSwitchTimer.sessionId,
-					   eSIR_MAC_UNSPEC_FAILURE_REASON);
+					   eSIR_MAC_UNSUPPORTED_CHANNEL_CSA,
+					   eLIM_LINK_MONITORING_DISASSOC);
 			return;
 		}
 	}
@@ -4724,7 +4725,8 @@ void lim_handle_heart_beat_failure_timeout(struct mac_context *mac_ctx)
 			 */
 			lim_tear_down_link_with_ap(mac_ctx,
 						psession_entry->peSessionId,
-						eSIR_BEACON_MISSED);
+						eSIR_MAC_BEACON_MISSED,
+						eLIM_LINK_MONITORING_DISASSOC);
 			mac_ctx->lim.gLimProbeFailureAfterHBfailedCnt++;
 		} else {
 			pe_err("Unexpected wt-probe-timeout in state");

+ 2 - 2
core/sme/inc/csr_internal.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -288,7 +288,7 @@ struct roam_cmd {
 	bool fStopWds;
 	tSirMacAddr peerMac;
 	tSirMacReasonCodes reason;
-	eCsrRoamDisconnectReason disconnect_reason;
+	tSirMacReasonCodes disconnect_reason;
 };
 
 struct setkey_cmd {

+ 3 - 1
core/sme/inc/sme_api.h

@@ -533,11 +533,13 @@ QDF_STATUS sme_roam_reassoc(mac_handle_t mac_handle, uint8_t sessionId,
  * @mac_handle: Opaque handle to the global MAC context
  * @session: SME session identifier
  * @reason: Reason to disconnect
+ * @mac_reason: Reason to disconnect as per enum eSirMacReasonCodes
  *
  * Return: QDF Status success or failure
  */
 QDF_STATUS sme_roam_disconnect(mac_handle_t mac_handle, uint8_t session,
-			       eCsrRoamDisconnectReason reason);
+			       eCsrRoamDisconnectReason reason,
+			       tSirMacReasonCodes mac_reason);
 
 void sme_dhcp_done_ind(mac_handle_t mac_handle, uint8_t session_id);
 QDF_STATUS sme_roam_stop_bss(mac_handle_t mac_handle, uint8_t sessionId);

+ 16 - 8
core/sme/src/common/sme_api.c

@@ -63,7 +63,8 @@
 
 static QDF_STATUS init_sme_cmd_list(struct mac_context *mac);
 
-static void sme_disconnect_connected_sessions(struct mac_context *mac);
+static void sme_disconnect_connected_sessions(struct mac_context *mac,
+					      enum eSirMacReasonCodes reason);
 
 static QDF_STATUS sme_handle_generic_change_country_code(struct mac_context *mac,
 						  void *msg_buf);
@@ -2859,7 +2860,8 @@ QDF_STATUS sme_roam_reassoc(mac_handle_t mac_handle, uint8_t sessionId,
 }
 
 QDF_STATUS sme_roam_disconnect(mac_handle_t mac_handle, uint8_t session_id,
-			       eCsrRoamDisconnectReason reason)
+			       eCsrRoamDisconnectReason reason,
+			       tSirMacReasonCodes mac_reason)
 {
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
@@ -2871,7 +2873,8 @@ QDF_STATUS sme_roam_disconnect(mac_handle_t mac_handle, uint8_t session_id,
 	if (QDF_IS_STATUS_SUCCESS(status)) {
 		if (CSR_IS_SESSION_VALID(mac_ctx, session_id))
 			status = csr_roam_disconnect(mac_ctx, session_id,
-						     reason);
+						     reason,
+						     mac_reason);
 		else
 			status = QDF_STATUS_E_INVAL;
 		sme_release_global_lock(&mac_ctx->sme);
@@ -5283,7 +5286,8 @@ sme_handle_generic_change_country_code(struct mac_context *mac_ctx,
 
 	mac_ctx->reg_hint_src = SOURCE_UNKNOWN;
 
-	sme_disconnect_connected_sessions(mac_ctx);
+	sme_disconnect_connected_sessions(mac_ctx,
+					  eSIR_MAC_UNSPEC_FAILURE_REASON);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -5305,7 +5309,8 @@ QDF_STATUS sme_update_channel_list(mac_handle_t mac_handle)
 
 		csr_apply_channel_power_info_wrapper(mac_ctx);
 		csr_scan_filter_results(mac_ctx);
-		sme_disconnect_connected_sessions(mac_ctx);
+		sme_disconnect_connected_sessions(mac_ctx,
+					eSIR_MAC_OPER_CHANNEL_USER_DISABLED);
 		sme_release_global_lock(&mac_ctx->sme);
 	}
 
@@ -5337,14 +5342,16 @@ static bool sme_search_in_base_ch_freq_lst(
 /**
  * sme_disconnect_connected_sessions() - Disconnect STA and P2P client session
  * if channel is not supported
- * @mac_ctx:          mac global context
+ * @mac_ctx: mac global context
+ * @reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
  *
  * If new country code does not support the channel on which STA/P2P client
  * is connetced, it sends the disconnect to the AP/P2P GO
  *
  * Return: void
  */
-static void sme_disconnect_connected_sessions(struct mac_context *mac_ctx)
+static void sme_disconnect_connected_sessions(struct mac_context *mac_ctx,
+					      enum eSirMacReasonCodes reason)
 {
 	uint8_t session_id, found = false;
 	uint32_t chan_freq;
@@ -5362,7 +5369,8 @@ static void sme_disconnect_connected_sessions(struct mac_context *mac_ctx)
 		if (!found) {
 			sme_debug("Disconnect Session: %d", session_id);
 			csr_roam_disconnect(mac_ctx, session_id,
-					    eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					    eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					    reason);
 		}
 	}
 }

+ 42 - 21
core/sme/src/csr/csr_api_roam.c

@@ -3982,9 +3982,8 @@ QDF_STATUS csr_roam_call_callback(struct mac_context *mac, uint32_t sessionId,
 			 * to 0 if unknown. eSIR_BEACON_MISSED reason code is
 			 * not recognizable so that we set to 0 instead.
 			 */
-			roam_info->reasonCode =
-				(roam_info->reasonCode == eSIR_BEACON_MISSED) ?
-				0 : roam_info->reasonCode;
+			if (roam_info->reasonCode == eSIR_MAC_BEACON_MISSED)
+				roam_info->reasonCode = 0;
 		}
 		status = mac->session_roam_complete_cb(mac->psoc, sessionId, roam_info,
 						       roamId, u1, u2);
@@ -8769,7 +8768,8 @@ QDF_STATUS csr_roam_connect(struct mac_context *mac, uint32_t sessionId,
 	    !csr_is_ssid_in_list(&pSession->connectedProfile.SSID,
 				 &pProfile->SSIDs))
 		csr_roam_issue_disassociate_cmd(mac, sessionId,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_UNSPEC_FAILURE_REASON);
 	/*
 	 * If roamSession.connectState is disconnecting that mean
 	 * disconnect was received with scan for ssid in progress
@@ -9019,7 +9019,8 @@ QDF_STATUS csr_roam_process_disassoc_deauth(struct mac_context *mac,
 	}
 	/* change state to 'Roaming'... */
 	csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINING, sessionId);
-
+	mlme_set_discon_reason_n_from_ap(mac->psoc, pCommand->vdev_id, false,
+					 pCommand->u.roamCmd.disconnect_reason);
 	if (csr_is_conn_state_ibss(mac, sessionId)) {
 		/* If we are in an IBSS, then stop the IBSS... */
 		status =
@@ -9100,7 +9101,8 @@ QDF_STATUS csr_roam_process_disassoc_deauth(struct mac_context *mac,
 
 QDF_STATUS csr_roam_issue_disassociate_cmd(struct mac_context *mac,
 					uint32_t sessionId,
-					eCsrRoamDisconnectReason reason)
+					eCsrRoamDisconnectReason reason,
+					tSirMacReasonCodes mac_reason)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	tSmeCmd *pCommand;
@@ -9159,7 +9161,7 @@ QDF_STATUS csr_roam_issue_disassociate_cmd(struct mac_context *mac,
 		default:
 			break;
 		}
-		pCommand->u.roamCmd.disconnect_reason = reason;
+		pCommand->u.roamCmd.disconnect_reason = mac_reason;
 		status = csr_queue_sme_command(mac, pCommand, true);
 		if (!QDF_IS_STATUS_SUCCESS(status))
 			sme_err("fail to send message status: %d", status);
@@ -9195,7 +9197,8 @@ QDF_STATUS csr_roam_issue_stop_bss_cmd(struct mac_context *mac, uint32_t session
 }
 
 QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessionId,
-					eCsrRoamDisconnectReason reason)
+					eCsrRoamDisconnectReason reason,
+					tSirMacReasonCodes mac_reason)
 {
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId);
@@ -9212,7 +9215,7 @@ QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessio
 	    || CSR_IS_CONN_NDI(&pSession->connectedProfile)) {
 		sme_debug("called");
 		status = csr_roam_issue_disassociate_cmd(mac, sessionId,
-							 reason);
+							 reason, mac_reason);
 	} else if (pSession->scan_info.profile) {
 		mac->roam.roamSession[sessionId].connectState =
 			eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING;
@@ -9226,7 +9229,8 @@ QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessio
 }
 
 QDF_STATUS csr_roam_disconnect(struct mac_context *mac_ctx, uint32_t session_id,
-			       eCsrRoamDisconnectReason reason)
+			       eCsrRoamDisconnectReason reason,
+			       tSirMacReasonCodes mac_reason)
 {
 	struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id);
 
@@ -9240,7 +9244,8 @@ QDF_STATUS csr_roam_disconnect(struct mac_context *mac_ctx, uint32_t session_id,
 	csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL,
 					  eCsrForcedDisassoc);
 
-	return csr_roam_disconnect_internal(mac_ctx, session_id, reason);
+	return csr_roam_disconnect_internal(mac_ctx, session_id, reason,
+					    mac_reason);
 }
 
 QDF_STATUS
@@ -9949,6 +9954,9 @@ static void csr_roam_roaming_state_reassoc_rsp_processor(struct mac_context *mac
 				roam_info = qdf_mem_malloc(sizeof(*roam_info));
 				if (!roam_info)
 					return;
+				mlme_set_discon_reason_n_from_ap(mac->psoc,
+					pSmeJoinRsp->vdev_id, false,
+					eSIR_MAC_HOST_TRIGGERED_ROAM_FAILURE);
 				csr_roam_call_callback(mac,
 						       pSmeJoinRsp->vdev_id,
 						       roam_info, roam_id,
@@ -10332,6 +10340,8 @@ void csr_handle_disassoc_ho(struct mac_context *mac, uint32_t session_id)
 	csr_scan_result_purge(mac, scan_handle_roam_ap);
 
 POST_ROAM_FAILURE:
+	mlme_set_discon_reason_n_from_ap(mac->psoc, session_id, false,
+					 eSIR_MAC_HOST_TRIGGERED_ROAM_FAILURE);
 	csr_post_roam_failure(mac, session_id, roam_info, NULL);
 	qdf_mem_free(roam_info);
 }
@@ -12007,7 +12017,7 @@ csr_roam_chk_lnk_deauth_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr)
 		session->disconnect_stats.disconnection_cnt++;
 		session->disconnect_stats.deauth_by_peer++;
 		break;
-	case eSIR_BEACON_MISSED:
+	case eSIR_MAC_BEACON_MISSED:
 		session->disconnect_stats.disconnection_cnt++;
 		session->disconnect_stats.bmiss++;
 		break;
@@ -12060,7 +12070,8 @@ csr_roam_chk_lnk_swt_ch_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr)
 	if (QDF_IS_STATUS_ERROR(pSwitchChnInd->status)) {
 		sme_err("Channel switch failed");
 		csr_roam_disconnect_internal(mac_ctx, sessionId,
-					     eCSR_DISCONNECT_REASON_DEAUTH);
+					     eCSR_DISCONNECT_REASON_DEAUTH,
+					     eSIR_MAC_CHANNEL_SWITCH_FAILED);
 		return;
 	}
 	session->connectedProfile.op_freq = pSwitchChnInd->freq;
@@ -12421,7 +12432,8 @@ csr_roam_chk_lnk_wm_status_change_ntf(struct mac_context *mac_ctx,
 			 mac_ctx->roam.curSubState[sessionId]))) {
 			sme_warn("Calling csr_roam_disconnect_internal");
 			csr_roam_disconnect_internal(mac_ctx, sessionId,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_UNSPEC_FAILURE_REASON);
 		} else {
 			sme_warn("Skipping the new scan as CSR is in state: %s and sub-state: %s",
 				mac_trace_getcsr_roam_state(
@@ -12764,7 +12776,8 @@ bool csr_roam_complete_roaming(struct mac_context *mac, uint32_t sessionId,
 			 * detinguish it. For missed beacon, LIM set reason to
 			 * be eSIR_BEACON_MISSED
 			 */
-			if (eSIR_BEACON_MISSED == pSession->roamingStatusCode) {
+			if (eSIR_MAC_BEACON_MISSED ==
+				pSession->roamingStatusCode) {
 				roamResult = eCSR_ROAM_RESULT_LOSTLINK;
 			} else if (eCsrLostlinkRoamingDisassoc ==
 				   pSession->roamingReason) {
@@ -12991,7 +13004,8 @@ void csr_roam_wait_for_key_time_out_handler(void *pv)
 					 pSession->connectedProfile.bssid);
 			if (QDF_IS_STATUS_SUCCESS(status)) {
 				csr_roam_disconnect(mac, vdev_id,
-					eCSR_DISCONNECT_REASON_UNSPECIFIED);
+					eCSR_DISCONNECT_REASON_UNSPECIFIED,
+					eSIR_MAC_KEY_TIMEOUT);
 			}
 		} else {
 			sme_err("session not found");
@@ -13179,6 +13193,7 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 	eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK;
 	struct csr_roam_info *roam_info;
 	struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId);
+	bool from_ap = false;
 
 	if (!pSession) {
 		sme_err("session: %d not found", sessionId);
@@ -13193,7 +13208,7 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 		pSession->roamingStatusCode = pDisassocIndMsg->status_code;
 		pSession->joinFailStatusCode.reasonCode =
 			pDisassocIndMsg->reasonCode;
-
+		from_ap = pDisassocIndMsg->from_ap;
 		qdf_copy_macaddr(&roam_info->peerMac,
 				 &pDisassocIndMsg->peer_macaddr);
 	} else if (eWNI_SME_DEAUTH_IND == type) {
@@ -13202,7 +13217,7 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 		pSession->roamingStatusCode = pDeauthIndMsg->status_code;
 		pSession->joinFailStatusCode.reasonCode =
 			pDeauthIndMsg->reasonCode;
-
+		from_ap = pDeauthIndMsg->from_ap;
 		qdf_copy_macaddr(&roam_info->peerMac,
 				 &pDeauthIndMsg->peer_macaddr);
 
@@ -13212,6 +13227,9 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 		pSession->joinFailStatusCode.reasonCode = 1;
 	}
 
+	mlme_set_discon_reason_n_from_ap(mac->psoc, sessionId, from_ap,
+				      pSession->joinFailStatusCode.reasonCode);
+
 	if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND) {
 		struct wlan_objmgr_vdev *vdev;
 		struct request_info info = {0};
@@ -20336,7 +20354,8 @@ void csr_process_ho_fail_ind(struct mac_context *mac_ctx, void *msg_buf)
 	QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
 		  "LFR3:Issue Disconnect on session %d", sessionId);
 	csr_roam_disconnect(mac_ctx, sessionId,
-			eCSR_DISCONNECT_REASON_ROAM_HO_FAIL);
+			eCSR_DISCONNECT_REASON_ROAM_HO_FAIL,
+			eSIR_MAC_FW_TRIGGERED_ROAM_FAILURE);
 	if (mac_ctx->mlme_cfg->gen.fatal_event_trigger)
 		cds_flush_logs(WLAN_LOG_TYPE_FATAL,
 				WLAN_LOG_INDICATOR_HOST_DRIVER,
@@ -21167,7 +21186,8 @@ static QDF_STATUS csr_process_roam_sync_callback(struct mac_context *mac_ctx,
 		if (vdev_roam_params->source == USERSPACE_INITIATED) {
 			/* Userspace roam req fail, disconnect with AP */
 			csr_roam_disconnect(mac_ctx, session_id,
-					    eCSR_DISCONNECT_REASON_DEAUTH);
+					eCSR_DISCONNECT_REASON_DEAUTH,
+					eSIR_MAC_USER_TRIGGERED_ROAM_FAILURE);
 		}
 		vdev_roam_params->roam_invoke_in_progress = false;
 		goto end;
@@ -21184,7 +21204,8 @@ static QDF_STATUS csr_process_roam_sync_callback(struct mac_context *mac_ctx,
 		if (wlan_reg_is_disable_for_freq(mac_ctx->pdev,
 						 roam_synch_data->chan_freq)) {
 			csr_roam_disconnect(mac_ctx, session_id,
-					    eCSR_DISCONNECT_REASON_DEAUTH);
+					    eCSR_DISCONNECT_REASON_DEAUTH,
+					    eSIR_MAC_OPER_CHANNEL_BAND_CHANGE);
 			sme_debug("Roaming Failed for disabled channel or band");
 			vdev_roam_params->roam_invoke_in_progress = false;
 			goto end;

+ 5 - 4
core/sme/src/csr/csr_host_scan_roam.c

@@ -570,10 +570,11 @@ void csr_neighbor_roam_request_handoff(struct mac_context *mac_ctx,
 
 	sme_debug("csr_roamHandoffRequested: disassociating with current AP");
 
-	if (!QDF_IS_STATUS_SUCCESS
-		    (csr_roam_issue_disassociate_cmd
-			    (mac_ctx, session_id,
-			    eCSR_DISCONNECT_REASON_HANDOFF))) {
+	if (!QDF_IS_STATUS_SUCCESS(csr_roam_issue_disassociate_cmd(
+					mac_ctx,
+					session_id,
+					eCSR_DISCONNECT_REASON_HANDOFF,
+					eSIR_MAC_UNSPEC_FAILURE_REASON))) {
 		sme_warn("csr_roamHandoffRequested: fail to issue disassoc");
 		qdf_mem_free(roam_info);
 		return;

+ 13 - 9
core/sme/src/csr/csr_inside_api.h

@@ -254,10 +254,12 @@ eRoamCmdStatus csr_get_roam_complete_status(struct mac_context *mac,
 					    uint32_t sessionId);
 /* pBand can be NULL if caller doesn't need to get it */
 QDF_STATUS csr_roam_issue_disassociate_cmd(struct mac_context *mac,
-					uint32_t sessionId,
-					   eCsrRoamDisconnectReason reason);
+					   uint32_t sessionId,
+					   eCsrRoamDisconnectReason reason,
+					   tSirMacReasonCodes mac_reason);
 QDF_STATUS csr_roam_disconnect_internal(struct mac_context *mac, uint32_t sessionId,
-					eCsrRoamDisconnectReason reason);
+					eCsrRoamDisconnectReason reason,
+					tSirMacReasonCodes mac_reason);
 /* pCommand may be NULL */
 void csr_roam_remove_duplicate_command(struct mac_context *mac, uint32_t sessionId,
 				       tSmeCmd *pCommand,
@@ -813,15 +815,17 @@ void csr_roam_free_connect_profile(tCsrRoamConnectedProfile *profile);
 QDF_STATUS csr_apply_channel_and_power_list(struct mac_context *mac);
 
 /*
- * csr_roam_disconnect() -
- *  To disconnect from a network
+ * csr_roam_disconnect() - To disconnect from a network
+ * @mac: pointer to mac context
+ * @session_id: Session ID
+ * @reason: CSR disconnect reason code as per @enum eCsrRoamDisconnectReason
+ * @mac_reason: Mac Disconnect reason code as per @enum eSirMacReasonCodes
  *
- * Reason -- To indicate the reason for disconnecting. Currently, only
- * eCSR_DISCONNECT_REASON_MIC_ERROR is meanful.
  * Return QDF_STATUS
  */
-QDF_STATUS csr_roam_disconnect(struct mac_context *mac, uint32_t sessionId,
-			       eCsrRoamDisconnectReason reason);
+QDF_STATUS csr_roam_disconnect(struct mac_context *mac, uint32_t session_id,
+			       eCsrRoamDisconnectReason reason,
+			       tSirMacReasonCodes mac_reason);
 
 /* This function is used to stop a BSS. It is similar of csr_roamIssueDisconnect
  * but this function doesn't have any logic other than blindly trying to stop