aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c13
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/iface.c10
-rw-r--r--net/mac80211/main.c30
-rw-r--r--net/mac80211/mlme.c20
-rw-r--r--net/mac80211/rx.c35
-rw-r--r--net/mac80211/tx.c11
-rw-r--r--net/mac80211/util.c1
-rw-r--r--net/mac80211/wext.c120
-rw-r--r--net/wireless/Makefile1
-rw-r--r--net/wireless/nl80211.c57
-rw-r--r--net/wireless/reg.c5
-rw-r--r--net/wireless/wext-compat.c139
13 files changed, 299 insertions, 144 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 16423f94801..7a7a6c176dc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1095,6 +1095,18 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return 0;
}
+static int ieee80211_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_sec_chan_offset sec_chan_offset)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ local->oper_channel = chan;
+ local->oper_sec_chan_offset = sec_chan_offset;
+
+ return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1122,4 +1134,5 @@ struct cfg80211_ops mac80211_config_ops = {
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
+ .set_channel = ieee80211_set_channel,
};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 155a2041001..527205f8c1a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -626,6 +626,7 @@ struct ieee80211_local {
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
struct ieee80211_channel *oper_channel, *scan_channel;
+ enum nl80211_sec_chan_offset oper_sec_chan_offset;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head bss_list;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 46082125f3e..5abbc3f07dd 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -435,7 +435,11 @@ static int ieee80211_stop(struct net_device *dev)
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
+ /* Announce that we are leaving the network. */
+ if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED)
+ ieee80211_sta_deauthenticate(sdata,
+ WLAN_REASON_DEAUTH_LEAVING);
+
memset(sdata->u.sta.bssid, 0, ETH_ALEN);
del_timer_sync(&sdata->u.sta.timer);
/*
@@ -694,6 +698,10 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
if (type == sdata->vif.type)
return 0;
+ /* Setting ad-hoc mode on non-IBSS channel is not supported. */
+ if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)
+ return -EOPNOTSUPP;
+
/*
* We could, here, on changes between IBSS/STA/MESH modes,
* invoke an MLME function instead that disassociates etc.
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index cec9b6d3e1c..29c3ecf7e91 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -195,20 +195,42 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
struct ieee80211_channel *chan;
int ret = 0;
int power;
+ enum nl80211_sec_chan_offset sec_chan_offset;
might_sleep();
- if (local->sw_scanning)
+ if (local->sw_scanning) {
chan = local->scan_channel;
- else
+ sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+ } else {
chan = local->oper_channel;
+ sec_chan_offset = local->oper_sec_chan_offset;
+ }
- if (chan != local->hw.conf.channel) {
+ if (chan != local->hw.conf.channel ||
+ sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
local->hw.conf.channel = chan;
+ switch (sec_chan_offset) {
+ case NL80211_SEC_CHAN_NO_HT:
+ local->hw.conf.ht.enabled = false;
+ local->hw.conf.ht.sec_chan_offset = 0;
+ break;
+ case NL80211_SEC_CHAN_DISABLED:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = 0;
+ break;
+ case NL80211_SEC_CHAN_BELOW:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = -1;
+ break;
+ case NL80211_SEC_CHAN_ABOVE:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = 1;
+ break;
+ }
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
-
if (!local->hw.conf.power_level)
power = chan->max_power;
else
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7600ac9b87f..87b2ac85d91 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -855,16 +855,26 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
ifsta->state = IEEE80211_STA_MLME_DISABLED;
- sta_info_unlink(&sta);
-
rcu_read_unlock();
- sta_info_destroy(sta);
-
local->hw.conf.ht.enabled = false;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
ieee80211_bss_info_change_notify(sdata, changed);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ifsta->bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ sta_info_unlink(&sta);
+
+ rcu_read_unlock();
+
+ sta_info_destroy(sta);
}
static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
@@ -2002,7 +2012,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
}
}
- if (hidden_ssid && ifsta->ssid_len == ssid_len)
+ if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0))
return 1;
if (ssid_len == 1 && ssid[0] == ' ')
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 648a1d0e6c8..14be095b852 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -654,9 +654,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
static void ap_sta_ps_start(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
+ if (local->ops->sta_notify_ps)
+ local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_SLEEP,
+ &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
sdata->dev->name, sta->sta.addr, sta->sta.aid);
@@ -673,6 +677,9 @@ static int ap_sta_ps_end(struct sta_info *sta)
atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
+ if (local->ops->sta_notify_ps)
+ local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_AWAKE,
+ &sta->sta);
if (!skb_queue_empty(&sta->ps_tx_buf))
sta_info_clear_tim_bit(sta);
@@ -741,17 +748,29 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise;
+ /*
+ * Change STA power saving mode only at the end of a frame
+ * exchange sequence.
+ */
if (!ieee80211_has_morefrags(hdr->frame_control) &&
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
- /* Change STA power saving mode only in the end of a frame
- * exchange sequence */
- if (test_sta_flags(sta, WLAN_STA_PS) &&
- !ieee80211_has_pm(hdr->frame_control))
- rx->sent_ps_buffered += ap_sta_ps_end(sta);
- else if (!test_sta_flags(sta, WLAN_STA_PS) &&
- ieee80211_has_pm(hdr->frame_control))
- ap_sta_ps_start(sta);
+ if (test_sta_flags(sta, WLAN_STA_PS)) {
+ /*
+ * Ignore doze->wake transitions that are
+ * indicated by non-data frames, the standard
+ * is unclear here, but for example going to
+ * PS mode and then scanning would cause a
+ * doze->wake transition for the probe request,
+ * and that is clearly undesirable.
+ */
+ if (ieee80211_is_data(hdr->frame_control) &&
+ !ieee80211_has_pm(hdr->frame_control))
+ rx->sent_ps_buffered += ap_sta_ps_end(sta);
+ } else {
+ if (ieee80211_has_pm(hdr->frame_control))
+ ap_sta_ps_start(sta);
+ }
}
/* Drop data::nullfunc frames silently, since they are used only to
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0d81b2cfd1a..d7761e95e4c 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1779,8 +1779,7 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */
-static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
- struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
struct sk_buff *skb,
struct beacon_data *beacon)
{
@@ -1848,7 +1847,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info;
- struct net_device *bdev;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
struct ieee80211_if_sta *ifsta = NULL;
@@ -1861,7 +1859,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
rcu_read_lock();
sdata = vif_to_sdata(vif);
- bdev = sdata->dev;
if (sdata->vif.type == NL80211_IFTYPE_AP) {
ap = &sdata->u.ap;
@@ -1889,12 +1886,12 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
- ieee80211_beacon_add_tim(local, ap, skb, beacon);
+ ieee80211_beacon_add_tim(ap, skb, beacon);
} else {
unsigned long flags;
spin_lock_irqsave(&local->sta_lock, flags);
- ieee80211_beacon_add_tim(local, ap, skb, beacon);
+ ieee80211_beacon_add_tim(ap, skb, beacon);
spin_unlock_irqrestore(&local->sta_lock, flags);
}
@@ -2016,14 +2013,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL;
struct sta_info *sta;
struct ieee80211_tx_data tx;
- struct net_device *bdev;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
struct beacon_data *beacon;
struct ieee80211_tx_info *info;
sdata = vif_to_sdata(vif);
- bdev = sdata->dev;
bss = &sdata->u.ap;
if (!bss)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0f841317c7e..505d68f344c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -641,6 +641,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
chan->flags & IEEE80211_CHAN_NO_IBSS)
return ret;
local->oper_channel = chan;
+ local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
if (local->sw_scanning || local->hw_scanning)
ret = 0;
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index b3ce28d3561..4e1fdcfacb0 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -135,48 +135,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
return -EOPNOTSUPP;
}
-static int ieee80211_ioctl_giwname(struct net_device *dev,
- struct iw_request_info *info,
- char *name, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_supported_band *sband;
- u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0;
-
-
- sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
- if (sband) {
- is_a = 1;
- is_ht |= sband->ht_cap.ht_supported;
- }
-
- sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
- if (sband) {
- int i;
- /* Check for mandatory rates */
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].bitrate == 10)
- is_b = 1;
- if (sband->bitrates[i].bitrate == 60)
- is_g = 1;
- }
- is_ht |= sband->ht_cap.ht_supported;
- }
-
- strcpy(name, "IEEE 802.11");
- if (is_a)
- strcat(name, "a");
- if (is_b)
- strcat(name, "b");
- if (is_g)
- strcat(name, "g");
- if (is_ht)
- strcat(name, "n");
-
- return 0;
-}
-
-
static int ieee80211_ioctl_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
@@ -266,78 +224,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
}
-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);
- struct ieee80211_local *local = sdata->local;
- int type;
-
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- return -EOPNOTSUPP;
-
- switch (*mode) {
- case IW_MODE_INFRA:
- type = NL80211_IFTYPE_STATION;
- break;
- case IW_MODE_ADHOC:
- /* Setting ad-hoc mode on non ibss channel is not
- * supported.
- */
- if (local->oper_channel &&
- (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS))
- return -EOPNOTSUPP;
-
- type = NL80211_IFTYPE_ADHOC;
- break;
- case IW_MODE_REPEAT:
- type = NL80211_IFTYPE_WDS;
- break;
- case IW_MODE_MONITOR:
- type = NL80211_IFTYPE_MONITOR;
- break;
- default:
- return -EINVAL;
- }
-
- return ieee80211_if_change_type(sdata, type);
-}
-
-
-static int ieee80211_ioctl_giwmode(struct net_device *dev,
- struct iw_request_info *info,
- __u32 *mode, char *extra)
-{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- *mode = IW_MODE_MASTER;
- break;
- case NL80211_IFTYPE_STATION:
- *mode = IW_MODE_INFRA;
- break;
- case NL80211_IFTYPE_ADHOC:
- *mode = IW_MODE_ADHOC;
- break;
- case NL80211_IFTYPE_MONITOR:
- *mode = IW_MODE_MONITOR;
- break;
- case NL80211_IFTYPE_WDS:
- *mode = IW_MODE_REPEAT;
- break;
- case NL80211_IFTYPE_AP_VLAN:
- *mode = IW_MODE_SECOND; /* FIXME */
- break;
- default:
- *mode = IW_MODE_AUTO;
- break;
- }
- return 0;
-}
-
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
@@ -1146,13 +1032,13 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
static const iw_handler ieee80211_handler[] =
{
(iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */
+ (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
(iw_handler) NULL, /* SIOCSIWNWID */
(iw_handler) NULL, /* SIOCGIWNWID */
(iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
(iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
- (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */
- (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */
+ (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
+ (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
(iw_handler) NULL, /* SIOCSIWSENS */
(iw_handler) NULL, /* SIOCGIWSENS */
(iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index cc547edb111..9bc412c8343 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
+cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
cfg80211-$(CONFIG_NL80211) += nl80211.o
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c9141e3df9b..9caee6022e3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -59,6 +59,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = BUS_ID_SIZE-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -359,6 +361,61 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
}
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_sec_chan_offset sec_chan_offset =
+ NL80211_SEC_CHAN_NO_HT;
+ struct ieee80211_channel *chan;
+ u32 freq, sec_freq;
+
+ if (!rdev->ops->set_channel) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
+ sec_chan_offset = nla_get_u32(
+ info->attrs[
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
+ if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
+ sec_chan_offset != NL80211_SEC_CHAN_DISABLED &&
+ sec_chan_offset != NL80211_SEC_CHAN_BELOW &&
+ sec_chan_offset != NL80211_SEC_CHAN_ABOVE) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+ }
+
+ freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Primary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ if (sec_chan_offset == NL80211_SEC_CHAN_BELOW)
+ sec_freq = freq - 20;
+ else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE)
+ sec_freq = freq + 20;
+ else
+ sec_freq = 0;
+
+ if (sec_freq) {
+ struct ieee80211_channel *schan;
+ schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
+ if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Secondary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ }
+
+ result = rdev->ops->set_channel(&rdev->wiphy, chan,
+ sec_chan_offset);
+ if (result)
+ goto bad_res;
+ }
+
+
bad_res:
cfg80211_put_dev(rdev);
return result;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 0990059f7e4..4f877535e66 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -989,6 +989,9 @@ void regulatory_hint_11d(struct wiphy *wiphy,
u32 checksum = 0;
enum environment_cap env = ENVIRON_ANY;
+ if (!last_request)
+ return;
+
mutex_lock(&cfg80211_drv_mutex);
/* IE len must be evenly divisible by 2 */
@@ -1330,7 +1333,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
/* Caller must hold cfg80211_drv_mutex */
void reg_device_remove(struct wiphy *wiphy)
{
- if (!last_request->wiphy)
+ if (!last_request || !last_request->wiphy)
return;
if (last_request->wiphy != wiphy)
return;
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
new file mode 100644
index 00000000000..58e489fd4ae
--- /dev/null
+++ b/net/wireless/wext-compat.c
@@ -0,0 +1,139 @@
+/*
+ * cfg80211 - wext compat code
+ *
+ * This is temporary code until all wireless functionality is migrated
+ * into cfg80211, when that happens all the exports here go away and
+ * we directly assign the wireless handlers of wireless interfaces.
+ *
+ * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/wireless.h>
+#include <linux/nl80211.h>
+#include <net/iw_handler.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+int cfg80211_wext_giwname(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct ieee80211_supported_band *sband;
+ bool is_ht = false, is_a = false, is_b = false, is_g = false;
+
+ if (!wdev)
+ return -EOPNOTSUPP;
+
+ sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (sband) {
+ is_a = true;
+ is_ht |= sband->ht_cap.ht_supported;
+ }
+
+ sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (sband) {
+ int i;
+ /* Check for mandatory rates */
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].bitrate == 10)
+ is_b = true;
+ if (sband->bitrates[i].bitrate == 60)
+ is_g = true;
+ }
+ is_ht |= sband->ht_cap.ht_supported;
+ }
+
+ strcpy(name, "IEEE 802.11");
+ if (is_a)
+ strcat(name, "a");
+ if (is_b)
+ strcat(name, "b");
+ if (is_g)
+ strcat(name, "g");
+ if (is_ht)
+ strcat(name, "n");
+
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwname);
+
+int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
+ u32 *mode, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev;
+ struct vif_params vifparams;
+ enum nl80211_iftype type;
+
+ 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;
+ break;
+ case IW_MODE_ADHOC:
+ type = NL80211_IFTYPE_ADHOC;
+ break;
+ case IW_MODE_REPEAT:
+ type = NL80211_IFTYPE_WDS;
+ break;
+ case IW_MODE_MONITOR:
+ type = NL80211_IFTYPE_MONITOR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ memset(&vifparams, 0, sizeof(vifparams));
+
+ return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
+ NULL, &vifparams);
+}
+EXPORT_SYMBOL(cfg80211_wext_siwmode);
+
+int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
+ u32 *mode, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (!wdev)
+ return -EOPNOTSUPP;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ *mode = IW_MODE_MASTER;
+ break;
+ case NL80211_IFTYPE_STATION:
+ *mode = IW_MODE_INFRA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ *mode = IW_MODE_ADHOC;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ *mode = IW_MODE_MONITOR;
+ break;
+ case NL80211_IFTYPE_WDS:
+ *mode = IW_MODE_REPEAT;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ *mode = IW_MODE_SECOND; /* FIXME */
+ break;
+ default:
+ *mode = IW_MODE_AUTO;
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwmode);