#include <net/mac80211.h>
#include "ieee80211_i.h"
-#include "hostapd_ioctl.h"
#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
+
static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
- int idx, int alg, int set_tx_key,
- const u8 *_key, size_t key_len)
+ int idx, int alg, int remove,
+ int set_tx_key, const u8 *_key,
+ size_t key_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int ret = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
+ printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
+ dev->name, idx);
+ return -EINVAL;
+ }
+
if (is_broadcast_ether_addr(sta_addr)) {
sta = NULL;
- if (idx >= NUM_DEFAULT_KEYS) {
- printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
- dev->name, idx);
- return -EINVAL;
- }
key = sdata->keys[idx];
} else {
set_tx_key = 0;
- if (idx != 0) {
+ /*
+ * According to the standard, the key index of a pairwise
+ * key must be zero. However, some AP are broken when it
+ * comes to WEP key indices, so we work around this.
+ */
+ if (idx != 0 && alg != ALG_WEP) {
printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
"individual key\n", dev->name);
return -EINVAL;
sta = sta_info_get(local, sta_addr);
if (!sta) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
- MAC_FMT "\n",
- dev->name, MAC_ARG(sta_addr));
+ "%s\n",
+ dev->name, print_mac(mac, sta_addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
return -ENOENT;
key = sta->key;
}
- if (alg == ALG_NONE) {
+ if (remove) {
ieee80211_key_free(key);
key = NULL;
} else {
/*
- * Need to free it before allocating a new one with
- * with the same index or the ordering to the driver's
- * set_key() callback becomes confused.
+ * Automatically frees any old key if present.
*/
- ieee80211_key_free(key);
key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
if (!key) {
ret = -ENOMEM;
struct iw_point *data, char *extra)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- if (local->user_space_mlme)
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
return -EOPNOTSUPP;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
return 0;
}
- if (sdata->type == IEEE80211_IF_TYPE_AP) {
- kfree(sdata->u.ap.generic_elem);
- sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
- if (!sdata->u.ap.generic_elem)
- return -ENOMEM;
- memcpy(sdata->u.ap.generic_elem, extra, data->length);
- sdata->u.ap.generic_elem_len = data->length;
- return ieee80211_if_config(dev);
- }
return -EOPNOTSUPP;
}
case MODE_IEEE80211G:
strcpy(name, "IEEE 802.11g");
break;
- case MODE_ATHEROS_TURBO:
- strcpy(name, "5GHz Turbo");
- break;
default:
strcpy(name, "IEEE 802.11");
break;
struct ieee80211_channel *chan = &mode->channels[c];
if (chan->flag & IEEE80211_CHAN_W_SCAN &&
((chan->chan == channel) || (chan->freq == freq))) {
- /* Use next_mode as the mode preference to
- * resolve non-unique channel numbers. */
- if (set && mode->mode != local->next_mode)
- continue;
-
local->oper_channel = chan;
local->oper_hw_mode = mode;
set++;
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
size_t len = data->length;
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
int ret;
- if (local->user_space_mlme) {
+ if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
if (len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
memcpy(sdata->u.sta.ssid, ssid, len);
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
int ret;
- if (local->user_space_mlme) {
+ if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
ETH_ALEN);
return 0;
struct ieee80211_rate *rates = &mode->rates[i];
int this_rate = rates->rate;
- if (mode->mode == MODE_ATHEROS_TURBO ||
- mode->mode == MODE_ATHEROS_TURBOG)
- this_rate *= 2;
if (target_rate == this_rate) {
sdata->bss->max_ratectrl_rateidx = i;
if (rate->fixed)
return 0;
}
+static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *data, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ bool need_reconfig = 0;
+
+ if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+ return -EINVAL;
+ if (data->txpower.flags & IW_TXPOW_RANGE)
+ return -EINVAL;
+ if (!data->txpower.fixed)
+ return -EINVAL;
+
+ if (local->hw.conf.power_level != data->txpower.value) {
+ local->hw.conf.power_level = data->txpower.value;
+ need_reconfig = 1;
+ }
+ if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
+ local->hw.conf.radio_enabled = !(data->txpower.disabled);
+ need_reconfig = 1;
+ }
+ if (need_reconfig) {
+ ieee80211_hw_config(local);
+ /* The return value of hw_config is not of big interest here,
+ * as it doesn't say that it failed because of _this_ config
+ * change or something else. Ignore it. */
+ }
+
+ return 0;
+}
+
static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
return 0;
}
-static int ieee80211_ioctl_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- void *wrqu, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata;
- int *i = (int *) extra;
- int param = *i;
- int value = *(i + 1);
- int ret = 0;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- switch (param) {
- case PRISM2_PARAM_IEEE_802_1X:
- if (local->ops->set_ieee8021x)
- ret = local->ops->set_ieee8021x(local_to_hw(local),
- value);
- if (ret)
- printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
- "for low-level driver\n", dev->name, value);
- else
- sdata->ieee802_1x = value;
- break;
-
- case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- if (sdata->type == IEEE80211_IF_TYPE_AP) {
- if (value)
- sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
- else
- sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
- ieee80211_erp_info_change_notify(dev,
- IEEE80211_ERP_CHANGE_PROTECTION);
- } else {
- ret = -ENOENT;
- }
- break;
-
- case PRISM2_PARAM_PREAMBLE:
- if (sdata->type != IEEE80211_IF_TYPE_AP) {
- if (value)
- sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
- else
- sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
- ieee80211_erp_info_change_notify(dev,
- IEEE80211_ERP_CHANGE_PREAMBLE);
- } else {
- ret = -ENOENT;
- }
- break;
-
- case PRISM2_PARAM_SHORT_SLOT_TIME:
- if (value)
- local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
- else
- local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_NEXT_MODE:
- local->next_mode = value;
- break;
-
- case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
- local->key_tx_rx_threshold = value;
- break;
-
- case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
- local->wifi_wme_noack_test = value;
- break;
-
- case PRISM2_PARAM_SCAN_FLAGS:
- local->scan_flags = value;
- break;
-
- case PRISM2_PARAM_MIXED_CELL:
- if (sdata->type != IEEE80211_IF_TYPE_STA &&
- sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else {
- if (value)
- sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL;
- else
- sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL;
- }
- break;
-
- case PRISM2_PARAM_HW_MODES:
- local->enabled_modes = value;
- break;
-
- case PRISM2_PARAM_CREATE_IBSS:
- if (sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else {
- if (value)
- sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS;
- else
- sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS;
- }
- break;
- case PRISM2_PARAM_WMM_ENABLED:
- if (sdata->type != IEEE80211_IF_TYPE_STA &&
- sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else {
- if (value)
- sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED;
- else
- sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED;
- }
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-
-static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- void *wrqu, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata;
- int *param = (int *) extra;
- int ret = 0;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- switch (*param) {
- case PRISM2_PARAM_IEEE_802_1X:
- *param = sdata->ieee802_1x;
- break;
-
- case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION);
- break;
-
- case PRISM2_PARAM_PREAMBLE:
- *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
- break;
-
- case PRISM2_PARAM_SHORT_SLOT_TIME:
- *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
- break;
-
- case PRISM2_PARAM_NEXT_MODE:
- *param = local->next_mode;
- break;
-
- case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
- *param = local->key_tx_rx_threshold;
- break;
-
- case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
- *param = local->wifi_wme_noack_test;
- break;
-
- case PRISM2_PARAM_SCAN_FLAGS:
- *param = local->scan_flags;
- break;
-
- case PRISM2_PARAM_HW_MODES:
- *param = local->enabled_modes;
- break;
-
- case PRISM2_PARAM_CREATE_IBSS:
- if (sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else
- *param = !!(sdata->u.sta.flags &
- IEEE80211_STA_CREATE_IBSS);
- break;
-
- case PRISM2_PARAM_MIXED_CELL:
- if (sdata->type != IEEE80211_IF_TYPE_STA &&
- sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else
- *param = !!(sdata->u.sta.flags &
- IEEE80211_STA_MIXED_CELL);
- break;
- case PRISM2_PARAM_WMM_ENABLED:
- if (sdata->type != IEEE80211_IF_TYPE_STA &&
- sdata->type != IEEE80211_IF_TYPE_IBSS)
- ret = -EINVAL;
- else
- *param = !!(sdata->u.sta.flags &
- IEEE80211_STA_WMM_ENABLED);
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
static int ieee80211_ioctl_siwmlme(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
struct ieee80211_sub_if_data *sdata;
int idx, i, alg = ALG_WEP;
u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ int remove = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
idx--;
if (erq->flags & IW_ENCODE_DISABLED)
- alg = ALG_NONE;
+ remove = 1;
else if (erq->length == 0) {
/* No key data - just set the default TX key index */
ieee80211_set_default_key(sdata, idx);
return ieee80211_set_encryption(
dev, bcaddr,
- idx, alg,
+ idx, alg, remove,
!sdata->default_key,
keybuf, erq->length);
}
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int alg, idx, i;
+ int uninitialized_var(alg), idx, i, remove = 0;
switch (ext->alg) {
case IW_ENCODE_ALG_NONE:
- alg = ALG_NONE;
+ remove = 1;
break;
case IW_ENCODE_ALG_WEP:
alg = ALG_WEP;
}
if (erq->flags & IW_ENCODE_DISABLED)
- alg = ALG_NONE;
+ remove = 1;
idx = erq->flags & IW_ENCODE_INDEX;
if (idx < 1 || idx > 4) {
idx--;
return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+ remove,
ext->ext_flags &
IW_ENCODE_EXT_SET_TX_KEY,
ext->key, ext->key_len);
}
-static const struct iw_priv_args ieee80211_ioctl_priv[] = {
- { PRISM2_IOCTL_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
- { PRISM2_IOCTL_GET_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
-};
-
/* Structures to export the Wireless Handlers */
static const iw_handler ieee80211_handler[] =
(iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
(iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
(iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
- iw_handler_set_spy, /* SIOCSIWSPY */
- iw_handler_get_spy, /* SIOCGIWSPY */
- iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
- iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+ (iw_handler) NULL, /* SIOCSIWTHRSPY */
+ (iw_handler) NULL, /* SIOCGIWTHRSPY */
(iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
(iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
(iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
(iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
(iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
(iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
+ (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
(iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
(iw_handler) NULL, /* -- hole -- */
};
-static const iw_handler ieee80211_private_handler[] =
-{ /* SIOCIWFIRSTPRIV + */
- (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */
- (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */
-};
-
const struct iw_handler_def ieee80211_iw_handler_def =
{
.num_standard = ARRAY_SIZE(ieee80211_handler),
- .num_private = ARRAY_SIZE(ieee80211_private_handler),
- .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
.standard = (iw_handler *) ieee80211_handler,
- .private = (iw_handler *) ieee80211_private_handler,
- .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
.get_wireless_stats = ieee80211_get_wireless_stats,
};