summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-02-09 14:41:42 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2009-02-09 14:41:42 +1100
commit343b7eaa291f22959f922f603ed12a981ad1d7a5 (patch)
treedf98a7a9720414b61ccb5a09131a9b94fc6a61b5 /net
parent4ca47e2cc140ab7bb16de399edaf8adf3aff7a2b (diff)
parent9e0f629d3367e3f5b900886bea3de17474453c4e (diff)
Merge commit 'wireless/master'
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/iface.c47
-rw-r--r--net/mac80211/main.c29
-rw-r--r--net/mac80211/mlme.c48
-rw-r--r--net/mac80211/rx.c19
-rw-r--r--net/mac80211/tx.c21
-rw-r--r--net/mac80211/wext.c3
-rw-r--r--net/wireless/nl80211.c81
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/reg.h2
9 files changed, 194 insertions, 58 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 00562a8b99cf..915d04323a32 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -591,19 +591,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
dev_mc_sync(local->mdev, dev);
}
-static void ieee80211_if_setup(struct net_device *dev)
-{
- ether_setup(dev);
- dev->hard_start_xmit = ieee80211_subif_start_xmit;
- dev->wireless_handlers = &ieee80211_iw_handler_def;
- dev->set_multicast_list = ieee80211_set_multicast_list;
- dev->change_mtu = ieee80211_change_mtu;
- dev->open = ieee80211_open;
- dev->stop = ieee80211_stop;
- dev->destructor = free_netdev;
- /* we will validate the address ourselves in ->open */
- dev->validate_addr = NULL;
-}
/*
* Called when the netdev is removed or, by the code below, before
* the interface type changes.
@@ -671,6 +658,34 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
WARN_ON(flushed);
}
+static const struct net_device_ops ieee80211_dataif_ops = {
+ .ndo_open = ieee80211_open,
+ .ndo_stop = ieee80211_stop,
+ .ndo_uninit = ieee80211_teardown_sdata,
+ .ndo_start_xmit = ieee80211_subif_start_xmit,
+ .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_change_mtu = ieee80211_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static const struct net_device_ops ieee80211_monitorif_ops = {
+ .ndo_open = ieee80211_open,
+ .ndo_stop = ieee80211_stop,
+ .ndo_uninit = ieee80211_teardown_sdata,
+ .ndo_start_xmit = ieee80211_monitor_start_xmit,
+ .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_change_mtu = ieee80211_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void ieee80211_if_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->netdev_ops = &ieee80211_dataif_ops;
+ dev->wireless_handlers = &ieee80211_iw_handler_def;
+ dev->destructor = free_netdev;
+}
+
/*
* Helper function to initialise an interface to a specific type.
*/
@@ -682,7 +697,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
/* and set some type-dependent values */
sdata->vif.type = type;
- sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit;
+ sdata->dev->netdev_ops = &ieee80211_dataif_ops;
sdata->wdev.iftype = type;
/* only monitor differs */
@@ -703,7 +718,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
break;
case NL80211_IFTYPE_MONITOR:
sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
- sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+ sdata->dev->netdev_ops = &ieee80211_monitorif_ops;
sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
MONITOR_FLAG_OTHER_BSS;
break;
@@ -809,8 +824,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
if (ret)
goto fail;
- ndev->uninit = ieee80211_teardown_sdata;
-
if (ieee80211_vif_is_mesh(&sdata->vif) &&
params && params->mesh_id_len)
ieee80211_sdata_set_mesh_id(sdata,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index a109c06e8e4e..caf92424c76d 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -791,6 +791,23 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
+static const struct net_device_ops ieee80211_master_ops = {
+ .ndo_start_xmit = ieee80211_master_start_xmit,
+ .ndo_open = ieee80211_master_open,
+ .ndo_stop = ieee80211_master_stop,
+ .ndo_set_multicast_list = ieee80211_master_set_multicast_list,
+ .ndo_select_queue = ieee80211_select_queue,
+};
+
+static void ieee80211_master_setup(struct net_device *mdev)
+{
+ mdev->type = ARPHRD_IEEE80211;
+ mdev->netdev_ops = &ieee80211_master_ops;
+ mdev->header_ops = &ieee80211_header_ops;
+ mdev->tx_queue_len = 1000;
+ mdev->addr_len = ETH_ALEN;
+}
+
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -840,7 +857,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
hw->ampdu_queues = 0;
mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
- "wmaster%d", ether_setup,
+ "wmaster%d", ieee80211_master_setup,
ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
@@ -851,13 +868,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_rx_bss_list_init(local);
- mdev->hard_start_xmit = ieee80211_master_start_xmit;
- mdev->open = ieee80211_master_open;
- mdev->stop = ieee80211_master_stop;
- mdev->type = ARPHRD_IEEE80211;
- mdev->header_ops = &ieee80211_header_ops;
- mdev->set_multicast_list = ieee80211_master_set_multicast_list;
-
local->hw.workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
@@ -884,7 +894,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.conf.listen_interval = local->hw.max_listen_interval;
local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
- IEEE80211_HW_SIGNAL_DB |
IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
@@ -924,8 +933,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_wep;
}
- local->mdev->select_queue = ieee80211_select_queue;
-
/* add one default STA interface if supported */
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
result = ieee80211_if_add(local, "wlan%d", NULL,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9d51e278c1e5..57967d32e5fd 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1042,6 +1042,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int disassoc;
+ bool remove_bss = false;
/* TODO: start monitoring current AP signal quality and number of
* missed beacons. Scan other channels every now and then and search
@@ -1067,6 +1068,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
"range\n",
sdata->dev->name, ifsta->bssid);
disassoc = 1;
+ remove_bss = true;
} else
ieee80211_send_probe_req(sdata, ifsta->bssid,
ifsta->ssid,
@@ -1086,12 +1088,24 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
- if (disassoc)
+ if (disassoc) {
ieee80211_set_disassoc(sdata, ifsta, true, true,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- else
+ if (remove_bss) {
+ struct ieee80211_bss *bss;
+
+ bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+ local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
+ if (bss) {
+ atomic_dec(&bss->users);
+ ieee80211_rx_bss_put(local, bss);
+ }
+ }
+ } else {
mod_timer(&ifsta->timer, jiffies +
IEEE80211_MONITORING_INTERVAL);
+ }
}
@@ -1503,13 +1517,22 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss)
{
struct ieee80211_local *local = sdata->local;
- int res, rates, i, j;
+ int res = 0, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
union iwreq_data wrqu;
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+
+ if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&
+ memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) == 0)
+ return res;
+
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
sdata->u.sta.ie_proberesp_len);
if (!skb) {
@@ -1520,13 +1543,11 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- /* Remove possible STA entries from other IBSS networks. */
- sta_info_flush_delayed(sdata);
-
- if (local->ops->reset_tsf) {
- /* Reset own TSF to allow time synchronization work. */
- local->ops->reset_tsf(local_to_hw(local));
+ if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush_delayed(sdata);
}
+
memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
if (res)
@@ -2415,8 +2436,10 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
ifsta->ssid_len);
ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
- } else
+ } else {
+ ifsta->assoc_scan_tries = 0;
ifsta->state = IEEE80211_STA_MLME_DISABLED;
+ }
}
return -1;
}
@@ -2720,9 +2743,8 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
ifsta = &sdata->u.sta;
- if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
- (!(ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED) &&
- !ieee80211_sta_active_ibss(sdata)))
+ if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||
+ !ieee80211_sta_active_ibss(sdata))
ieee80211_sta_find_ibss(sdata, ifsta);
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 19ffc8ef1d1d..8e8ddbfcd236 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -86,8 +86,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
if (status->flag & RX_FLAG_TSFT)
len += 8;
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
- local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
len += 1;
if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
len += 1;
@@ -199,14 +198,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
*pos = status->antenna;
pos++;
- /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
- *pos = status->signal;
- rthdr->it_present |=
- cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
- pos++;
- }
-
/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
/* IEEE80211_RADIOTAP_RX_FLAGS */
@@ -1225,12 +1216,12 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
switch (hdr->frame_control &
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
- case __constant_cpu_to_le16(IEEE80211_FCTL_TODS):
+ case cpu_to_le16(IEEE80211_FCTL_TODS):
if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
return -1;
break;
- case __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+ case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
return -1;
@@ -1244,13 +1235,13 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
}
}
break;
- case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+ case cpu_to_le16(IEEE80211_FCTL_FROMDS):
if (sdata->vif.type != NL80211_IFTYPE_STATION ||
(is_multicast_ether_addr(dst) &&
!compare_ether_addr(src, dev->dev_addr)))
return -1;
break;
- case __constant_cpu_to_le16(0):
+ case cpu_to_le16(0):
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -1;
break;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7b013fb0d27f..f1c726d94f47 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1433,10 +1433,31 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_channel *chan = local->hw.conf.channel;
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
u16 len_rthdr;
+ /*
+ * Frame injection is not allowed if beaconing is not allowed
+ * or if we need radar detection. Beaconing is usually not allowed when
+ * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
+ * Passive scan is also used in world regulatory domains where
+ * your country is not known and as such it should be treated as
+ * NO TX unless the channel is explicitly allowed in which case
+ * your current regulatory domain would not have the passive scan
+ * flag.
+ *
+ * Since AP mode uses monitor interfaces to inject/TX management
+ * frames we can make AP mode the exception to this rule once it
+ * supports radar detection as its implementation can deal with
+ * radar detection by itself. We can do that later by adding a
+ * monitor flag interfaces used for AP support.
+ */
+ if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_PASSIVE_SCAN)))
+ goto fail;
+
/* check for not even having the fixed radiotap header part */
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
goto fail; /* too short to be possibly valid */
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 5c88b8246bbb..bad1cfbfdf18 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -173,8 +173,7 @@ 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)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
range->max_qual.level = local->hw.max_signal;
else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
range->max_qual.level = -110;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e69da8d20474..d452396006ee 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2093,6 +2093,81 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
#undef FILL_IN_MESH_PARAM_IF_SET
+static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *msg;
+ void *hdr = NULL;
+ struct nlattr *nl_reg_rules;
+ unsigned int i;
+ int err = -EINVAL;
+
+ mutex_lock(&cfg80211_drv_mutex);
+
+ if (!cfg80211_regdomain)
+ goto out;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ err = -ENOBUFS;
+ goto out;
+ }
+
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_GET_REG);
+ if (!hdr)
+ goto nla_put_failure;
+
+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2,
+ cfg80211_regdomain->alpha2);
+
+ nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
+ if (!nl_reg_rules)
+ goto nla_put_failure;
+
+ for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+ struct nlattr *nl_reg_rule;
+ const struct ieee80211_reg_rule *reg_rule;
+ const struct ieee80211_freq_range *freq_range;
+ const struct ieee80211_power_rule *power_rule;
+
+ reg_rule = &cfg80211_regdomain->reg_rules[i];
+ freq_range = &reg_rule->freq_range;
+ power_rule = &reg_rule->power_rule;
+
+ nl_reg_rule = nla_nest_start(msg, i);
+ if (!nl_reg_rule)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS,
+ reg_rule->flags);
+ NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START,
+ freq_range->start_freq_khz);
+ NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END,
+ freq_range->end_freq_khz);
+ NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
+ freq_range->max_bandwidth_khz);
+ NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ power_rule->max_antenna_gain);
+ NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
+ power_rule->max_eirp);
+
+ nla_nest_end(msg, nl_reg_rule);
+ }
+
+ nla_nest_end(msg, nl_reg_rules);
+
+ genlmsg_end(msg, hdr);
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ err = -EMSGSIZE;
+out:
+ mutex_unlock(&cfg80211_drv_mutex);
+ return err;
+}
+
static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@@ -2333,6 +2408,12 @@ static struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM,
},
{
+ .cmd = NL80211_CMD_GET_REG,
+ .doit = nl80211_get_reg,
+ .policy = nl80211_policy,
+ /* can be retrieved by unprivileged users */
+ },
+ {
.cmd = NL80211_CMD_SET_REG,
.doit = nl80211_set_reg,
.policy = nl80211_policy,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index f643d3981102..2323644330cd 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -57,7 +57,7 @@ static u32 supported_bandwidths[] = {
/* Central wireless core regulatory domains, we only need two,
* the current one and a world regulatory domain in case we have no
* information to give us an alpha2 */
-static const struct ieee80211_regdomain *cfg80211_regdomain;
+const struct ieee80211_regdomain *cfg80211_regdomain;
/* We use this as a place for the rd structure built from the
* last parsed country IE to rest until CRDA gets back to us with
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index eb1dd5bc9b27..fe8c83f34fb7 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -1,6 +1,8 @@
#ifndef __NET_WIRELESS_REG_H
#define __NET_WIRELESS_REG_H
+extern const struct ieee80211_regdomain *cfg80211_regdomain;
+
bool is_world_regdom(const char *alpha2);
bool reg_is_valid_request(const char *alpha2);