#include <linux/nl80211.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
+#include <linux/slab.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
+#include "wext-compat.h"
#include "core.h"
int cfg80211_wext_giwname(struct net_device *dev,
enum nl80211_iftype type;
int ret;
- if (!wdev)
- return -EOPNOTSUPP;
-
rdev = wiphy_to_dev(wdev->wiphy);
- if (!rdev->ops->change_virtual_intf)
- return -EOPNOTSUPP;
-
- /* don't support changing VLANs, you just re-create them */
- if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
- return -EOPNOTSUPP;
-
switch (*mode) {
case IW_MODE_INFRA:
type = NL80211_IFTYPE_STATION;
memset(&vifparams, 0, sizeof(vifparams));
- ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
- NULL, &vifparams);
- WARN_ON(!ret && wdev->iftype != type);
+ cfg80211_lock_rdev(rdev);
+ ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
+ cfg80211_unlock_rdev(rdev);
return ret;
}
* @wiphy: the wiphy
* @freq: the wext freq encoding
*
- * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
+ * Returns a frequency, or a negative error code, or 0 for auto.
*/
-struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
- struct iw_freq *freq)
+int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
{
- struct ieee80211_channel *chan;
- int f;
-
/*
- * Parse frequency - return NULL for auto and
+ * Parse frequency - return 0 for auto and
* -EINVAL for impossible things.
*/
if (freq->e == 0) {
if (freq->m < 0)
- return NULL;
- f = ieee80211_channel_to_frequency(freq->m);
+ return 0;
+ return ieee80211_channel_to_frequency(freq->m);
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
if (div <= 0)
- return ERR_PTR(-EINVAL);
- f = freq->m / div;
+ return -EINVAL;
+ return freq->m / div;
}
-
- /*
- * Look up channel struct and return -EINVAL when
- * it cannot be found.
- */
- chan = ieee80211_get_channel(wiphy, f);
- if (!chan)
- return ERR_PTR(-EINVAL);
- return chan;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_request_info *info,
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *addr,
- bool remove, bool tx_key, int idx,
- struct key_params *params)
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- int err;
+ int err, i;
+ bool rejoin = false;
+
+ if (!wdev->wext.keys) {
+ wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+ GFP_KERNEL);
+ if (!wdev->wext.keys)
+ return -ENOMEM;
+ for (i = 0; i < 6; i++)
+ wdev->wext.keys->params[i].key =
+ wdev->wext.keys->data[i];
+ }
+
+ if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+ wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (!wdev->current_bss)
+ return -ENOLINK;
+
if (!rdev->ops->set_default_mgmt_key)
return -EOPNOTSUPP;
return -EINVAL;
if (remove) {
- err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
- if (!err) {
- if (idx == wdev->wext.default_key)
- wdev->wext.default_key = -1;
- else if (idx == wdev->wext.default_mgmt_key)
- wdev->wext.default_mgmt_key = -1;
+ err = 0;
+ if (wdev->current_bss) {
+ /*
+ * If removing the current TX key, we will need to
+ * join a new IBSS without the privacy bit clear.
+ */
+ if (idx == wdev->wext.default_key &&
+ wdev->iftype == NL80211_IFTYPE_ADHOC) {
+ __cfg80211_leave_ibss(rdev, wdev->netdev, true);
+ rejoin = true;
+ }
+ err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
}
+ wdev->wext.connect.privacy = false;
/*
* Applications using wireless extensions expect to be
* able to delete keys that don't exist, so allow that.
*/
if (err == -ENOENT)
- return 0;
+ err = 0;
+ if (!err) {
+ if (!addr) {
+ wdev->wext.keys->params[idx].key_len = 0;
+ wdev->wext.keys->params[idx].cipher = 0;
+ }
+ if (idx == wdev->wext.default_key)
+ wdev->wext.default_key = -1;
+ else if (idx == wdev->wext.default_mgmt_key)
+ wdev->wext.default_mgmt_key = -1;
+ }
+
+ if (!err && rejoin)
+ err = cfg80211_ibss_wext_join(rdev, wdev);
return err;
- } else {
- if (addr)
- tx_key = false;
+ }
- if (cfg80211_validate_key_settings(params, idx, addr))
- return -EINVAL;
+ if (addr)
+ tx_key = false;
+
+ if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+ return -EINVAL;
+ err = 0;
+ if (wdev->current_bss)
err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
- if (err)
- return err;
+ if (err)
+ return err;
- if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+ if (!addr) {
+ wdev->wext.keys->params[idx] = *params;
+ memcpy(wdev->wext.keys->data[idx],
+ params->key, params->key_len);
+ wdev->wext.keys->params[idx].key =
+ wdev->wext.keys->data[idx];
+ }
+
+ if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+ (tx_key || (!addr && wdev->wext.default_key == -1))) {
+ if (wdev->current_bss) {
+ /*
+ * If we are getting a new TX key from not having
+ * had one before we need to join a new IBSS with
+ * the privacy bit set.
+ */
+ if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
+ wdev->wext.default_key == -1) {
+ __cfg80211_leave_ibss(rdev, wdev->netdev, true);
+ rejoin = true;
+ }
err = rdev->ops->set_default_key(&rdev->wiphy,
dev, idx);
- if (!err)
- wdev->wext.default_key = idx;
- return err;
}
+ if (!err) {
+ wdev->wext.default_key = idx;
+ if (rejoin)
+ err = cfg80211_ibss_wext_join(rdev, wdev);
+ }
+ return err;
+ }
- if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
- (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+ (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ if (wdev->current_bss)
err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
dev, idx);
- if (!err)
- wdev->wext.default_mgmt_key = idx;
- return err;
- }
-
- return 0;
+ if (!err)
+ wdev->wext.default_mgmt_key = idx;
+ return err;
}
+
+ return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
+{
+ int err;
+
+ /* devlist mutex needed for possible IBSS re-join */
+ mutex_lock(&rdev->devlist_mtx);
+ wdev_lock(dev->ieee80211_ptr);
+ err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+ tx_key, idx, params);
+ wdev_unlock(dev->ieee80211_ptr);
+ mutex_unlock(&rdev->devlist_mtx);
+
+ return err;
}
int cfg80211_wext_siwencode(struct net_device *dev,
bool remove = false;
struct key_params params;
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
+
/* no use -- only MFP (set_default_mgmt_key) is optional */
if (!rdev->ops->del_key ||
!rdev->ops->add_key ||
remove = true;
else if (erq->length == 0) {
/* No key data - just set the default TX key index */
- err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+ err = 0;
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ err = rdev->ops->set_default_key(&rdev->wiphy,
+ dev, idx);
if (!err)
wdev->wext.default_key = idx;
+ wdev_unlock(wdev);
return err;
}
struct key_params params;
u32 cipher;
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
+
/* no use -- only MFP (set_default_mgmt_key) is optional */
if (!rdev->ops->del_key ||
!rdev->ops->add_key ||
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
-struct giwencode_cookie {
- size_t buflen;
- char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
- struct giwencode_cookie *data = cookie;
-
- if (!params->key) {
- data->buflen = 0;
- return;
- }
-
- data->buflen = min_t(size_t, data->buflen, params->key_len);
- memcpy(data->keybuf, params->key, data->buflen);
-}
-
int cfg80211_wext_giwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *keybuf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- int idx, err;
- struct giwencode_cookie data = {
- .keybuf = keybuf,
- .buflen = erq->length,
- };
+ int idx;
- if (!rdev->ops->get_key)
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
idx = erq->flags & IW_ENCODE_INDEX;
erq->flags = idx + 1;
- err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
- giwencode_get_key_cb);
- if (!err) {
- erq->length = data.buflen;
- erq->flags |= IW_ENCODE_ENABLED;
- return 0;
- }
-
- if (err == -ENOENT) {
+ if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
erq->flags |= IW_ENCODE_DISABLED;
erq->length = 0;
return 0;
}
- return err;
+ erq->length = min_t(size_t, erq->length,
+ wdev->wext.keys->params[idx].key_len);
+ memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
+int cfg80211_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *wextfreq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int freq, err;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
+ default:
+ freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+ if (freq < 0)
+ return freq;
+ if (freq == 0)
+ return -EINVAL;
+ mutex_lock(&rdev->devlist_mtx);
+ err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT);
+ mutex_unlock(&rdev->devlist_mtx);
+ return err;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
+
+int cfg80211_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+ default:
+ if (!rdev->channel)
+ return -EINVAL;
+ freq->m = rdev->channel->center_freq;
+ freq->e = 6;
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq);
+
int cfg80211_wext_siwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
return 0;
}
- return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
+ return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
{
- wdev->wext.connect.crypto.wpa_versions = 0;
-
if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
- IW_AUTH_WPA_VERSION_WPA2))
+ IW_AUTH_WPA_VERSION_WPA2|
+ IW_AUTH_WPA_VERSION_DISABLED))
+ return -EINVAL;
+
+ if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
+ (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
+ IW_AUTH_WPA_VERSION_WPA2)))
return -EINVAL;
+ if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
+ wdev->wext.connect.crypto.wpa_versions &=
+ ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+
if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
wdev->wext.connect.crypto.wpa_versions |=
NL80211_WPA_VERSION_1;
return 0;
}
-int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
+static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
{
- wdev->wext.connect.crypto.cipher_group = 0;
-
if (cipher & IW_AUTH_CIPHER_WEP40)
wdev->wext.connect.crypto.cipher_group =
WLAN_CIPHER_SUITE_WEP40;
else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
wdev->wext.connect.crypto.cipher_group =
WLAN_CIPHER_SUITE_AES_CMAC;
+ else if (cipher & IW_AUTH_CIPHER_NONE)
+ wdev->wext.connect.crypto.cipher_group = 0;
else
return -EINVAL;
return 0;
}
-int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
+static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
{
int nr_ciphers = 0;
u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
}
-int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
+static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
{
int nr_akm_suites = 0;
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- bool ps = wdev->wext.ps;
- int timeout = wdev->wext.ps_timeout;
+ bool ps = wdev->ps;
+ int timeout = wdev->ps_timeout;
int err;
if (wdev->iftype != NL80211_IFTYPE_STATION)
if (err)
return err;
- wdev->wext.ps = ps;
- wdev->wext.ps_timeout = timeout;
+ wdev->ps = ps;
+ wdev->ps_timeout = timeout;
return 0;
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- wrq->disabled = !wdev->wext.ps;
+ wrq->disabled = !wdev->ps;
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
-int cfg80211_wds_wext_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *addr, char *extra)
+static int cfg80211_wds_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap);
-int cfg80211_wds_wext_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *addr, char *extra)
+static int cfg80211_wds_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
int cfg80211_wext_siwrate(struct net_device *dev,
struct iw_request_info *info,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_bitrate_mask mask;
+ u32 fixed, maxrate;
+ struct ieee80211_supported_band *sband;
+ int band, ridx;
+ bool match = false;
if (!rdev->ops->set_bitrate_mask)
return -EOPNOTSUPP;
- mask.fixed = 0;
- mask.maxrate = 0;
+ memset(&mask, 0, sizeof(mask));
+ fixed = 0;
+ maxrate = (u32)-1;
if (rate->value < 0) {
/* nothing */
} else if (rate->fixed) {
- mask.fixed = rate->value / 1000; /* kbps */
+ fixed = rate->value / 100000;
} else {
- mask.maxrate = rate->value / 1000; /* kbps */
+ maxrate = rate->value / 100000;
+ }
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ sband = wdev->wiphy->bands[band];
+ if (sband == NULL)
+ continue;
+ for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+ struct ieee80211_rate *srate = &sband->bitrates[ridx];
+ if (fixed == srate->bitrate) {
+ mask.control[band].legacy = 1 << ridx;
+ match = true;
+ break;
+ }
+ if (srate->bitrate <= maxrate) {
+ mask.control[band].legacy |= 1 << ridx;
+ match = true;
+ }
+ }
}
+ if (!match)
+ return -EINVAL;
+
return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
/* we are under RTNL - globally locked - so can use a static struct */
static struct station_info sinfo;
- u8 *addr;
+ u8 addr[ETH_ALEN];
int err;
if (wdev->iftype != NL80211_IFTYPE_STATION)
if (!rdev->ops->get_station)
return -EOPNOTSUPP;
- addr = wdev->wext.connect.bssid;
- if (!addr)
- return -EOPNOTSUPP;
+ err = 0;
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN);
+ else
+ err = -EOPNOTSUPP;
+ wdev_unlock(wdev);
+ if (err)
+ return err;
err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
if (err)
if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
return -EOPNOTSUPP;
- rate->value = 0;
-
- if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
- rate->value = 100000 * sinfo.txrate.legacy;
+ rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
return 0;
}
/* we are under RTNL - globally locked - so can use static structs */
static struct iw_statistics wstats;
static struct station_info sinfo;
- u8 *addr;
+ u8 bssid[ETH_ALEN];
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
return NULL;
if (!rdev->ops->get_station)
return NULL;
- addr = wdev->wext.connect.bssid;
- if (!addr)
+ /* Grab BSSID of current BSS, if any */
+ wdev_lock(wdev);
+ if (!wdev->current_bss) {
+ wdev_unlock(wdev);
return NULL;
+ }
+ memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
+ wdev_unlock(wdev);
- if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo))
+ if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo))
return NULL;
memset(&wstats, 0, sizeof(wstats));
return &wstats;
}
EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);
+
+int cfg80211_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_WDS:
+ return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwap);
+
+int cfg80211_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_WDS:
+ return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwap);
+
+int cfg80211_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid);
+
+int cfg80211_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
+
+int cfg80211_wext_siwpmksa(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_pmksa cfg_pmksa;
+ struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
+
+ memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa));
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+ cfg_pmksa.bssid = pmksa->bssid.sa_data;
+ cfg_pmksa.pmkid = pmksa->pmkid;
+
+ switch (pmksa->cmd) {
+ case IW_PMKSA_ADD:
+ if (!rdev->ops->set_pmksa)
+ return -EOPNOTSUPP;
+
+ return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
+
+ case IW_PMKSA_REMOVE:
+ if (!rdev->ops->del_pmksa)
+ return -EOPNOTSUPP;
+
+ return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
+
+ case IW_PMKSA_FLUSH:
+ if (!rdev->ops->flush_pmksa)
+ return -EOPNOTSUPP;
+
+ return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const iw_handler cfg80211_handlers[] = {
+ [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
+ [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,
+ [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq,
+ [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode,
+ [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode,
+ [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange,
+ [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap,
+ [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap,
+ [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme,
+ [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan,
+ [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan,
+ [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid,
+ [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid,
+ [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate,
+ [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate,
+ [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts,
+ [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts,
+ [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag,
+ [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag,
+ [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower,
+ [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower,
+ [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry,
+ [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry,
+ [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode,
+ [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode,
+ [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower,
+ [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower,
+ [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie,
+ [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth,
+ [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth,
+ [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,
+ [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa,
+};
+
+const struct iw_handler_def cfg80211_wext_handler = {
+ .num_standard = ARRAY_SIZE(cfg80211_handlers),
+ .standard = cfg80211_handlers,
+ .get_wireless_stats = cfg80211_wireless_stats,
+};