#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "cfg.h"
-#include "ieee80211_rate.h"
-#ifdef CONFIG_MAC80211_MESH
+#include "rate.h"
#include "mesh.h"
-#endif
-
-#define DEFAULT_RATES 0
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
case NL80211_IFTYPE_MESH_POINT:
return IEEE80211_IF_TYPE_MESH_POINT;
#endif
+ case NL80211_IFTYPE_WDS:
+ return IEEE80211_IF_TYPE_WDS;
default:
return IEEE80211_IF_TYPE_INVALID;
}
ieee80211_if_reinit(dev);
ieee80211_if_set_type(dev, itype);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- params->mesh_id_len) {
- sdata->u.sta.mesh_id_len = params->mesh_id_len;
- memcpy(sdata->u.sta.mesh_id, params->mesh_id,
- params->mesh_id_len);
- }
-#endif
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
return 0;
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL;
enum ieee80211_key_alg alg;
- int ret;
struct ieee80211_key *key;
+ int err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (!key)
return -ENOMEM;
+ rcu_read_lock();
+
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta) {
ieee80211_key_free(key);
- return -ENOENT;
+ err = -ENOENT;
+ goto out_unlock;
}
}
ieee80211_key_link(key, sdata, sta);
- ret = 0;
-
- if (sta)
- sta_info_put(sta);
+ err = 0;
+ out_unlock:
+ rcu_read_unlock();
- return ret;
+ return err;
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
int ret;
- struct ieee80211_key *key;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ rcu_read_lock();
+
if (mac_addr) {
+ ret = -ENOENT;
+
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
- return -ENOENT;
+ goto out_unlock;
- ret = 0;
if (sta->key) {
- key = sta->key;
- ieee80211_key_free(key);
+ ieee80211_key_free(sta->key);
WARN_ON(sta->key);
- } else
- ret = -ENOENT;
+ ret = 0;
+ }
- sta_info_put(sta);
- return ret;
+ goto out_unlock;
}
- if (!sdata->keys[key_idx])
- return -ENOENT;
+ if (!sdata->keys[key_idx]) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
- key = sdata->keys[key_idx];
- ieee80211_key_free(key);
+ ieee80211_key_free(sdata->keys[key_idx]);
WARN_ON(sdata->keys[key_idx]);
- return 0;
+ ret = 0;
+ out_unlock:
+ rcu_read_unlock();
+
+ return ret;
}
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
u16 iv16;
int err = -ENOENT;
+ rcu_read_lock();
+
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
err = 0;
out:
- if (sta)
- sta_info_put(sta);
+ rcu_read_unlock();
return err;
}
{
struct ieee80211_sub_if_data *sdata;
+ rcu_read_lock();
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_key(sdata, key_idx);
+ rcu_read_unlock();
+
return 0;
}
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
-#ifdef CONFIG_MAC80211_MESH
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-#endif
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES |
sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes;
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
sinfo->filled |= STATION_INFO_LLID |
STATION_INFO_PLID |
STATION_INFO_PLINK_STATE;
sinfo->llid = le16_to_cpu(sta->llid);
sinfo->plid = le16_to_cpu(sta->plid);
sinfo->plink_state = sta->plink_state;
- }
#endif
+ }
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
+ int ret = -ENOENT;
+
+ rcu_read_lock();
sta = sta_info_get_by_idx(local, idx, dev);
- if (!sta)
- return -ENOENT;
+ if (sta) {
+ ret = 0;
+ memcpy(mac, sta->addr, ETH_ALEN);
+ sta_set_sinfo(sta, sinfo);
+ }
- memcpy(mac, sta->addr, ETH_ALEN);
- sta_set_sinfo(sta, sinfo);
- sta_info_put(sta);
+ rcu_read_unlock();
- return 0;
+ return ret;
}
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
+ int ret = -ENOENT;
- sta = sta_info_get(local, mac);
- if (!sta)
- return -ENOENT;
+ rcu_read_lock();
/* XXX: verify sta->dev == dev */
- sta_set_sinfo(sta, sinfo);
- sta_info_put(sta);
- return 0;
+ sta = sta_info_get(local, mac);
+ if (sta) {
+ ret = 0;
+ sta_set_sinfo(sta, sinfo);
+ }
+
+ rcu_read_unlock();
+
+ return ret;
}
/*
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
- skb->dev = sta->dev;
- skb->protocol = eth_type_trans(skb, sta->dev);
+ skb->dev = sta->sdata->dev;
+ skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
}
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
-#ifdef CONFIG_MAC80211_MESH
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-#endif
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+ /*
+ * FIXME: updating the flags is racy when this function is
+ * called from ieee80211_change_station(), this will
+ * be resolved in a future patch.
+ */
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
sta->flags |= WLAN_STA_WME;
}
+ /*
+ * FIXME: updating the following information is racy when this
+ * function is called from ieee80211_change_station().
+ * However, all this information should be static so
+ * maybe we should just reject attemps to change it.
+ */
+
if (params->aid) {
sta->aid = params->aid;
if (sta->aid > IEEE80211_MAX_AID)
sta->supp_rates[local->oper_channel->band] = rates;
}
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- params->plink_action)
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
switch (params->plink_action) {
case PLINK_ACTION_OPEN:
mesh_plink_open(sta);
mesh_plink_block(sta);
break;
}
-#endif
+ }
}
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
+ int err;
/* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev))
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
- sta = mesh_plink_add(mac, DEFAULT_RATES, dev);
- else
-#endif
- sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+ if (compare_ether_addr(mac, dev->dev_addr) == 0)
+ return -EINVAL;
- if (IS_ERR(sta))
- return PTR_ERR(sta);
+ if (is_multicast_ether_addr(mac))
+ return -EINVAL;
- sta->dev = sdata->dev;
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
- sdata->vif.type == IEEE80211_IF_TYPE_AP)
- ieee80211_send_layer2_update(sta);
+ sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
rate_control_rate_init(sta, local);
- sta_info_put(sta);
+ rcu_read_lock();
+
+ err = sta_info_insert(sta);
+ if (err) {
+ /* STA has been freed */
+ rcu_read_unlock();
+ return err;
+ }
+
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+ sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ ieee80211_send_layer2_update(sta);
+
+ rcu_read_unlock();
return 0;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
if (mac) {
+ rcu_read_lock();
+
/* XXX: get sta belonging to dev */
sta = sta_info_get(local, mac);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return -ENOENT;
+ }
+
+ sta_info_unlink(&sta);
+ rcu_read_unlock();
- sta_info_free(sta);
- sta_info_put(sta);
+ sta_info_destroy(sta);
} else
- sta_info_flush(local, dev);
+ sta_info_flush(local, sdata);
return 0;
}
struct sta_info *sta;
struct ieee80211_sub_if_data *vlansdata;
+ rcu_read_lock();
+
/* XXX: get sta belonging to dev */
sta = sta_info_get(local, mac);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return -ENOENT;
+ }
- if (params->vlan && params->vlan != sta->dev) {
+ if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
- vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
+ vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
+ rcu_read_unlock();
return -EINVAL;
+ }
- sta->dev = params->vlan;
+ sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
ieee80211_send_layer2_update(sta);
}
sta_apply_parameters(local, sta, params);
- sta_info_put(sta);
+ rcu_read_unlock();
return 0;
}
if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
return -ENOTSUPP;
+ rcu_read_lock();
sta = sta_info_get(local, next_hop);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return -ENOENT;
+ }
err = mesh_path_add(dst, dev);
- if (err)
+ if (err) {
+ rcu_read_unlock();
return err;
+ }
- rcu_read_lock();
mpath = mesh_path_lookup(dst, dev);
if (!mpath) {
rcu_read_unlock();
- sta_info_put(sta);
return -ENXIO;
}
mesh_path_fix_nexthop(mpath, sta);
- sta_info_put(sta);
+
rcu_read_unlock();
return 0;
}
if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
return -ENOTSUPP;
+ rcu_read_lock();
+
sta = sta_info_get(local, next_hop);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return -ENOENT;
+ }
- rcu_read_lock();
mpath = mesh_path_lookup(dst, dev);
if (!mpath) {
rcu_read_unlock();
- sta_info_put(sta);
return -ENOENT;
}
mesh_path_fix_nexthop(mpath, sta);
- sta_info_put(sta);
+
rcu_read_unlock();
return 0;
}