From 7c1c7431da14476701eabd897943820a3160cbf2 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Thu, 4 Apr 2019 12:11:57 +0530 Subject: [PATCH] qcacld-3.0: Use peer to get the cipher to decide MIC length Driver uses cipher stored in vdev to get the MIC length, which may get updated if multiple peer(TDLS peer in STA case) get connected to the vdev. Thus depending on latest peer cipher type the MIC length will be calculated for all peers. To fix store cipher info in peer and use it to calculate MIC length for the frame. Change-Id: I8afbf9a3bb43c294dbacbbaa7fa0746600937d11 CRs-Fixed: 2428482 --- components/mlme/core/inc/wlan_mlme_main.h | 95 +++++++++++++++++- components/mlme/core/src/wlan_mlme_main.c | 96 +++++++++++++++++++ .../mlme/dispatcher/src/wlan_mlme_ucfg_api.c | 35 +++++++ .../p2p/core/src/wlan_p2p_off_chan_tx.c | 19 +++- core/wma/inc/wma.h | 1 - core/wma/src/wma_data.c | 23 +++-- core/wma/src/wma_mgmt.c | 57 +++++++---- core/wma/src/wma_scan_roam.c | 57 +++++++++++ 8 files changed, 351 insertions(+), 32 deletions(-) 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);