#include "aes_ccm.h"
#include "debugfs_key.h"
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
static void ieee80211_set_hw_encryption(struct net_device *dev,
struct sta_info *sta, u8 addr[ETH_ALEN],
struct ieee80211_key *key)
int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
if (ret)
return ret;
- sdata->u.sta.auto_bssid_sel = 0;
+ sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
ieee80211_sta_req_auth(dev, &sdata->u.sta);
return 0;
}
return -EOPNOTSUPP;
}
-static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev,
- int val)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_conf *conf = &local->hw.conf;
-
- conf->radio_enabled = val;
- return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr));
-}
-
static int ieee80211_ioctl_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
}
-struct ieee80211_channel_range {
- short start_freq;
- short end_freq;
- unsigned char power_level;
- unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
- { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
- { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
- { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
- { 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
- { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
- { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
- { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
- ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(struct net_device *dev, int mode,
- struct ieee80211_channel *chan)
-{
- int i;
-
- chan->flag = 0;
-
- if (ieee80211_regdom == 64 &&
- (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
- /* Do not allow Turbo modes in Japan. */
- return;
- }
-
- for (i = 0; channel_range[i].start_freq; i++) {
- const struct ieee80211_channel_range *r = &channel_range[i];
- if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
- if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
- chan->freq >= 5260 && chan->freq <= 5320) {
- /*
- * Skip new channels in Japan since the
- * firmware was not marked having been upgraded
- * by the vendor.
- */
- continue;
- }
-
- if (ieee80211_regdom == 0x10 &&
- (chan->freq == 5190 || chan->freq == 5210 ||
- chan->freq == 5230)) {
- /* Skip MKK channels when in FCC domain. */
- continue;
- }
-
- chan->flag |= IEEE80211_CHAN_W_SCAN |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_IBSS;
- chan->power_level = r->power_level;
- chan->antenna_max = r->antenna_max;
-
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5170 || chan->freq == 5190 ||
- chan->freq == 5210 || chan->freq == 5230)) {
- /*
- * New regulatory rules in Japan have backwards
- * compatibility with old channels in 5.15-5.25
- * GHz band, but the station is not allowed to
- * use active scan on these old channels.
- */
- chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
- }
-
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5260 || chan->freq == 5280 ||
- chan->freq == 5300 || chan->freq == 5320)) {
- /*
- * IBSS is not allowed on 5.25-5.35 GHz band
- * due to radar detection requirements.
- */
- chan->flag &= ~IEEE80211_CHAN_W_IBSS;
- }
-
- break;
- }
- }
-}
-
-
-static int ieee80211_unmask_channels(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int c;
-
- list_for_each_entry(mode, &local->modes_list, list) {
- for (c = 0; c < mode->num_channels; c++) {
- ieee80211_unmask_channel(dev, mode->mode,
- &mode->channels[c]);
- }
- }
- return 0;
-}
-
-
-int ieee80211_init_client(struct net_device *dev)
-{
- if (ieee80211_regdom == 0x40)
- channel_range = ieee80211_mkk_channels;
- ieee80211_unmask_channels(dev);
- return 0;
-}
-
-
static int ieee80211_ioctl_siwmode(struct net_device *dev,
struct iw_request_info *info,
__u32 *mode, char *extra)
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_STA)
- sdata->u.sta.auto_channel_sel = 0;
+ 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->type == IEEE80211_IF_TYPE_STA)
- sdata->u.sta.auto_channel_sel = 1;
+ sdata->u.sta.flags |=
+ IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
} else
return ieee80211_set_channel(local, freq->m, -1);
sdata->u.sta.ssid_len = len;
return 0;
}
- sdata->u.sta.auto_ssid_sel = !data->flags;
+ if (data->flags)
+ sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
+ else
+ sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
ret = ieee80211_sta_set_ssid(dev, ssid, len);
if (ret)
return ret;
ETH_ALEN);
return 0;
}
- if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
- sdata->u.sta.auto_bssid_sel = 1;
- sdata->u.sta.auto_channel_sel = 1;
- } else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
- sdata->u.sta.auto_bssid_sel = 1;
+ if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
+ sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL;
+ else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+ sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
else
- sdata->u.sta.auto_bssid_sel = 0;
+ sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
if (ret)
return ret;
if (!netif_running(dev))
return -ENETDOWN;
- if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
- if (sdata->type == IEEE80211_IF_TYPE_STA ||
- sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
ssid = sdata->u.sta.ssid;
ssid_len = sdata->u.sta.ssid_len;
- } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ }
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
ssid = sdata->u.ap.ssid;
ssid_len = sdata->u.ap.ssid_len;
- } else
- return -EINVAL;
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
}
+
return ieee80211_sta_req_scan(dev, ssid, ssid_len);
}
}
+static int ieee80211_ioctl_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int i;
+ u32 target_rate = rate->value / 100000;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!sdata->bss)
+ return -ENODEV;
+ mode = local->oper_hw_mode;
+ /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+ * target_rate = X, rate->fixed = 1 means only rate X
+ * target_rate = X, rate->fixed = 0 means all rates <= X */
+ sdata->bss->max_ratectrl_rateidx = -1;
+ sdata->bss->force_unicast_rateidx = -1;
+ if (rate->value < 0)
+ return 0;
+ for (i=0; i< mode->num_rates; i++) {
+ 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)
+ sdata->bss->force_unicast_rateidx = i;
+ break;
+ }
+ }
+ return 0;
+}
+
static int ieee80211_ioctl_giwrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rate, char *extra)
return 0;
}
+static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *data, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ data->txpower.fixed = 1;
+ data->txpower.disabled = !(local->hw.conf.radio_enabled);
+ data->txpower.value = local->hw.conf.power_level;
+ data->txpower.flags = IW_TXPOW_DBM;
+
+ return 0;
+}
+
static int ieee80211_ioctl_siwrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rts, char *extra)
return 0;
}
-static int ieee80211_ioctl_clear_keys(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_key_conf key;
- int i;
- u8 addr[ETH_ALEN];
- struct ieee80211_key_conf *keyconf;
- struct ieee80211_sub_if_data *sdata;
- struct sta_info *sta;
-
- memset(addr, 0xff, ETH_ALEN);
- read_lock(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list) {
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- keyconf = NULL;
- if (sdata->keys[i] &&
- !sdata->keys[i]->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local,
- sdata->keys[i])))
- local->ops->set_key(local_to_hw(local),
- DISABLE_KEY, addr,
- keyconf, 0);
- kfree(keyconf);
- ieee80211_key_free(sdata->keys[i]);
- sdata->keys[i] = NULL;
- }
- sdata->default_key = NULL;
- }
- read_unlock(&local->sub_if_lock);
-
- spin_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
- keyconf = NULL;
- if (sta->key && !sta->key->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local, sta->key)))
- local->ops->set_key(local_to_hw(local), DISABLE_KEY,
- sta->addr, keyconf, sta->aid);
- kfree(keyconf);
- ieee80211_key_free(sta->key);
- sta->key = NULL;
- }
- spin_unlock_bh(&local->sta_lock);
-
- memset(&key, 0, sizeof(key));
- if (local->ops->set_key &&
- local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
- NULL, &key, 0))
- printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
- dev->name);
-
- return 0;
-}
-
-
static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
struct ieee80211_key *key)
{
sdata->ieee802_1x = value;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- local->hw.conf.antenna_sel_tx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- local->hw.conf.antenna_sel_rx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- local->cts_protect_erp_frames = value;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- sdata->drop_unencrypted = value;
+ 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:
- local->short_preamble = value;
- break;
-
- case PRISM2_PARAM_STAT_TIME:
- if (!local->stat_time && value) {
- local->stat_timer.expires = jiffies + HZ * value / 100;
- add_timer(&local->stat_timer);
- } else if (local->stat_time && !value) {
- del_timer_sync(&local->stat_timer);
+ 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;
}
- local->stat_time = value;
break;
+
case PRISM2_PARAM_SHORT_SLOT_TIME:
if (value)
local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
local->next_mode = value;
break;
- case PRISM2_PARAM_CLEAR_KEYS:
- ret = ieee80211_ioctl_clear_keys(dev);
- break;
-
- case PRISM2_PARAM_RADIO_ENABLED:
- ret = ieee80211_ioctl_set_radio_enabled(dev, value);
- break;
-
- case PRISM2_PARAM_ANTENNA_MODE:
- local->hw.conf.antenna_mode = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_STA_ANTENNA_SEL:
- local->sta_antenna_sel = value;
- break;
-
- case PRISM2_PARAM_TX_POWER_REDUCTION:
- if (value < 0)
- ret = -EINVAL;
- else
- local->hw.conf.tx_power_reduction = value;
- break;
-
case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
local->key_tx_rx_threshold = value;
break;
- case PRISM2_PARAM_DEFAULT_WEP_ONLY:
- ret = ieee80211_ioctl_default_wep_only(local, value);
- break;
-
case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
local->wifi_wme_noack_test = value;
break;
if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
- else
- sdata->u.sta.mixed_cell = !!value;
+ 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:
case PRISM2_PARAM_CREATE_IBSS:
if (sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
- else
- sdata->u.sta.create_ibss = !!value;
+ 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
- sdata->u.sta.wmm_enabled = !!value;
- break;
- case PRISM2_PARAM_RADAR_DETECT:
- local->hw.conf.radar_detect = value;
- break;
- case PRISM2_PARAM_SPECTRUM_MGMT:
- local->hw.conf.spect_mgmt = value;
+ else {
+ if (value)
+ sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED;
+ else
+ sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED;
+ }
break;
default:
ret = -EOPNOTSUPP;
*param = sdata->ieee802_1x;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- *param = local->hw.conf.antenna_sel_tx;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- *param = local->hw.conf.antenna_sel_rx;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- *param = local->cts_protect_erp_frames;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- *param = sdata->drop_unencrypted;
+ *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION);
break;
case PRISM2_PARAM_PREAMBLE:
- *param = local->short_preamble;
+ *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
break;
- case PRISM2_PARAM_STAT_TIME:
- *param = local->stat_time;
- break;
case PRISM2_PARAM_SHORT_SLOT_TIME:
*param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
break;
*param = local->next_mode;
break;
- case PRISM2_PARAM_ANTENNA_MODE:
- *param = local->hw.conf.antenna_mode;
- break;
-
- case PRISM2_PARAM_STA_ANTENNA_SEL:
- *param = local->sta_antenna_sel;
- break;
-
- case PRISM2_PARAM_TX_POWER_REDUCTION:
- *param = local->hw.conf.tx_power_reduction;
- break;
-
case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
*param = local->key_tx_rx_threshold;
break;
- case PRISM2_PARAM_DEFAULT_WEP_ONLY:
- *param = local->default_wep_only;
- break;
-
case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
*param = local->wifi_wme_noack_test;
break;
if (sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
- *param = !!sdata->u.sta.create_ibss;
+ *param = !!(sdata->u.sta.flags &
+ IEEE80211_STA_CREATE_IBSS);
break;
case PRISM2_PARAM_MIXED_CELL:
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
- *param = !!sdata->u.sta.mixed_cell;
+ *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.wmm_enabled;
+ *param = !!(sdata->u.sta.flags &
+ IEEE80211_STA_WMM_ENABLED);
break;
default:
ret = -EOPNOTSUPP;
ret = -EINVAL;
else {
/*
- * TODO: sdata->u.sta.key_mgmt does not match with WE18
- * value completely; could consider modifying this to
- * be closer to WE18. For now, this value is not really
- * used for anything else than Privacy matching, so the
- * current code here should be more or less OK.
+ * Key management was set by wpa_supplicant,
+ * we only need this to associate to a network
+ * that has privacy enabled regardless of not
+ * having a key.
*/
- if (data->value & IW_AUTH_KEY_MGMT_802_1X) {
- sdata->u.sta.key_mgmt =
- IEEE80211_KEY_MGMT_WPA_EAP;
- } else if (data->value & IW_AUTH_KEY_MGMT_PSK) {
- sdata->u.sta.key_mgmt =
- IEEE80211_KEY_MGMT_WPA_PSK;
- } else {
- sdata->u.sta.key_mgmt =
- IEEE80211_KEY_MGMT_NONE;
- }
+ sdata->u.sta.key_management_enabled = !!data->value;
}
break;
case IW_AUTH_80211_AUTH_ALG:
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
(iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
(iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
(iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
(iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
(iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
(iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
(iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
(iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */