diff --git a/os_if/linux/mlme/inc/wlan_cfg80211_cm_rsp.h b/os_if/linux/mlme/inc/wlan_cfg80211_cm_rsp.h index 33f7ac5388..3cc6c2f6c6 100644 --- a/os_if/linux/mlme/inc/wlan_cfg80211_cm_rsp.h +++ b/os_if/linux/mlme/inc/wlan_cfg80211_cm_rsp.h @@ -42,4 +42,18 @@ QDF_STATUS osif_disconnect_handler(struct wlan_objmgr_vdev *vdev, struct wlan_cm_discon_rsp *rsp); +/** + * osif_connect_handler() - API to send connect response to kernel + * @vdev: vdev pointer + * @rsp: Connection manager connect response + * + * The API is used to send connection response to kernel + * + * Context: Any context. + * Return: QDF_STATUS + */ + +QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_rsp *rsp); + #endif /* __WLAN_CFG80211_CM_RSP_H */ diff --git a/os_if/linux/mlme/src/wlan_cfg80211_cm_connect_rsp.c b/os_if/linux/mlme/src/wlan_cfg80211_cm_connect_rsp.c index d392b8fd82..af93e8f42c 100644 --- a/os_if/linux/mlme/src/wlan_cfg80211_cm_connect_rsp.c +++ b/os_if/linux/mlme/src/wlan_cfg80211_cm_connect_rsp.c @@ -19,3 +19,434 @@ * * This file maintains definitaions of connect response apis. */ + +#include +#include +#include +#include "wlan_osif_priv.h" +#include "wlan_cfg80211_cm_rsp.h" +#include "wlan_cfg80211_cm_util.h" +#include "wlan_cfg80211.h" +#include "wlan_cfg80211_scan.h" + +/** + * osif_validate_connect_and_reset_src_id() - Validate connect response and + * resets source and id + * @osif_priv: Pointer to vdev osif priv + * @cm_id: Command id received in the connect response + * + * This function validates connect response and if the connect + * response is valid, resets the source and id of the command + * + * Context: Any context. Takes and releases cmd id spinlock. + * Return: QDF_STATUS + */ +static QDF_STATUS +osif_validate_connect_and_reset_src_id(struct vdev_osif_priv *osif_priv, + wlan_cm_id cm_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* + * Send to kernel only if last osif cmd type is connect and + * cookie match else drop. If cookie match reset the cookie + * and source. + */ + qdf_spinlock_acquire(&osif_priv->last_cmd_info.cmd_id_lock); + if (cm_id != osif_priv->last_cmd_info.last_id || + osif_priv->last_cmd_info.last_source != CM_OSIF_CONNECT) { + osif_debug("Ignore as cm_id(%d)/src(%d) didn't match stored cm_id(%d)/src(%d)", + cm_id, CM_OSIF_CONNECT, + osif_priv->last_cmd_info.last_id, + osif_priv->last_cmd_info.last_source); + status = QDF_STATUS_E_INVAL; + goto rel_lock; + } + + osif_cm_reset_id_and_src_no_lock(osif_priv); +rel_lock: + qdf_spinlock_release(&osif_priv->last_cmd_info.cmd_id_lock); + + return status; +} + +/** + * osif_convert_timeout_reason() - Convert to kernel specific enum + * @timeout_reason: reason for connect timeout + * + * This function is used to convert host timeout + * reason enum to kernel specific enum. + * + * Context: Any context. + * Return: nl timeout enum + */ + +static enum nl80211_timeout_reason +osif_convert_timeout_reason(enum wlan_cm_connect_fail_reason reason) +{ + switch (reason) { + case CM_JOIN_TIMEOUT: + return NL80211_TIMEOUT_SCAN; + case CM_AUTH_TIMEOUT: + return NL80211_TIMEOUT_AUTH; + case CM_ASSOC_TIMEOUT: + return NL80211_TIMEOUT_ASSOC; + default: + return NL80211_TIMEOUT_UNSPECIFIED; + } +} + +#if defined CFG80211_CONNECT_BSS || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) + +#if defined CFG80211_CONNECT_TIMEOUT_REASON_CODE || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) +/** + * osif_connect_timeout() - API to send connection timeout reason + * @dev: network device + * @bssid: bssid to which we want to associate + * @reason: reason for connect timeout + * + * This API is used to send connection timeout reason to supplicant + * + * Context: Any context. + * Return: Void + */ +static void +osif_connect_timeout(struct net_device *dev, const u8 *bssid, + enum wlan_cm_connect_fail_reason reason) +{ + enum nl80211_timeout_reason nl_timeout_reason; + + nl_timeout_reason = osif_convert_timeout_reason(reason); + + osif_debug("nl_timeout_reason %d", nl_timeout_reason); + + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL, + nl_timeout_reason); +} + +/** + * __osif_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bss: bss info + * @connect_rsp: Connection manager connect response + * + * Context: Any context. + * Return: void + */ +static void __osif_connect_bss(struct net_device *dev, + struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp, + enum ieee80211_statuscode status) +{ + enum nl80211_timeout_reason nl_timeout_reason; + + nl_timeout_reason = osif_convert_timeout_reason(rsp->reason); + + osif_debug("nl_timeout_reason %d", nl_timeout_reason); + + cfg80211_connect_bss(dev, rsp->bssid.bytes, bss, + rsp->connect_ies.assoc_req.ptr, + rsp->connect_ies.assoc_req.len, + rsp->connect_ies.assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.len, + status, GFP_KERNEL, + nl_timeout_reason); +} +#else /* CFG80211_CONNECT_TIMEOUT_REASON_CODE */ + +#if defined CFG80211_CONNECT_TIMEOUT || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) +static void osif_connect_timeout( + struct net_device *dev, + const u8 *bssid, + enum wlan_cm_connect_fail_reason reason) +{ + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL); +} +#endif + +static void __osif_connect_bss(struct net_device *dev, + struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp, + ieee80211_statuscode status) +{ + cfg80211_connect_bss(dev, rsp->bssid.bytes, bss, + rsp->connect_ies.assoc_req.ptr, + rsp->connect_ies.assoc_req.len, + rsp->connect_ies.assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.len, + status, GFP_KERNEL); +} +#endif /* CFG80211_CONNECT_TIMEOUT_REASON_CODE */ + +/** + * osif_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bss: bss info + * @connect_rsp: Connection manager connect response + * + * The API is a wrapper to send connection status to supplicant + * + * Context: Any context. + * Return: Void + */ +#if defined CFG80211_CONNECT_TIMEOUT || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) +static void osif_connect_bss(struct net_device *dev, struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ + enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; + + osif_enter_dev(dev); + + if (rsp->reason == CM_JOIN_TIMEOUT || + rsp->reason == CM_AUTH_TIMEOUT || + rsp->reason == CM_ASSOC_TIMEOUT) { + osif_connect_timeout(dev, rsp->bssid.bytes, + rsp->reason); + } else { + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + __osif_connect_bss(dev, bss, rsp, status); + } +} +#else /* CFG80211_CONNECT_TIMEOUT */ +static void osif_connect_bss(struct net_device *dev, struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ + enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; + + osif_enter_dev(dev); + + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + + __osif_connect_bss(dev, bss, rsp, status); +} +#endif /* CFG80211_CONNECT_TIMEOUT */ + +#if defined(WLAN_FEATURE_FILS_SK) + +#if (defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + +#if defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +/** + * osif_populate_fils_params() - Populate FILS keys to connect response + * @conn_rsp_params: connect response to supplicant + * @fils_ie: Fils ie information from connection manager + * + * Context: Any context. + * Return: None + */ +static void +osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, + struct fils_connect_rsp_params *fils_ie) +{ + /* Increment seq number to be used for next FILS */ + rsp_params->fils_erp_next_seq_num = fils_ie->fils_seq_num + 1; + rsp_params->update_erp_next_seq_num = true; + rsp_params->fils_kek = fils_ie->kek; + rsp_params->fils_kek_len = fils_ie->kek_len; + rsp_params->pmk = fils_ie->fils_pmk; + rsp_params->pmk_len = fils_ie->fils_pmk_len; + rsp_params->pmkid = fils_ie->fils_pmkid; + osif_debug("erp_next_seq_num:%d", rsp_params->fils_erp_next_seq_num); +} +#else /* CFG80211_FILS_SK_OFFLOAD_SUPPORT */ +static inline void +osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, + struct fils_connect_rsp_params *fils_ie) + +{ } +#endif /* CFG80211_FILS_SK_OFFLOAD_SUPPORT */ + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * osif_populate_fils_params() - Populate FILS keys to connect response + * @conn_rsp_params: connect response to supplicant + * @fils_ie: Fils ie information from connection manager + * + * Context: Any context. + * Return: None + */ +static void +osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, + struct fils_connect_rsp_params *fils_ie) + +{ + /* Increament seq number to be used for next FILS */ + rsp_params->fils.erp_next_seq_num = fils_ie->fils_seq_num + 1; + rsp_params->fils.update_erp_next_seq_num = true; + rsp_params->fils.kek = fils_ie->kek; + rsp_params->fils.kek_len = fils_ie->kek_len; + rsp_params->fils.pmk = fils_ie->fils_pmk; + rsp_params->fils.pmk_len = fils_ie->fils_pmk_len; + rsp_params->fils.pmkid = fils_ie->fils_pmkid; + osif_debug("erp_next_seq_num:%d", rsp_params->fils.erp_next_seq_num); +} +#endif /* CFG80211_CONNECT_DONE */ + +#if defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +/** + * osif_connect_done() - Wrapper API to call cfg80211_connect_done + * @dev: network device + * @bss: bss info + * @connect_rsp: Connection manager connect response + * + * This API is used as wrapper to send FILS key/sequence number + * params etc. to supplicant in case of FILS connection + * + * Context: Any context. + * Return: None + */ +static void osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ + struct cfg80211_connect_resp_params conn_rsp_params; + enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; + + osif_enter_dev(dev); + + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) { + if (rsp->reason_code) + status = rsp->reason_code; + else + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } + qdf_mem_zero(&conn_rsp_params, sizeof(conn_rsp_params)); + + if (!rsp->connect_ies.fils_ie) { + conn_rsp_params.status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else { + conn_rsp_params.status = status; + conn_rsp_params.bssid = rsp->bssid.bytes; + conn_rsp_params.timeout_reason = + osif_convert_timeout_reason(rsp->reason); + conn_rsp_params.req_ie = rsp->connect_ies.assoc_req.ptr; + conn_rsp_params.req_ie_len = rsp->connect_ies.assoc_req.len; + conn_rsp_params.resp_ie = rsp->connect_ies.assoc_rsp.ptr; + conn_rsp_params.resp_ie_len = rsp->connect_ies.assoc_rsp.len; + conn_rsp_params.bss = bss; + osif_populate_fils_params(&conn_rsp_params, + rsp->connect_ies.fils_ie); + /* save GTK */ + } + + cfg80211_connect_done(dev, &conn_rsp_params, GFP_KERNEL); + /* hlp data for DHCP */ +} +#else /* CFG80211_CONNECT_DONE */ +static inline void +osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ } +#endif /* CFG80211_CONNECT_DONE */ +#endif /* WLAN_FEATURE_FILS_SK */ + +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))) +/** + * osif_fils_update_connect_results() - API to send fils connection status to + * supplicant. + * @dev: network device + * @bss: bss info + * @connect_rsp: Connection manager connect response + * + * The API is a wrapper to send connection status to supplicant + * + * Context: Any context. + * Return: 0 if success else failure + */ +static int osif_update_connect_results(struct net_device *dev, + struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ + if (!rsp->is_fils_connection) { + osif_debug("fils IE is NULL"); + return -EINVAL; + } + osif_connect_done(dev, bss, rsp); + + return 0; +} +#else /* WLAN_FEATURE_FILS_SK && CFG80211_CONNECT_DONE */ + +static inline int osif_update_connect_results(struct net_device *dev, + struct cfg80211_bss *bss, + struct wlan_cm_connect_rsp *rsp) +{ + return -EINVAL; +} +#endif /* WLAN_FEATURE_FILS_SK && CFG80211_CONNECT_DONE */ + +static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, + struct vdev_osif_priv *osif_priv, + struct wlan_cm_connect_rsp *rsp) +{ + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *chan; + + if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { + chan = ieee80211_get_channel(osif_priv->wdev->wiphy, + rsp->freq); + bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, + rsp->bssid.bytes, + rsp->ssid.ssid, + rsp->ssid.length); + } + + if (osif_update_connect_results(osif_priv->wdev->netdev, bss, rsp)) + osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); +} +#else /* CFG80211_CONNECT_BSS */ +static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, + struct vdev_osif_priv *osif_priv, + struct wlan_cm_connect_rsp *rsp) +{ + enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; + + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) { + if (rsp->reason_code) + status = rsp->reason_code; + else + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + cfg80211_connect_result(osif_priv->wdev->netdev, + rsp->bssid.bytes, + rsp->connect_ies.assoc_req.ptr, + rsp->connect_ies.assoc_req.len, + rsp->connect_ies.assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.len + status, GFP_KERNEL); +} +#endif /* CFG80211_CONNECT_BSS */ + +QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_rsp *rsp) +{ + struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); + QDF_STATUS status; + + osif_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id %d cm_reason %d reason_code %d", + osif_priv->wdev->netdev->name, rsp->vdev_id, + QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), + QDF_MAC_ADDR_REF(rsp->bssid.bytes), + rsp->ssid.length, rsp->ssid.ssid, + rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id, + rsp->reason, rsp->reason_code); + + status = osif_validate_connect_and_reset_src_id(osif_priv, rsp->cm_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + osif_indcate_connect_results(vdev, osif_priv, rsp); + + return QDF_STATUS_SUCCESS; +} diff --git a/os_if/linux/mlme/src/wlan_cfg80211_cm_req.c b/os_if/linux/mlme/src/wlan_cfg80211_cm_req.c index 269e0cd51b..e51db60194 100644 --- a/os_if/linux/mlme/src/wlan_cfg80211_cm_req.c +++ b/os_if/linux/mlme/src/wlan_cfg80211_cm_req.c @@ -329,7 +329,7 @@ int wlan_osif_cfg80211_connect(struct net_device *dev, return -ENOMEM; connect_req->vdev_id = vdev_id; - connect_req->source = CM_OSIF_CONNECT_REQ; + connect_req->source = CM_OSIF_CONNECT; if (req->bssid) qdf_mem_copy(connect_req->bssid.bytes, req->bssid, QDF_MAC_ADDR_SIZE); diff --git a/os_if/linux/mlme/src/wlan_cfg80211_cm_util.c b/os_if/linux/mlme/src/wlan_cfg80211_cm_util.c index ecc37c083e..dd94ed5a98 100644 --- a/os_if/linux/mlme/src/wlan_cfg80211_cm_util.c +++ b/os_if/linux/mlme/src/wlan_cfg80211_cm_util.c @@ -50,15 +50,15 @@ QDF_STATUS osif_cm_reset_id_and_src(struct wlan_objmgr_vdev *vdev) /** * osif_cm_connect_complete_cb() - Connect complete callback * @vdev: vdev pointer - * @cm_conn_rsp: connect response + * @rsp: connect response * * Return: QDF_STATUS */ static QDF_STATUS osif_cm_connect_complete_cb(struct wlan_objmgr_vdev *vdev, - struct wlan_cm_connect_rsp *cm_conn_rsp) + struct wlan_cm_connect_rsp *rsp) { - return QDF_STATUS_SUCCESS; + return osif_connect_handler(vdev, rsp); } /** diff --git a/os_if/linux/wlan_cfg80211.h b/os_if/linux/wlan_cfg80211.h index 4af50c6813..83792921ee 100644 --- a/os_if/linux/wlan_cfg80211.h +++ b/os_if/linux/wlan_cfg80211.h @@ -58,6 +58,9 @@ #define osif_nofl_debug(params...) \ QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_OS_IF, params) +#define osif_enter_dev(dev) \ + QDF_TRACE_ENTER(QDF_MODULE_ID_OS_IF, "enter(%s)", (dev)->name) + /* For kernel version >= 5.2, driver needs to provide policy */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) #define vendor_command_policy(__policy, __maxattr) \ diff --git a/umac/mlme/connection_mgr/core/src/wlan_cm_util.c b/umac/mlme/connection_mgr/core/src/wlan_cm_util.c index f1670ae2e4..cce5a9b7ad 100644 --- a/umac/mlme/connection_mgr/core/src/wlan_cm_util.c +++ b/umac/mlme/connection_mgr/core/src/wlan_cm_util.c @@ -30,7 +30,7 @@ static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) { switch (source) { - case CM_OSIF_CONNECT_REQ: + case CM_OSIF_CONNECT: case CM_ROAMING: return CONNECT_REQ_PREFIX; default: diff --git a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h index 5fe0151f2d..0205fb497a 100644 --- a/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h +++ b/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h @@ -26,6 +26,7 @@ #ifdef FEATURE_CM_ENABLE #include #include "wlan_crypto_global_def.h" +#include "qdf_status.h" #define CM_ID_INVALID 0xFFFFFFFF typedef uint32_t wlan_cm_id; @@ -101,7 +102,7 @@ struct wlan_fils_con_info { /** * enum wlan_cm_source - connection manager req source - * @CM_OSIF_CONNECT_REQ: Connect req initiated by OSIF or north bound + * @CM_OSIF_CONNECT: Connect req initiated by OSIF or north bound * @CM_ROAMING: Roaming request * @CM_OSIF_DISCONNECT: Disconnect req initiated by OSIF or north bound * @CM_PEER_DISCONNECT: Disconnect req initiated by peer sending deauth/disassoc @@ -114,7 +115,7 @@ struct wlan_fils_con_info { * @CM_SOURCE_INVALID: Invalid connection manager req source */ enum wlan_cm_source { - CM_OSIF_CONNECT_REQ, + CM_OSIF_CONNECT, CM_ROAMING, CM_OSIF_DISCONNECT, CM_PEER_DISCONNECT, @@ -251,6 +252,7 @@ enum wlan_cm_connect_fail_reason { * @src_mac: src mac * @hlp_data: hlp data * @hlp_data_len: hlp data length + * @fils_seq_num: FILS sequence number */ struct fils_connect_rsp_params { uint8_t *fils_pmk; @@ -266,6 +268,7 @@ struct fils_connect_rsp_params { struct qdf_mac_addr src_mac; uint8_t hlp_data[CM_FILS_MAX_HLP_DATA_LEN]; uint16_t hlp_data_len; + uint16_t fils_seq_num; }; #endif @@ -283,7 +286,7 @@ struct wlan_connect_rsp_ies { struct element_info assoc_rsp; struct element_info ric_resp_ie; #ifdef WLAN_FEATURE_FILS_SK - struct fils_connect_rsp_params fils_ie; + struct fils_connect_rsp_params *fils_ie; #endif }; @@ -297,15 +300,25 @@ struct wlan_connect_rsp_ies { * @reason_code: protocol reason code of the connect failure * @aid: aid * @connect_ies: connect related IE required by osif to send to kernel + * @is_fils_connection: is fils connection + * @bssid: BSSID of the ap + * @ssid: SSID of the connection + * @freq: Channel frequency */ struct wlan_cm_connect_rsp { uint8_t vdev_id; wlan_cm_id cm_id; - uint8_t connect_status; + QDF_STATUS connect_status; enum wlan_cm_connect_fail_reason reason; uint8_t reason_code; uint8_t aid; struct wlan_connect_rsp_ies connect_ies; +#ifdef WLAN_FEATURE_FILS_SK + bool is_fils_connection; +#endif + struct qdf_mac_addr bssid; + struct wlan_ssid ssid; + qdf_freq_t freq; };