diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 498 |
1 files changed, 351 insertions, 147 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c78ea873a63a..87671446e24b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -20,6 +20,23 @@ #include "cfg80211.h" #include "main.h" +static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { + { + .max = 1, .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, +}; + /* * This function maps the nl802.11 channel type into driver channel type. * @@ -67,7 +84,7 @@ mwifiex_is_alg_wep(u32 cipher) /* * This function retrieves the private structure from kernel wiphy structure. */ -static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) +static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy) { return (void *) (*(unsigned long *) wiphy_priv(wiphy)); } @@ -80,8 +97,10 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); + const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; - if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { + if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) { wiphy_err(wiphy, "deleting the crypto keys\n"); return -EFAULT; } @@ -98,7 +117,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct mwifiex_power_cfg power_cfg; int dbm = MBM_TO_DBM(mbm); @@ -109,6 +129,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, power_cfg.is_power_auto = 1; } + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + return mwifiex_set_tx_power(priv, &power_cfg); } @@ -148,7 +170,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, if (!priv->sec_info.wep_enabled) return 0; - if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) { + if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) { wiphy_err(wiphy, "set default Tx key index\n"); return -EFAULT; } @@ -165,9 +187,11 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, struct key_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); + const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; if (mwifiex_set_encode(priv, params->key, params->key_len, - key_index, 0)) { + key_index, peer_mac, 0)) { wiphy_err(wiphy, "crypto keys added\n"); return -EFAULT; } @@ -192,13 +216,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) enum ieee80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; /* Set country code */ - domain_info->country_code[0] = priv->country_code[0]; - domain_info->country_code[1] = priv->country_code[1]; + domain_info->country_code[0] = adapter->country_code[0]; + domain_info->country_code[1] = adapter->country_code[1]; domain_info->country_code[2] = ' '; band = mwifiex_band_to_radio_type(adapter->config_bands); @@ -250,6 +274,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) domain_info->no_of_triplet = no_of_triplet; + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); @@ -272,12 +298,12 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) static int mwifiex_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); - wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" - " %c%c\n", request->alpha2[0], request->alpha2[1]); + wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n", + request->alpha2[0], request->alpha2[1]); - memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); switch (request->initiator) { case NL80211_REGDOM_SET_BY_DRIVER: @@ -361,33 +387,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, if (mwifiex_bss_set_channel(priv, &cfp)) return -EFAULT; - return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); -} - -/* - * CFG802.11 operation handler to set channel. - * - * This function can only be used when station is not connected. - */ -static int -mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - struct mwifiex_private *priv; - - if (dev) - priv = mwifiex_netdev_get_priv(dev); + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); else - priv = mwifiex_cfg80211_get_priv(wiphy); - - if (priv->media_connected) { - wiphy_err(wiphy, "This setting is valid only when station " - "is not connected\n"); - return -EINVAL; - } - - return mwifiex_set_rf_channel(priv, chan, channel_type); + return mwifiex_uap_set_channel(priv, cfp.channel); } /* @@ -399,18 +402,13 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) { - int ret; - if (frag_thr < MWIFIEX_FRAG_MIN_VALUE || frag_thr > MWIFIEX_FRAG_MAX_VALUE) - return -EINVAL; - - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, FRAG_THRESH_I, - &frag_thr); + frag_thr = MWIFIEX_FRAG_MAX_VALUE; - return ret; + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr); } /* @@ -439,19 +437,85 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) static int mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret = 0; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; + struct mwifiex_uap_bss_param *bss_cfg; + int ret, bss_started, i; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + + switch (priv->bss_role) { + case MWIFIEX_BSS_ROLE_UAP: + bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), + GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + mwifiex_set_sys_config_invalid_data(bss_cfg); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + bss_cfg->rts_threshold = wiphy->rts_threshold; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + bss_cfg->frag_threshold = wiphy->frag_threshold; + if (changed & WIPHY_PARAM_RETRY_LONG) + bss_cfg->retry_limit = wiphy->retry_long; + + bss_started = priv->bss_started; + + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, + NULL); + if (ret) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + kfree(bss_cfg); + return ret; + } - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - ret = mwifiex_set_rts(priv, wiphy->rts_threshold); - if (ret) - return ret; - } + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg); - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) - ret = mwifiex_set_frag(priv, wiphy->frag_threshold); + kfree(bss_cfg); - return ret; + if (ret) { + wiphy_err(wiphy, "Failed to set bss config\n"); + return ret; + } + + if (!bss_started) + break; + + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, + NULL); + if (ret) { + wiphy_err(wiphy, "Failed to start BSS\n"); + return ret; + } + + break; + case MWIFIEX_BSS_ROLE_STA: + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = mwifiex_set_rts(priv, + wiphy->rts_threshold); + if (ret) + return ret; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + ret = mwifiex_set_frag(priv, + wiphy->frag_threshold); + if (ret) + return ret; + } + break; + } + } + + return 0; } /* @@ -466,31 +530,59 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - if (priv->bss_mode == type) { - wiphy_warn(wiphy, "already set to required type\n"); - return 0; - } - - priv->bss_mode = type; - - switch (type) { + switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_ADHOC: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; - wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); + switch (type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); + case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_AP: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } break; case NL80211_IFTYPE_STATION: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - wiphy_dbg(wiphy, "info: setting interface type to managed\n"); + switch (type) { + case NL80211_IFTYPE_ADHOC: + break; + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); + case NL80211_IFTYPE_STATION: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_AP: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + break; + case NL80211_IFTYPE_AP: + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); + case NL80211_IFTYPE_AP: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } break; - case NL80211_IFTYPE_UNSPECIFIED: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - wiphy_dbg(wiphy, "info: setting interface type to auto\n"); - return 0; default: - wiphy_err(wiphy, "unknown interface type: %d\n", type); - return -EINVAL; + wiphy_err(wiphy, "%s: unknown iftype: %d\n", + dev->name, dev->ieee80211_ptr->iftype); + return -EOPNOTSUPP; } + dev->ieee80211_ptr->iftype = type; + priv->bss_mode = type; mwifiex_deauthenticate(priv, NULL); priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; @@ -804,6 +896,90 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, return 0; } +/* cfg80211 operation handler for stop ap. + * Function stops BSS running at uAP interface. + */ +static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (mwifiex_del_mgmt_ies(priv)) + wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + return -1; + } + + return 0; +} + +/* cfg80211 operation handler for start_ap. + * Function sets beacon period, DTIM period, SSID and security into + * AP config structure. + * AP is configured with these settings and BSS is started. + */ +static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + struct mwifiex_uap_bss_param *bss_cfg; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) + return -1; + if (mwifiex_set_mgmt_ies(priv, params)) + return -1; + + bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + mwifiex_set_sys_config_invalid_data(bss_cfg); + + if (params->beacon_interval) + bss_cfg->beacon_period = params->beacon_interval; + if (params->dtim_period) + bss_cfg->dtim_period = params->dtim_period; + + if (params->ssid && params->ssid_len) { + memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); + bss_cfg->ssid.ssid_len = params->ssid_len; + } + + if (mwifiex_set_secure_params(priv, bss_cfg, params)) { + kfree(bss_cfg); + wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); + return -1; + } + + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + kfree(bss_cfg); + return -1; + } + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg)) { + wiphy_err(wiphy, "Failed to set the SSID\n"); + kfree(bss_cfg); + return -1; + } + + kfree(bss_cfg); + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to start the BSS\n"); + return -1; + } + + return 0; +} + /* * CFG802.11 operation handler for disconnection request. * @@ -923,7 +1099,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, priv->wep_key_curr_index = 0; priv->sec_info.encryption_mode = 0; priv->sec_info.is_authtype_auto = 0; - ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); + ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1); if (mode == NL80211_IFTYPE_ADHOC) { /* "privacy" is set only for ad-hoc mode */ @@ -971,7 +1147,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, " with key len %d\n", sme->key_len); priv->wep_key_curr_index = sme->key_idx; ret = mwifiex_set_encode(priv, sme->key, sme->key_len, - sme->key_idx, 0); + sme->key_idx, NULL, 0); } } done: @@ -1050,6 +1226,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, goto done; } + if (priv->bss_mode == NL80211_IFTYPE_AP) { + wiphy_err(wiphy, "skip association request for AP interface\n"); + goto done; + } + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); @@ -1283,15 +1464,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, u32 *flags, struct vif_params *params) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - struct mwifiex_adapter *adapter; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; + struct wireless_dev *wdev; - if (!priv) - return NULL; - - adapter = priv->adapter; if (!adapter) return NULL; @@ -1299,12 +1477,21 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; if (priv->bss_mode) { - wiphy_err(wiphy, "cannot create multiple" - " station/adhoc interfaces\n"); + wiphy_err(wiphy, + "cannot create multiple sta/adhoc ifaces\n"); return NULL; } + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) + return NULL; + + wdev->wiphy = wiphy; + priv->wdev = wdev; + wdev->iftype = NL80211_IFTYPE_STATION; + if (type == NL80211_IFTYPE_UNSPECIFIED) priv->bss_mode = NL80211_IFTYPE_STATION; else @@ -1312,11 +1499,36 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_type = MWIFIEX_BSS_TYPE_STA; priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; - priv->bss_priority = 0; + priv->bss_priority = MWIFIEX_BSS_ROLE_STA; priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_num = 0; break; + case NL80211_IFTYPE_AP: + priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; + + if (priv->bss_mode) { + wiphy_err(wiphy, "Can't create multiple AP interfaces"); + return NULL; + } + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) + return NULL; + + priv->wdev = wdev; + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_AP; + + priv->bss_type = MWIFIEX_BSS_TYPE_UAP; + priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = MWIFIEX_BSS_ROLE_UAP; + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + priv->bss_started = 0; + priv->bss_num = 0; + priv->bss_mode = type; + + break; default: wiphy_err(wiphy, "type not supported\n"); return NULL; @@ -1329,6 +1541,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, goto error; } + mwifiex_init_priv_params(priv, dev); + priv->netdev = dev; + + mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + + if (adapter->config_bands & BAND_A) + mwifiex_setup_ht_caps( + &wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + dev_net_set(dev, wiphy_net(wiphy)); dev->ieee80211_ptr = priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; @@ -1343,9 +1564,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, mdev_priv = netdev_priv(dev); *((unsigned long *) mdev_priv) = (unsigned long) priv; - priv->netdev = dev; - mwifiex_init_priv_params(priv, dev); - SET_NETDEV_DEV(dev, adapter->dev); /* Register network device */ @@ -1417,7 +1635,6 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .get_station = mwifiex_cfg80211_get_station, .dump_station = mwifiex_cfg80211_dump_station, .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, - .set_channel = mwifiex_cfg80211_set_channel, .join_ibss = mwifiex_cfg80211_join_ibss, .leave_ibss = mwifiex_cfg80211_leave_ibss, .add_key = mwifiex_cfg80211_add_key, @@ -1426,6 +1643,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, .set_tx_power = mwifiex_cfg80211_set_tx_power, .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, + .start_ap = mwifiex_cfg80211_start_ap, + .stop_ap = mwifiex_cfg80211_stop_ap, .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, }; @@ -1436,82 +1655,67 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { * default parameters and handler function pointers, and finally * registers the device. */ -int mwifiex_register_cfg80211(struct mwifiex_private *priv) + +int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) { int ret; void *wdev_priv; - struct wireless_dev *wdev; - struct ieee80211_sta_ht_cap *ht_info; + struct wiphy *wiphy; + struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; u8 *country_code; - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) { - dev_err(priv->adapter->dev, "%s: allocating wireless device\n", - __func__); - return -ENOMEM; - } - wdev->wiphy = - wiphy_new(&mwifiex_cfg80211_ops, - sizeof(struct mwifiex_private *)); - if (!wdev->wiphy) { - kfree(wdev); + /* create a new wiphy for use with cfg80211 */ + wiphy = wiphy_new(&mwifiex_cfg80211_ops, + sizeof(struct mwifiex_adapter *)); + if (!wiphy) { + dev_err(adapter->dev, "%s: creating new wiphy\n", __func__); return -ENOMEM; } - wdev->iftype = NL80211_IFTYPE_STATION; - wdev->wiphy->max_scan_ssids = 10; - wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; - ht_info = &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap; - mwifiex_setup_ht_caps(ht_info, priv); - - if (priv->adapter->config_bands & BAND_A) { - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; - ht_info = &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap; - mwifiex_setup_ht_caps(ht_info, priv); - } else { - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - } + wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + + wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; + if (adapter->config_bands & BAND_A) + wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + else + wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; + wiphy->n_iface_combinations = 1; /* Initialize cipher suits */ - wdev->wiphy->cipher_suites = mwifiex_cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + wiphy->cipher_suites = mwifiex_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY; /* Reserve space for mwifiex specific private data for BSS */ - wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); - - wdev->wiphy->reg_notifier = mwifiex_reg_notifier; + wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); - /* Set struct mwifiex_private pointer in wiphy_priv */ - wdev_priv = wiphy_priv(wdev->wiphy); + wiphy->reg_notifier = mwifiex_reg_notifier; - *(unsigned long *) wdev_priv = (unsigned long) priv; + /* Set struct mwifiex_adapter pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wiphy); + *(unsigned long *)wdev_priv = (unsigned long)adapter; - set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev); + set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev); - ret = wiphy_register(wdev->wiphy); + ret = wiphy_register(wiphy); if (ret < 0) { - dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", - __func__); - wiphy_free(wdev->wiphy); - kfree(wdev); + dev_err(adapter->dev, + "%s: wiphy_register failed: %d\n", __func__, ret); + wiphy_free(wiphy); return ret; - } else { - dev_dbg(priv->adapter->dev, - "info: successfully registered wiphy device\n"); } - country_code = mwifiex_11d_code_2_region(priv->adapter->region_code); - if (country_code && regulatory_hint(wdev->wiphy, country_code)) - dev_err(priv->adapter->dev, - "%s: regulatory_hint failed\n", __func__); - - priv->wdev = wdev; + if (country_code && regulatory_hint(wiphy, country_code)) + dev_err(adapter->dev, "regulatory_hint() failed\n"); + adapter->wiphy = wiphy; return ret; } |