diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 59b81a730d0b..0d6bdb548a31 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2629,6 +2629,16 @@ struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx, const char *iface_name); enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width); +/** + * hdd_nl_to_qdf_iface_type() - map nl80211_iftype to QDF_OPMODE + * @nl_type: the input NL80211 interface type to map + * @out_qdf_type: the output, equivalent QDF operating mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_nl_to_qdf_iface_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type); + /** * wlan_hdd_find_opclass() - Find operating class for a channel * @mac_handle: global MAC handle diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 6586d2a2cb0e..f7de3dd6fa68 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -13001,61 +13001,56 @@ static int __wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, } /** - * wlan_hdd_change_client_iface_to_new_mode() - to change iface to provided mode - * @ndev: pointer to net device provided by supplicant - * @type: type of the interface, upper layer wanted to change + * hdd_change_adapter_mode() - change @adapter's operating mode to @new_mode + * @adapter: the adapter to change modes on + * @new_mode: the new operating mode to change to * - * Upper layer provides the new interface mode that needs to be changed - * for given net device - * - * Return: success or failure in terms of integer value + * Return: Errno */ -static int wlan_hdd_change_client_iface_to_new_mode(struct net_device *ndev, - enum nl80211_iftype type) +static int hdd_change_adapter_mode(struct hdd_adapter *adapter, + enum QDF_OPMODE new_mode) { - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct net_device *netdev = adapter->dev; struct hdd_config *config = hdd_ctx->config; struct csr_roam_profile *roam_profile; - struct wireless_dev *wdev; QDF_STATUS status = QDF_STATUS_SUCCESS; hdd_enter(); if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { - hdd_warn("ACS is in progress, don't change iface!"); + hdd_warn("Can't change interface: ACS in progress"); return -EBUSY; } - wdev = ndev->ieee80211_ptr; hdd_stop_adapter(hdd_ctx, adapter); hdd_deinit_adapter(hdd_ctx, adapter, true); - wdev->iftype = type; - /*Check for sub-string p2p to confirm its a p2p interface */ - if (NULL != strnstr(ndev->name, "p2p", 3)) { - adapter->device_mode = - (type == NL80211_IFTYPE_STATION) ? - QDF_P2P_DEVICE_MODE : QDF_P2P_CLIENT_MODE; - } else if (type == NL80211_IFTYPE_ADHOC) { - adapter->device_mode = QDF_IBSS_MODE; - } else { - adapter->device_mode = - (type == NL80211_IFTYPE_STATION) ? - QDF_STA_MODE : QDF_P2P_CLIENT_MODE; - } + + /* A userspace issue leads to it sending a 'change to station mode' + * request on a "p2p" device, expecting the driver do execute a 'change + * to p2p-device mode' request instead. The (unfortunate) work around + * here is implemented by overriding the new mode if the net_device name + * starts with "p2p" and the requested mode was station. + */ + if (strnstr(netdev->name, "p2p", 3) && new_mode == QDF_STA_MODE) + adapter->device_mode = QDF_P2P_DEVICE_MODE; + else + adapter->device_mode = new_mode; + memset(&adapter->session, 0, sizeof(adapter->session)); - hdd_set_station_ops(adapter->dev); + hdd_set_station_ops(netdev); roam_profile = hdd_roam_profile(adapter); roam_profile->pAddIEScan = adapter->scan_info.scan_add_ie.addIEdata; - roam_profile->nAddIEScanLength = - adapter->scan_info.scan_add_ie.length; - if (type == NL80211_IFTYPE_ADHOC) { + roam_profile->nAddIEScanLength = adapter->scan_info.scan_add_ie.length; + + if (new_mode == QDF_IBSS_MODE) { status = hdd_start_station_adapter(adapter); roam_profile->BSSType = eCSR_BSS_TYPE_START_IBSS; roam_profile->phyMode = hdd_cfg_xlate_to_csr_phy_mode(config->dot11Mode); } + hdd_exit(); return qdf_status_to_os_return(status); @@ -13094,7 +13089,9 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); struct hdd_context *hdd_ctx; int errno; - bool iff_up = (ndev->flags & IFF_UP); + bool iff_up = ndev->flags & IFF_UP; + enum QDF_OPMODE new_mode; + QDF_STATUS status; hdd_enter(); @@ -13112,8 +13109,20 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, adapter->session_id, type)); - hdd_debug("Device_mode = %d, IFTYPE = 0x%x", - adapter->device_mode, type); + wdev = ndev->ieee80211_ptr; + if (!wdev) { + hdd_err("Wireless dev is NULL"); + return -EINVAL; + } + + status = hdd_nl_to_qdf_iface_type(type, &new_mode); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_debug("Changing mode for '%s' from %s to %s", + ndev->name, + qdf_opmode_str(adapter->device_mode), + qdf_opmode_str(new_mode)); errno = hdd_wlan_start_modules(hdd_ctx, false); if (errno) { @@ -13128,14 +13137,12 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, return -EINVAL; } - wdev = ndev->ieee80211_ptr; - /* Reset the current device mode bit mask */ policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); if (adapter->device_mode != QDF_P2P_DEVICE_MODE || - type != NL80211_IFTYPE_STATION) { - hdd_debug("Teardown tdls links and disable tdls in FW as new interface is coming up"); + new_mode != QDF_STA_MODE) { + hdd_debug("Disable tdls; new interface is coming up"); hdd_notify_teardown_tdls_links(adapter->vdev); } @@ -13143,38 +13150,31 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, adapter->device_mode == QDF_P2P_CLIENT_MODE || adapter->device_mode == QDF_P2P_DEVICE_MODE || adapter->device_mode == QDF_IBSS_MODE) { - switch (type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_ADHOC: - if (type == NL80211_IFTYPE_ADHOC) { + switch (new_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + if (new_mode == QDF_IBSS_MODE) hdd_deregister_tx_flow_control(adapter); - hdd_debug("Setting interface Type to ADHOC"); - } - errno = wlan_hdd_change_client_iface_to_new_mode(ndev, - type); - if (errno) { - hdd_err("Failed to change iface to new mode:%d; errno:%d", - type, errno); + + errno = hdd_change_adapter_mode(adapter, new_mode); + if (errno) return errno; - } + if (iff_up) { - if (hdd_start_adapter(adapter)) { - hdd_err("Failed to start adapter: %d", - adapter->device_mode); + errno = hdd_start_adapter(adapter); + if (errno) { + hdd_err("Failed to start adapter"); return -EINVAL; } } - goto done; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - hdd_debug("Setting interface Type to %s", - (type == - NL80211_IFTYPE_AP) ? "SoftAP" : - "P2pGo"); - /* Cancel any remain on channel for GO mode */ - if (type == NL80211_IFTYPE_P2P_GO) { + wdev->iftype = type; + + goto done; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (new_mode == QDF_P2P_GO_MODE) { wlan_hdd_cancel_existing_remain_on_channel (adapter); } @@ -13182,12 +13182,7 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, hdd_stop_adapter(hdd_ctx, adapter); hdd_deinit_adapter(hdd_ctx, adapter, true); memset(&adapter->session, 0, sizeof(adapter->session)); - adapter->device_mode = type == NL80211_IFTYPE_AP ? - QDF_SAP_MODE : QDF_P2P_GO_MODE; - - /* - * Fw will take care incase of concurrency - */ + adapter->device_mode = new_mode; if (adapter->device_mode == QDF_SAP_MODE && hdd_ctx->config->apRandomBssidEnabled) { @@ -13210,61 +13205,59 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, hdd_set_ap_ops(adapter->dev); if (iff_up) { - if (hdd_start_adapter(adapter)) { - hdd_err("Failed to start adapter: %d", - adapter->device_mode); - return -EINVAL; + errno = hdd_start_adapter(adapter); + if (errno) { + hdd_err("Failed to start adapter"); + return errno; } } - /* Interface type changed update in wiphy structure */ - if (wdev) { - wdev->iftype = type; - } else { - hdd_err("Wireless dev is NULL"); - return -EINVAL; - } + wdev->iftype = type; goto done; default: - hdd_err("Unsupported interface type: %d", type); + hdd_err("Changing to device mode '%s' is not supported", + qdf_opmode_str(new_mode)); return -EOPNOTSUPP; } } else if (adapter->device_mode == QDF_SAP_MODE || adapter->device_mode == QDF_P2P_GO_MODE) { - switch (type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_ADHOC: - errno = wlan_hdd_change_client_iface_to_new_mode(ndev, - type); + switch (new_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + errno = hdd_change_adapter_mode(adapter, new_mode); if (errno) return errno; if (iff_up) { - if (hdd_start_adapter(adapter)) { - hdd_err("Failed to start adapter: %d", - adapter->device_mode); + errno = hdd_start_adapter(adapter); + if (errno) { + hdd_err("Failed to start adapter"); return -EINVAL; } } - goto done; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: wdev->iftype = type; - adapter->device_mode = type == NL80211_IFTYPE_AP ? - QDF_SAP_MODE : QDF_P2P_GO_MODE; - goto done; + goto done; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + wdev->iftype = type; + adapter->device_mode = new_mode; + + goto done; default: - hdd_err("Unsupported interface type: %d", type); + hdd_err("Changing to device mode '%s' is not supported", + qdf_opmode_str(new_mode)); return -EOPNOTSUPP; } } else { - hdd_err("Unsupported device mode: %d", adapter->device_mode); + hdd_err("Changing from device mode '%s' is not supported", + qdf_opmode_str(adapter->device_mode)); return -EOPNOTSUPP; } + done: /* Set bitmask based on updated value */ policy_mgr_set_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index a1b5c7ac7e3c..9622c49c2c8a 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -802,6 +802,45 @@ enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width) } } +QDF_STATUS hdd_nl_to_qdf_iface_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type) +{ + switch (nl_type) { + case NL80211_IFTYPE_ADHOC: + *out_qdf_type = QDF_IBSS_MODE; + break; + case NL80211_IFTYPE_AP: + *out_qdf_type = QDF_SAP_MODE; + break; + case NL80211_IFTYPE_MONITOR: + *out_qdf_type = QDF_MONITOR_MODE; + break; + case NL80211_IFTYPE_OCB: + *out_qdf_type = QDF_OCB_MODE; + break; + case NL80211_IFTYPE_P2P_CLIENT: + *out_qdf_type = QDF_P2P_CLIENT_MODE; + break; + case NL80211_IFTYPE_P2P_DEVICE: + *out_qdf_type = QDF_P2P_DEVICE_MODE; + break; + case NL80211_IFTYPE_P2P_GO: + *out_qdf_type = QDF_P2P_GO_MODE; + break; + case NL80211_IFTYPE_STATION: + *out_qdf_type = QDF_STA_MODE; + break; + case NL80211_IFTYPE_WDS: + *out_qdf_type = QDF_WDS_MODE; + break; + default: + hdd_err("Invalid nl80211 interface type %d", nl_type); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + uint8_t wlan_hdd_find_opclass(mac_handle_t mac_handle, uint8_t channel, uint8_t bw_offset) {