diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h index 31602454cb96..087c1c2ef5d2 100644 --- a/components/mlme/core/inc/wlan_mlme_main.h +++ b/components/mlme/core/inc/wlan_mlme_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019 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 @@ -27,7 +27,7 @@ #include #include #include - +#include #define mlme_fatal(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_MLME, params) #define mlme_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_MLME, params) @@ -43,6 +43,14 @@ struct wlan_mlme_psoc_obj { struct wlan_mlme_cfg cfg; }; +/** + * struct peer_mlme_priv_obj - peer MLME component object + * @ucast_key_cipher: unicast crypto type. + */ +struct peer_mlme_priv_obj { + uint32_t ucast_key_cipher; +}; + #ifdef CONFIG_VDEV_SM /** @@ -119,6 +127,89 @@ mlme_vdev_object_destroyed_notification(struct wlan_objmgr_vdev *vdev, #endif +/** + * wlan_peer_set_unicast_cipher() - set unicast cipher + * @peer: PEER object + * @value: value to be set + * + * Return: void + */ +static inline +void wlan_peer_set_unicast_cipher(struct wlan_objmgr_peer *peer, uint32_t value) +{ + struct peer_mlme_priv_obj *peer_priv; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_err(" peer mlme component object is NULL"); + return; + } + peer_priv->ucast_key_cipher = value; +} + +/** + * wlan_peer_get_unicast_cipher() - get unicast cipher + * @peer: PEER object + * + * Return: ucast_key_cipher value + */ +static inline +uint32_t wlan_peer_get_unicast_cipher(struct wlan_objmgr_peer *peer) +{ + struct peer_mlme_priv_obj *peer_priv; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_err("peer mlme component object is NULL"); + return 0; + } + + return peer_priv->ucast_key_cipher; +} + +/** + * wma_get_peer_mic_len() - get mic hdr len and mic length for peer + * @psoc: psoc + * @pdev_id: pdev id for the peer + * @peer_mac: peer mac + * @mic_len: mic length for peer + * @mic_hdr_len: mic header length for peer + * + * Return: Success or Failure status + */ +QDF_STATUS mlme_get_peer_mic_len(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, + uint8_t *peer_mac, uint8_t *mic_len, + uint8_t *mic_hdr_len); + +/** + * mlme_peer_object_created_notification(): mlme peer create handler + * @peer: peer which is going to created by objmgr + * @arg: argument for vdev create handler + * + * Register this api with objmgr to detect peer is created + * + * Return: QDF_STATUS status in case of success else return error + */ + +QDF_STATUS +mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer, + void *arg); + +/** + * mlme_peer_object_destroyed_notification(): mlme peer delete handler + * @peer: peer which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * Register this api with objmgr to detect peer is deleted + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +mlme_peer_object_destroyed_notification(struct wlan_objmgr_peer *peer, + void *arg); + /** * mlme_get_dynamic_vdev_config() - get the vdev dynamic config params * @vdev: vdev pointer diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c index 0874301ef79f..c14ac20d84b4 100644 --- a/components/mlme/core/src/wlan_mlme_main.c +++ b/components/mlme/core/src/wlan_mlme_main.c @@ -239,6 +239,102 @@ out: return status; } +QDF_STATUS mlme_get_peer_mic_len(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, + uint8_t *peer_mac, uint8_t *mic_len, + uint8_t *mic_hdr_len) +{ + struct wlan_objmgr_peer *peer; + uint32_t key_cipher; + + if (!psoc || !mic_len || !mic_hdr_len || !peer_mac) { + mlme_debug("psoc/mic_len/mic_hdr_len/peer_mac null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_objmgr_get_peer(psoc, pdev_id, + peer_mac, WLAN_LEGACY_MAC_ID); + if (!peer) { + mlme_debug("Peer of peer_mac %pM not found", peer_mac); + return QDF_STATUS_E_INVAL; + } + key_cipher = wlan_peer_get_unicast_cipher(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + if (key_cipher == WMI_CIPHER_AES_GCM) { + *mic_hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; + *mic_len = WLAN_IEEE80211_GCMP_MICLEN; + } else { + *mic_hdr_len = IEEE80211_CCMP_HEADERLEN; + *mic_len = IEEE80211_CCMP_MICLEN; + } + mlme_debug("peer %pM hdr_len %d mic_len %d key_cipher %d", peer_mac, + *mic_hdr_len, *mic_len, key_cipher); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer, + void *arg) +{ + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status; + + if (!peer) { + mlme_err(" peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = qdf_mem_malloc(sizeof(*peer_priv)); + if (!peer_priv) { + mlme_err(" peer_priv component object alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + status = wlan_objmgr_peer_component_obj_attach(peer, + WLAN_UMAC_COMP_MLME, + (void *)peer_priv, + QDF_STATUS_SUCCESS); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("unable to attach peer_priv obj to peer obj"); + qdf_mem_free(peer_priv); + } + + return status; +} + +QDF_STATUS +mlme_peer_object_destroyed_notification(struct wlan_objmgr_peer *peer, + void *arg) +{ + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status; + + if (!peer) { + mlme_err(" peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_err(" peer MLME component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_peer_component_obj_detach(peer, + WLAN_UMAC_COMP_MLME, + peer_priv); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("unable to detach peer_priv obj to peer obj"); + + qdf_mem_free(peer_priv); + + return status; +} + static void mlme_init_chainmask_cfg(struct wlan_objmgr_psoc *psoc, struct wlan_mlme_chainmask *chainmask_info) { diff --git a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c index 2ae1328f617a..d1caa86e8162 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c +++ b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c @@ -125,7 +125,28 @@ QDF_STATUS ucfg_mlme_init(void) mlme_err("unable to register psoc create handle"); return status; } + status = ucfg_mlme_vdev_init(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("peer create register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("peer destroy register notification failed"); + return QDF_STATUS_E_FAILURE; + } return status; } @@ -134,6 +155,20 @@ QDF_STATUS ucfg_mlme_deinit(void) { QDF_STATUS status; + status = wlan_objmgr_unregister_peer_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("unable to unregister peer destroy handle"); + + status = wlan_objmgr_unregister_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("unable to unregister peer create handle"); + status = ucfg_mlme_vdev_deinit(); if (QDF_IS_STATUS_ERROR(status)) mlme_err("unable to unregister vdev destroy handle"); diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.c b/components/p2p/core/src/wlan_p2p_off_chan_tx.c index 1515a4d26632..c53efb40f951 100644 --- a/components/p2p/core/src/wlan_p2p_off_chan_tx.c +++ b/components/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -33,6 +33,7 @@ #include "wlan_p2p_main.h" #include "wlan_p2p_off_chan_tx.h" #include "wlan_osif_request_manager.h" +#include /** * p2p_psoc_get_tx_ops() - get p2p tx ops @@ -1509,9 +1510,21 @@ static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx, } if (!qdf_is_macaddr_group((struct qdf_mac_addr *)wh->i_addr1) && !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)wh->i_addr1)) { + uint8_t mic_len, mic_hdr_len, pdev_id; - frame_len = *size + IEEE80211_CCMP_HEADERLEN + - IEEE80211_CCMP_MICLEN; + pdev_id = + wlan_get_pdev_id_from_vdev_id(tx_ctx->p2p_soc_obj->soc, + tx_ctx->vdev_id, + WLAN_P2P_ID); + status = mlme_get_peer_mic_len(p2p_soc_obj->soc, pdev_id, + wh->i_addr1, &mic_len, + &mic_hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + p2p_err("Failed to get peer mic length."); + return status; + } + + frame_len = *size + mic_hdr_len + mic_len; status = p2p_packet_alloc((uint16_t)frame_len, (void **)&frame, &pkt); if (status != QDF_STATUS_SUCCESS) { @@ -1521,7 +1534,7 @@ static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx, } qdf_mem_copy(frame, wh, sizeof(*wh)); - qdf_mem_copy(frame + sizeof(*wh) + IEEE80211_CCMP_HEADERLEN, + qdf_mem_copy(frame + sizeof(*wh) + mic_hdr_len, *ppbuf + sizeof(*wh), *size - sizeof(*wh)); rmf_wh = (struct wlan_frame_hdr *)frame; diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 7ac94a6d6476..192b62850e01 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -809,7 +809,6 @@ struct wma_txrx_node { uint8_t rmfEnabled; #ifdef WLAN_FEATURE_11W wma_igtk_key_t key; - uint32_t ucast_key_cipher; #endif /* WLAN_FEATURE_11W */ uint32_t uapsd_cached_val; tAniGetPEStatsRsp *stats_rsp; diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 9c89e49f9742..3eff35f3a7c0 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -78,6 +78,7 @@ #include "wlan_lmac_if_api.h" #include #include +#include struct wma_search_rate { int32_t rate; @@ -2545,19 +2546,23 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, if (!QDF_IS_ADDR_BROADCAST(wh->i_addr1) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { if (pFc->wep) { - uint8_t mic_len, hdr_len; + uint8_t mic_len, hdr_len, pdev_id; /* Allocate extra bytes for privacy header and * trailer */ - if (iface->ucast_key_cipher == - WMI_CIPHER_AES_GCM) { - hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; - mic_len = WLAN_IEEE80211_GCMP_MICLEN; - } else { - hdr_len = IEEE80211_CCMP_HEADERLEN; - mic_len = IEEE80211_CCMP_MICLEN; - } + pdev_id = wlan_objmgr_pdev_get_pdev_id( + wma_handle->pdev); + qdf_status = + mlme_get_peer_mic_len(wma_handle->psoc, + pdev_id, + wh->i_addr1, + &mic_len, + &hdr_len); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + newFrmLen = frmLen + hdr_len + mic_len; qdf_status = cds_packet_alloc((uint16_t) newFrmLen, diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index e2e13ce5e52f..6b46cdc2d50d 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -77,6 +77,7 @@ #include "wlan_mlme_api.h" #include "wmi_unified_bcn_api.h" #include +#include /** * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL @@ -1913,6 +1914,23 @@ wma_skip_bip_key_set(tp_wma_handle wma_handle, uint32_t key_cipher) return false; } +static void wma_set_peer_unicast_cipher(tp_wma_handle wma, + struct set_key_params *params) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + params->peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", params->peer_mac); + return; + } + + wlan_peer_set_unicast_cipher(peer, params->key_cipher); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + /** * wma_setup_install_key_cmd() - set key parameters * @wma_handle: wma handle @@ -2089,11 +2107,11 @@ static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, CMAC_IPN_LEN); } } - - if (key_params->unicast && iface) - iface->ucast_key_cipher = params.key_cipher; #endif /* WLAN_FEATURE_11W */ + if (key_params->unicast) + wma_set_peer_unicast_cipher(wma_handle, ¶ms); + WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d", key_params->vdev_id, key_params->key_idx, key_params->key_type, key_params->key_len); @@ -3895,7 +3913,8 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, { uint8_t *orig_hdr; uint8_t *ccmp; - uint8_t mic_len, hdr_len; + uint8_t mic_len, hdr_len, pdev_id; + QDF_STATUS status; if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) { if (QDF_IS_ADDR_BROADCAST(wh->i_addr1) || @@ -3904,19 +3923,23 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, cds_pkt_return_packet(rx_pkt); return -EINVAL; } - if (iface->ucast_key_cipher == WMI_CIPHER_AES_GCM) { - hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; - mic_len = WLAN_IEEE80211_GCMP_MICLEN; - } else { - hdr_len = IEEE80211_CCMP_HEADERLEN; - mic_len = IEEE80211_CCMP_MICLEN; - } - if (qdf_nbuf_len(wbuf) < (sizeof(*wh) + hdr_len + mic_len)) { - WMA_LOGE("Buffer length less than expected %d", - (int)qdf_nbuf_len(wbuf)); - cds_pkt_return_packet(rx_pkt); - return -EINVAL; - } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev); + status = mlme_get_peer_mic_len(wma_handle->psoc, pdev_id, + wh->i_addr2, &mic_len, + &hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to get mic hdr and length"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + if (qdf_nbuf_len(wbuf) < (sizeof(*wh) + hdr_len + mic_len)) { + WMA_LOGE("Buffer length less than expected %d", + (int)qdf_nbuf_len(wbuf)); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } orig_hdr = (uint8_t *) qdf_nbuf_data(wbuf); /* Pointer to head of CCMP header */ diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 7361953a0c8d..d388b5a2b7fc 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -74,6 +74,7 @@ #include #include "wma_nan_datapath.h" #include "wlan_mlme_api.h" +#include #ifdef FEATURE_WLAN_EXTSCAN #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED @@ -2307,6 +2308,52 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma, return 0; } +static void wma_update_roamed_peer_unicast_cipher(tp_wma_handle wma, + uint32_t uc_cipher, + uint8_t *peer_mac) +{ + struct wlan_objmgr_peer *peer; + + if (!peer_mac) { + WMA_LOGE("peer_mac is NULL"); + return; + } + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", peer_mac); + return; + } + + wlan_peer_set_unicast_cipher(peer, uc_cipher); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +static uint32_t wma_get_peer_uc_cipher(tp_wma_handle wma, uint8_t *peer_mac) +{ + uint32_t uc_cipher; + struct wlan_objmgr_peer *peer; + + if (!peer_mac) { + WMA_LOGE("peer_mac is NULL"); + return 0; + } + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", peer_mac); + return 0; + } + + uc_cipher = wlan_peer_get_unicast_cipher(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + return uc_cipher; +} + /** * wma_roam_update_vdev() - Update the STA and BSS * @wma: Global WMA Handle @@ -2325,6 +2372,7 @@ static void wma_roam_update_vdev(tp_wma_handle wma, tDeleteStaParams *del_sta_params; tLinkStateParams *set_link_params; tAddStaParams *add_sta_params; + uint32_t uc_cipher; uint8_t vdev_id; vdev_id = roam_synch_ind_ptr->roamed_vdev_id; @@ -2358,9 +2406,18 @@ static void wma_roam_update_vdev(tp_wma_handle wma, add_sta_params->staIdx = STA_INVALID_IDX; add_sta_params->assocId = roam_synch_ind_ptr->aid; + /* + * Get uc cipher of old peer to update new peer as it doesnt + * change in roaming + */ + uc_cipher = wma_get_peer_uc_cipher(wma, del_bss_params->bssid); + wma_delete_sta(wma, del_sta_params); wma_delete_bss(wma, del_bss_params); wma_set_linkstate(wma, set_link_params); + /* Update new peer's uc cipher */ + wma_update_roamed_peer_unicast_cipher(wma, uc_cipher, + roam_synch_ind_ptr->bssid.bytes); wma_add_bss(wma, (tpAddBssParams)roam_synch_ind_ptr->add_bss_params); wma_add_sta(wma, add_sta_params); wma_vdev_set_mlme_state_run(wma, vdev_id);