diff --git a/components/tdls/core/src/wlan_tdls_ct.c b/components/tdls/core/src/wlan_tdls_ct.c index e4283f0d7a..0723929409 100644 --- a/components/tdls/core/src/wlan_tdls_ct.c +++ b/components/tdls/core/src/wlan_tdls_ct.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -1074,6 +1074,15 @@ int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev, tdls_debug("oper_class:%d", chan_switch_params.oper_class); } + } else if (conn_peer->off_channel_capable && + conn_peer->pref_off_chan_num) { + chan_switch_params.tdls_off_ch = + conn_peer->pref_off_chan_num; + chan_switch_params.oper_class = + tdls_get_opclass_from_bandwidth( + tdls_soc, conn_peer->pref_off_chan_num, + tdls_soc->tdls_configs.tdls_pre_off_chan_bw, + &chan_switch_params.tdls_off_ch_bw_offset); } else { tdls_err("TDLS off-channel parameters are not set yet!!!"); return -EINVAL; diff --git a/components/tdls/core/src/wlan_tdls_main.c b/components/tdls/core/src/wlan_tdls_main.c index 89c5aef54a..bb909ec5b2 100644 --- a/components/tdls/core/src/wlan_tdls_main.c +++ b/components/tdls/core/src/wlan_tdls_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -1806,26 +1806,32 @@ void tdls_scan_serialization_comp_info_cb(struct wlan_objmgr_vdev *vdev, uint8_t tdls_get_opclass_from_bandwidth(struct tdls_soc_priv_obj *soc_obj, - uint8_t channel, uint8_t bw_offset) + uint8_t channel, uint8_t bw_offset, + uint8_t *reg_bw_offset) { uint8_t opclass; if (bw_offset & (1 << BW_80_OFFSET_BIT)) { opclass = tdls_find_opclass(soc_obj->soc, channel, BW80); + *reg_bw_offset = BW80; } else if (bw_offset & (1 << BW_40_OFFSET_BIT)) { opclass = tdls_find_opclass(soc_obj->soc, channel, BW40_LOW_PRIMARY); + *reg_bw_offset = BW40_LOW_PRIMARY; if (!opclass) { opclass = tdls_find_opclass(soc_obj->soc, channel, BW40_HIGH_PRIMARY); + *reg_bw_offset = BW40_HIGH_PRIMARY; } } else if (bw_offset & (1 << BW_20_OFFSET_BIT)) { opclass = tdls_find_opclass(soc_obj->soc, channel, BW20); + *reg_bw_offset = BW20; } else { opclass = tdls_find_opclass(soc_obj->soc, channel, BWALL); + *reg_bw_offset = BWALL; } return opclass; diff --git a/components/tdls/core/src/wlan_tdls_main.h b/components/tdls/core/src/wlan_tdls_main.h index 12ee0ea7de..3ab68ac73b 100644 --- a/components/tdls/core/src/wlan_tdls_main.h +++ b/components/tdls/core/src/wlan_tdls_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -751,11 +751,13 @@ QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc, * @soc_obj: tdls soc object. * @channel: Channel number. * @bw_offset: Bandwidth offset. + * @reg_bw_offset: enum offset_t type bandwidth * * To return the opclas. * * Return: opclass */ uint8_t tdls_get_opclass_from_bandwidth(struct tdls_soc_priv_obj *soc_obj, - uint8_t channel, uint8_t bw_offset); + uint8_t channel, uint8_t bw_offset, + uint8_t *reg_bw_offset); #endif diff --git a/components/tdls/core/src/wlan_tdls_peer.c b/components/tdls/core/src/wlan_tdls_peer.c index d6cdb4ffec..cc3a8f4924 100644 --- a/components/tdls/core/src/wlan_tdls_peer.c +++ b/components/tdls/core/src/wlan_tdls_peer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -161,6 +161,7 @@ static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj, struct tdls_soc_priv_obj *soc_obj; uint8_t key = 0; qdf_list_t *head; + uint8_t reg_bw_offset; peer = qdf_mem_malloc(sizeof(*peer)); if (!peer) { @@ -183,9 +184,10 @@ static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj, peer->pref_off_chan_num = soc_obj->tdls_configs.tdls_pre_off_chan_num; peer->op_class_for_pref_off_chan = - tdls_get_opclass_from_bandwidth(soc_obj, - peer->pref_off_chan_num, - soc_obj->tdls_configs.tdls_pre_off_chan_bw); + tdls_get_opclass_from_bandwidth( + soc_obj, peer->pref_off_chan_num, + soc_obj->tdls_configs.tdls_pre_off_chan_bw, + ®_bw_offset); peer->valid_entry = false; @@ -748,6 +750,7 @@ QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj, struct tdls_soc_priv_obj *soc_obj; struct tdls_peer *curr_peer; struct tdls_user_config *config; + uint8_t reg_bw_offset; soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); if (!soc_obj) { @@ -765,9 +768,10 @@ QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj, config = &soc_obj->tdls_configs; curr_peer->pref_off_chan_num = config->tdls_pre_off_chan_num; curr_peer->op_class_for_pref_off_chan = - tdls_get_opclass_from_bandwidth(soc_obj, - curr_peer->pref_off_chan_num, - soc_obj->tdls_configs.tdls_pre_off_chan_bw); + tdls_get_opclass_from_bandwidth( + soc_obj, curr_peer->pref_off_chan_num, + soc_obj->tdls_configs.tdls_pre_off_chan_bw, + ®_bw_offset); } tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE, diff --git a/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h b/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h index 6229c0ca1b..f56d6d5fc7 100644 --- a/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h +++ b/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 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 @@ -137,6 +137,35 @@ QDF_STATUS cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc, bool val); +/** + * cfg_tdls_get_off_channel_enable_orig() - get tdls off channel enable orig + * @psoc: pointer to psoc object + * @val: pointer to tdls off channel enable + * + * This function gets tdls off channel enable orig + */ +QDF_STATUS +cfg_tdls_get_off_channel_enable_orig(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_restore_off_channel_enable() - set tdls off channel enable to + * tdls_off_chan_enable_orig + * @psoc: pointer to psoc object + * + * Return: NULL + */ +void cfg_tdls_restore_off_channel_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_tdls_store_off_channel_enable() - save tdls off channel enable to + * tdls_off_chan_enable_orig + * @psoc: pointer to psoc object + * + * Return: NULL + */ +void cfg_tdls_store_off_channel_enable(struct wlan_objmgr_psoc *psoc); + /** * cfg_tdls_get_wmm_mode_enable() - get tdls wmm mode enable * @psoc: pointer to psoc object diff --git a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h index b8710082a0..1fdca4dba4 100644 --- a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-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 @@ -461,6 +461,7 @@ enum tdls_feature_bit { * @tdls_vdev_nss_5g: tdls NSS setting for 5G band * @tdls_buffer_sta_enable: tdls buffer station enable * @tdls_off_chan_enable: tdls off channel enable + * @tdls_off_chan_enable_orig: original tdls off channel enable * @tdls_wmm_mode_enable: tdls wmm mode enable * @tdls_external_control: tdls external control enable * @tdls_implicit_trigger_enable: tdls implicit trigger enable @@ -492,6 +493,7 @@ struct tdls_user_config { uint8_t tdls_vdev_nss_5g; bool tdls_buffer_sta_enable; bool tdls_off_chan_enable; + bool tdls_off_chan_enable_orig; bool tdls_wmm_mode_enable; bool tdls_external_control; bool tdls_implicit_trigger_enable; @@ -929,7 +931,7 @@ struct tdls_peer_update_state { struct tdls_channel_switch_params { uint32_t vdev_id; uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE]; - uint16_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch_bw_offset; uint8_t tdls_off_ch; uint8_t tdls_sw_mode; uint8_t oper_class; diff --git a/components/tdls/dispatcher/src/wlan_tdls_cfg.c b/components/tdls/dispatcher/src/wlan_tdls_cfg.c index b9ff892212..fe5e50df43 100644 --- a/components/tdls/dispatcher/src/wlan_tdls_cfg.c +++ b/components/tdls/dispatcher/src/wlan_tdls_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 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 @@ -201,6 +201,53 @@ cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +QDF_STATUS +cfg_tdls_get_off_channel_enable_orig(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_off_chan_enable_orig; + + return QDF_STATUS_SUCCESS; +} + +void cfg_tdls_store_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return; + } + + soc_obj->tdls_configs.tdls_off_chan_enable_orig = + soc_obj->tdls_configs.tdls_off_chan_enable; +} + +void cfg_tdls_restore_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return; + } + + soc_obj->tdls_configs.tdls_off_chan_enable = + soc_obj->tdls_configs.tdls_off_chan_enable_orig; + soc_obj->tdls_configs.tdls_off_chan_enable_orig = false; +} + QDF_STATUS cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc, bool *val) diff --git a/core/hdd/inc/wlan_hdd_tdls.h b/core/hdd/inc/wlan_hdd_tdls.h index bda94d24a7..a2db5348e0 100644 --- a/core/hdd/inc/wlan_hdd_tdls.h +++ b/core/hdd/inc/wlan_hdd_tdls.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -173,6 +173,16 @@ QDF_STATUS hdd_tdls_deregister_peer(void *userdata, uint32_t vdev_id, */ void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg); +/** + * hdd_config_tdls_with_band_switch() - configure tdls when band changes + * Disable tdls offchmode if only one of + * bands is supported + * Enable tdls offchmode if all band enable + * @hdd_ctx: Pointer to the HDD context + * + * Return: none + */ +void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx); #else static inline int wlan_hdd_tdls_antenna_switch(struct hdd_context *hdd_ctx, @@ -208,5 +218,9 @@ static inline void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg) { } +static inline void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) +{ +} + #endif /* End of FEATURE_WLAN_TDLS */ #endif /* __HDD_TDLS_H */ diff --git a/core/hdd/src/wlan_hdd_regulatory.c b/core/hdd/src/wlan_hdd_regulatory.c index 22d54b0941..c7eea9beb6 100644 --- a/core/hdd/src/wlan_hdd_regulatory.c +++ b/core/hdd/src/wlan_hdd_regulatory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-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 @@ -1454,6 +1454,8 @@ static void hdd_regulatory_dyn_cbk(struct wlan_objmgr_psoc *psoc, hdd_ch_avoid_ind(hdd_ctx, &avoid_freq_ind->chan_list, &avoid_freq_ind->freq_list); } else { + hdd_config_tdls_with_band_switch(hdd_ctx); + sme_generic_change_country_code(hdd_ctx->mac_handle, hdd_ctx->reg.alpha2); /*Check whether need restart SAP/P2p Go*/ diff --git a/core/hdd/src/wlan_hdd_tdls.c b/core/hdd/src/wlan_hdd_tdls.c index efc308abfe..87951d4226 100644 --- a/core/hdd/src/wlan_hdd_tdls.c +++ b/core/hdd/src/wlan_hdd_tdls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -43,6 +43,7 @@ #include #include "wlan_tdls_cfg_api.h" #include "wlan_hdd_object_manager.h" +#include /** * enum qca_wlan_vendor_tdls_trigger_mode_hdd_map: Maps the user space TDLS @@ -767,6 +768,18 @@ int hdd_set_tdls_offchannelmode(struct hdd_context *hdd_ctx, { struct wlan_objmgr_vdev *vdev; QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool tdls_off_ch; + + if (cfg_tdls_get_off_channel_enable( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch failed"); + return qdf_status_to_os_return(status); + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch is false, do nothing"); + return qdf_status_to_os_return(status); + } if (hdd_ctx->tdls_umac_comp_active) { vdev = hdd_objmgr_get_vdev(adapter); @@ -881,3 +894,65 @@ void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg) tdls_cfg->tdls_del_sta_req = eWNI_SME_TDLS_DEL_STA_REQ; tdls_cfg->tdls_update_peer_state = WMA_UPDATE_TDLS_PEER_STATE; } + +void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_vdev *tdls_obj_vdev; + int offchmode; + enum band_info current_band; + bool tdls_off_ch; + + if (!hdd_ctx) { + hdd_err("Invalid hdd_ctx"); + return; + } + + if (ucfg_reg_get_curr_band(hdd_ctx->pdev, ¤t_band) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to get current band config"); + return; + } + + /** + * If all bands are supported, in below condition off channel enable + * orig is false and nothing is need to do + * 1. band switch does not happen. + * 2. band switch happens and it already restores + * 3. tdls off channel is disabled by default. + * If 2g or 5g is not supported. Disable tdls off channel only when + * tdls off channel is enabled currently. + */ + if (current_band == BAND_ALL) { + if (cfg_tdls_get_off_channel_enable_orig( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch orig failed"); + return; + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch orig is false, do nothing"); + return; + } + offchmode = ENABLE_CHANSWITCH; + cfg_tdls_restore_off_channel_enable(hdd_ctx->psoc); + } else { + if (cfg_tdls_get_off_channel_enable( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch failed"); + return; + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch is false, do nothing"); + return; + } + offchmode = DISABLE_CHANSWITCH; + cfg_tdls_store_off_channel_enable(hdd_ctx->psoc); + cfg_tdls_set_off_channel_enable(hdd_ctx->psoc, false); + } + tdls_obj_vdev = ucfg_get_tdls_vdev(hdd_ctx->psoc, WLAN_TDLS_NB_ID); + if (tdls_obj_vdev) { + ucfg_set_tdls_offchan_mode(tdls_obj_vdev, offchmode); + wlan_objmgr_vdev_release_ref(tdls_obj_vdev, WLAN_TDLS_NB_ID); + } +}