diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 969c2f0aa64c..3845c5ef12c7 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1545,7 +1545,7 @@ const char *hdd_get_fwpath(void); void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind); hdd_adapter_t *hdd_get_adapter_by_sme_session_id(hdd_context_t *hdd_ctx, uint32_t sme_session_id); - +phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width); uint8_t wlan_hdd_find_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset); diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index a6737ff9d503..d25e9ff99d6f 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -11115,6 +11115,7 @@ static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, uint8_t channel; uint16_t freq; int ret; + phy_ch_width ch_width; hddLog(LOG1, FL("Set Freq %d"), csa_params->chandef.chan->center_freq); @@ -11132,7 +11133,9 @@ static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, freq = csa_params->chandef.chan->center_freq; channel = cds_freq_to_chan(freq); - ret = hdd_softap_set_channel_change(dev, channel); + ch_width = hdd_map_nl_chan_width(csa_params->chandef.width); + + ret = hdd_softap_set_channel_change(dev, channel, ch_width); return ret; } diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index ba98484d1f91..6da5ebba25a9 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1701,7 +1701,8 @@ CDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, FL("Channel change indication from peer for channel %d"), pSapEvent->sapevt.sap_chan_cng_ind.new_chan); if (hdd_softap_set_channel_change(dev, - pSapEvent->sapevt.sap_chan_cng_ind.new_chan)) + pSapEvent->sapevt.sap_chan_cng_ind.new_chan, + CH_WIDTH_MAX)) return CDF_STATUS_E_FAILURE; else return CDF_STATUS_SUCCESS; @@ -1893,10 +1894,13 @@ int hdd_softap_unpack_ie(tHalHandle halHandle, * * @dev: pointer to the net device. * @target_channel: target channel number. + * @target_bw: Target bandwidth to move. + * If no bandwidth is specified, the value is CH_WIDTH_MAX * * Return: 0 for success, non zero for failure */ -int hdd_softap_set_channel_change(struct net_device *dev, int target_channel) +int hdd_softap_set_channel_change(struct net_device *dev, int target_channel, + phy_ch_width target_bw) { CDF_STATUS status; int ret = 0; @@ -1960,12 +1964,13 @@ int hdd_softap_set_channel_change(struct net_device *dev, int target_channel) p_cds_context, #endif (uint32_t) - target_channel); + target_channel, + target_bw); if (CDF_STATUS_SUCCESS != status) { hddLog(LOGE, - FL("SAP set channel failed for channel = %d"), - target_channel); + FL("SAP set channel failed for channel = %d, bw:%d"), + target_channel, target_bw); /* * If channel change command fails then clear the * radar found flag and also restart the netif @@ -2287,7 +2292,8 @@ static __iw_softap_setparam(struct net_device *dev, hddLog(LOG1, "SET Channel Change to new channel= %d", set_value); - ret = hdd_softap_set_channel_change(dev, set_value); + ret = hdd_softap_set_channel_change(dev, set_value, + CH_WIDTH_MAX); } else { hddLog(LOGE, FL("Channel Change Failed, Device in test mode")); diff --git a/core/hdd/src/wlan_hdd_hostapd.h b/core/hdd/src/wlan_hdd_hostapd.h index f57cb1c4b677..46dc54ebc8f9 100644 --- a/core/hdd/src/wlan_hdd_hostapd.h +++ b/core/hdd/src/wlan_hdd_hostapd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -58,7 +58,8 @@ eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]); int hdd_softap_set_channel_change(struct net_device *dev, - int target_channel); + int target_channel, + phy_ch_width target_bw); eCsrEncryptionType hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 98c560fc010c..fd30caf42c52 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -349,6 +349,39 @@ static int con_mode; /* Variable to hold connection mode including module parameter con_mode */ static int curr_con_mode; +/** + * hdd_map_nl_chan_width() - Map NL channel width to internal representation + * @ch_width: NL channel width + * + * Converts the NL channel width to the driver's internal representation + * + * Return: Converted channel width. In case of non matching NL channel width, + * CH_WIDTH_MAX will be returned. + */ +phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width) +{ + switch (ch_width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + return CH_WIDTH_20MHZ; + case NL80211_CHAN_WIDTH_40: + return CH_WIDTH_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_80P80: + return CH_WIDTH_80P80MHZ; + case NL80211_CHAN_WIDTH_160: + return CH_WIDTH_160MHZ; + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + default: + hdd_err("Invalid channel width %d, setting to default", + ch_width); + return CH_WIDTH_MAX; + } +} + /* wlan_hdd_find_opclass() - Find operating class for a channel * @hal: handler to HAL * @channel: channel id diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index cdc23d7dd2eb..e69dbf26b9d9 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -300,7 +300,8 @@ typedef enum ch_width { CH_WIDTH_40MHZ = 1, CH_WIDTH_80MHZ = 2, CH_WIDTH_160MHZ = 3, - CH_WIDTH_80P80MHZ = 4 + CH_WIDTH_80P80MHZ = 4, + CH_WIDTH_MAX } phy_ch_width; /** diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index ffe912c33b2b..165efe61c290 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -841,7 +841,7 @@ CDF_STATUS wlansap_disassoc_sta(void *p_cds_gctx, CDF_STATUS wlansap_deauth_sta(void *p_cds_gctx, struct tagCsrDelStaParams *pDelStaParams); CDF_STATUS wlansap_set_channel_change_with_csa(void *p_cds_gctx, - uint32_t targetChannel); + uint32_t targetChannel, phy_ch_width target_bw); CDF_STATUS wlansap_set_key_sta(void *p_cds_gctx, tCsrRoamSetKey *pSetKeyInfo); CDF_STATUS wlansap_get_assoc_stations(void *p_cds_gctx, diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index 40fcc28bd150..2bbeccc2e7bb 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1483,32 +1483,20 @@ static CDF_STATUS wlansap_update_csa_channel_params(ptSapContext sap_context, return CDF_STATUS_SUCCESS; } -/*========================================================================== - FUNCTION wlansap_set_channel_change_with_csa - - DESCRIPTION - This api function does a channel change to the target channel specified - through an iwpriv. CSA IE is included in the beacons before doing a - channel change. - - DEPENDENCIES - NA. - - PARAMETERS - - IN - p_cds_gctx : Pointer to cds global context structure - targetChannel : New target channel to change to. - - RETURN VALUE - The CDF_STATUS code associated with performing the operation - - CDF_STATUS_SUCCESS: Success - - SIDE EFFECTS - ============================================================================*/ +/** + * wlansap_set_channel_change_with_csa() - Set channel change with CSA + * @p_cds_gctx: Pointer to cds global context structure + * @targetChannel: Target channel + * @target_bw: Target bandwidth + * + * This api function does a channel change to the target channel specified. + * CSA IE is included in the beacons before doing a channel change. + * + * Return: CDF_STATUS + */ CDF_STATUS -wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel) +wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel, + phy_ch_width target_bw) { ptSapContext sapContext = NULL; @@ -1575,11 +1563,41 @@ wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel) pMac->sap.SapDfsInfo.target_channel = targetChannel; pMac->sap.SapDfsInfo.new_ch_params.ch_width = pMac->sap.SapDfsInfo.new_chanWidth; + + /* By this time, the best bandwidth is calculated for + * the given target channel. Now, if there was a + * request from user to move to a selected bandwidth, + * we can see if it can be honored. + * + * Ex1: BW80 was selected for the target channel and + * user wants BW40, it can be allowed + * Ex2: BW40 was selected for the target channel and + * user wants BW80, it cannot be allowed for the given + * target channel. + * + * So, the MIN of the selected channel bandwidth and + * user input is used for the bandwidth + */ + if (target_bw != CH_WIDTH_MAX) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s: target bw:%d new width:%d", + __func__, target_bw, + pMac->sap.SapDfsInfo. + new_ch_params.ch_width); + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth = + CDF_MIN(pMac->sap.SapDfsInfo. + new_ch_params.ch_width, + target_bw); + } + sme_set_ch_params(hHal, sapContext->csr_roamProfile.phyMode, targetChannel, 0, &pMac->sap.SapDfsInfo.new_ch_params); + /* * Set the CSA IE required flag. */