aboutsummaryrefslogtreecommitdiff
path: root/net/mac80211/wext.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/wext.c')
-rw-r--r--net/mac80211/wext.c243
1 files changed, 148 insertions, 95 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 7162d5816f3..2b023dce8b2 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -37,7 +37,14 @@ static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta
struct ieee80211_key *key;
int err;
- if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
+ if (alg == ALG_AES_CMAC) {
+ if (idx < NUM_DEFAULT_KEYS ||
+ idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
+ printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d "
+ "(BIP)\n", sdata->dev->name, idx);
+ return -EINVAL;
+ }
+ } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
sdata->dev->name, idx);
return -EINVAL;
@@ -103,6 +110,9 @@ static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta
if (set_tx_key || (!sta && !sdata->default_key && key))
ieee80211_set_default_key(sdata, idx);
+ if (alg == ALG_AES_CMAC &&
+ (set_tx_key || (!sta && !sdata->default_mgmt_key && key)))
+ ieee80211_set_default_mgmt_key(sdata, idx);
}
out_unlock:
@@ -135,6 +145,21 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
return -EOPNOTSUPP;
}
+static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)
+{
+ u8 wstats_flags = 0;
+
+ wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DBM) ?
+ IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+ wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
+ IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ wstats_flags |= IW_QUAL_DBM;
+
+ return wstats_flags;
+}
+
static int ieee80211_ioctl_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
@@ -163,9 +188,9 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->num_encoding_sizes = 2;
range->max_encoding_tokens = NUM_DEFAULT_KEYS;
- if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC ||
- local->hw.flags & IEEE80211_HW_SIGNAL_DB)
- range->max_qual.level = local->hw.max_signal;
+ /* cfg80211 requires this, and enforces 0..100 */
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
+ range->max_qual.level = 100;
else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
range->max_qual.level = -110;
else
@@ -177,13 +202,13 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->max_qual.noise = 0;
range->max_qual.qual = 100;
- range->max_qual.updated = local->wstats_flags;
+ range->max_qual.updated = ieee80211_get_wstats_flags(local);
range->avg_qual.qual = 50;
/* not always true but better than nothing */
range->avg_qual.level = range->max_qual.level / 2;
range->avg_qual.noise = range->max_qual.noise / 2;
- range->avg_qual.updated = local->wstats_flags;
+ range->avg_qual.updated = ieee80211_get_wstats_flags(local);
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
@@ -230,13 +255,15 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
if (freq->e == 0) {
if (freq->m < 0) {
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.sta.flags |=
IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
@@ -404,58 +431,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
}
-static int ieee80211_ioctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct iw_scan_req *req = NULL;
- u8 *ssid = NULL;
- size_t ssid_len = 0;
-
- if (!netif_running(dev))
- return -ENETDOWN;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
- return -EOPNOTSUPP;
-
- /* if SSID was specified explicitly then use that */
- if (wrqu->data.length == sizeof(struct iw_scan_req) &&
- wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- req = (struct iw_scan_req *)extra;
- ssid = req->essid;
- ssid_len = req->essid_len;
- }
-
- return ieee80211_request_scan(sdata, ssid, ssid_len);
-}
-
-
-static int ieee80211_ioctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- int res;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (local->sw_scanning || local->hw_scanning)
- return -EAGAIN;
-
- res = ieee80211_scan_results(local, info, extra, data->length);
- if (res >= 0) {
- data->length = res;
- return 0;
- }
- data->length = 0;
- return res;
-}
-
-
static int ieee80211_ioctl_siwrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rate, char *extra)
@@ -549,10 +524,9 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
else /* Automatic power level setting */
new_power_level = chan->max_power;
- if (local->hw.conf.power_level != new_power_level) {
- local->hw.conf.power_level = new_power_level;
+ local->user_power_level = new_power_level;
+ if (local->hw.conf.power_level != new_power_level)
reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
- }
if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
local->hw.conf.radio_enabled = !(data->txpower.disabled);
@@ -836,6 +810,9 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
int ret = 0, timeout = 0;
bool ps;
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+ return -EOPNOTSUPP;
+
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;
@@ -852,31 +829,49 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
ps = true;
break;
default: /* Otherwise we ignore */
- break;
+ return -EINVAL;
}
+ if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
+ return -EINVAL;
+
if (wrq->flags & IW_POWER_TIMEOUT)
timeout = wrq->value / 1000;
-set:
- if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
+ set:
+ if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
return ret;
local->powersave = ps;
- local->dynamic_ps_timeout = timeout;
+ conf->dynamic_ps_timeout = timeout;
- if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
- if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
- local->dynamic_ps_timeout > 0)
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(local->dynamic_ps_timeout));
- else {
- if (local->powersave)
- conf->flags |= IEEE80211_CONF_PS;
- else
- conf->flags &= ~IEEE80211_CONF_PS;
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+ ret = ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
+
+ if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
+ return ret;
+
+ if (conf->dynamic_ps_timeout > 0 &&
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(conf->dynamic_ps_timeout));
+ } else {
+ if (local->powersave) {
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ conf->flags |= IEEE80211_CONF_PS;
+ ret = ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ } else {
+ conf->flags &= ~IEEE80211_CONF_PS;
+ ret = ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_PS);
+ if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+ ieee80211_send_nullfunc(local, sdata, 0);
+ del_timer_sync(&local->dynamic_ps_timer);
+ cancel_work_sync(&local->dynamic_ps_enable_work);
}
- ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
return ret;
@@ -903,11 +898,22 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_WPA_ENABLED:
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
case IW_AUTH_KEY_MGMT:
+ case IW_AUTH_CIPHER_GROUP_MGMT:
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ if (data->value & (IW_AUTH_CIPHER_WEP40 |
+ IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
+ sdata->u.sta.flags |=
+ IEEE80211_STA_TKIP_WEP_USED;
+ else
+ sdata->u.sta.flags &=
+ ~IEEE80211_STA_TKIP_WEP_USED;
+ }
break;
case IW_AUTH_DROP_UNENCRYPTED:
sdata->drop_unencrypted = !!data->value;
@@ -934,6 +940,29 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
else
ret = -EOPNOTSUPP;
break;
+ case IW_AUTH_MFP:
+ if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ switch (data->value) {
+ case IW_AUTH_MFP_DISABLED:
+ sdata->u.sta.mfp = IEEE80211_MFP_DISABLED;
+ break;
+ case IW_AUTH_MFP_OPTIONAL:
+ sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL;
+ break;
+ case IW_AUTH_MFP_REQUIRED:
+ sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else
+ ret = -EOPNOTSUPP;
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -965,7 +994,7 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
wstats->qual.level = sta->last_signal;
wstats->qual.qual = sta->last_qual;
wstats->qual.noise = sta->last_noise;
- wstats->qual.updated = local->wstats_flags;
+ wstats->qual.updated = ieee80211_get_wstats_flags(local);
}
rcu_read_unlock();
@@ -1017,6 +1046,9 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
case IW_ENCODE_ALG_CCMP:
alg = ALG_CCMP;
break;
+ case IW_ENCODE_ALG_AES_CMAC:
+ alg = ALG_AES_CMAC;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -1025,20 +1057,41 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
remove = 1;
idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!sdata->default_key)
- idx = 0;
- else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->default_key == sdata->keys[i]) {
- idx = i;
- break;
+ if (alg == ALG_AES_CMAC) {
+ if (idx < NUM_DEFAULT_KEYS + 1 ||
+ idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
+ idx = -1;
+ if (!sdata->default_mgmt_key)
+ idx = 0;
+ else for (i = NUM_DEFAULT_KEYS;
+ i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
+ i++) {
+ if (sdata->default_mgmt_key == sdata->keys[i])
+ {
+ idx = i;
+ break;
+ }
}
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ } else {
+ if (idx < 1 || idx > 4) {
+ idx = -1;
+ if (!sdata->default_key)
+ idx = 0;
+ else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (sdata->default_key == sdata->keys[i]) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ }
return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
remove,
@@ -1076,8 +1129,8 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
(iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
- (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */
- (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */
+ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
+ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
(iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
(iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
(iw_handler) NULL, /* SIOCSIWNICKN */