#include "ieee80211_i.h"
#include "sta_info.h"
#include "debugfs_netdev.h"
+#include "mesh.h"
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
{
/* Default values for sub-interface parameters */
sdata->drop_unencrypted = 0;
- sdata->eapol = 1;
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list);
/* Must be called with rtnl lock held. */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type)
+ struct net_device **new_dev, int type,
+ struct vif_params *params)
{
struct net_device *ndev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int ret;
ASSERT_RTNL();
- ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+ ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
name, ieee80211_if_setup);
if (!ndev)
return -ENOMEM;
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
ndev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = local->hw.wiphy;
- sdata->type = IEEE80211_IF_TYPE_AP;
+ sdata->vif.type = IEEE80211_IF_TYPE_AP;
sdata->dev = ndev;
sdata->local = local;
ieee80211_if_sdata_init(sdata);
ieee80211_debugfs_add_netdev(sdata);
ieee80211_if_set_type(ndev, type);
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ params && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
+
/* we're under RTNL so all this is fine */
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
__ieee80211_if_del(local, sdata);
return ret;
}
-int ieee80211_if_add_mgmt(struct ieee80211_local *local)
-{
- struct net_device *ndev;
- struct ieee80211_sub_if_data *nsdata;
- int ret;
-
- ASSERT_RTNL();
-
- ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
- ieee80211_if_mgmt_setup);
- if (!ndev)
- return -ENOMEM;
- ret = dev_alloc_name(ndev, ndev->name);
- if (ret < 0)
- goto fail;
-
- memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
- SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-
- nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
- ndev->ieee80211_ptr = &nsdata->wdev;
- nsdata->wdev.wiphy = local->hw.wiphy;
- nsdata->type = IEEE80211_IF_TYPE_MGMT;
- nsdata->dev = ndev;
- nsdata->local = local;
- ieee80211_if_sdata_init(nsdata);
-
- ret = register_netdevice(ndev);
- if (ret)
- goto fail;
-
- /*
- * Called even when register_netdevice fails, it would
- * oops if assigned before initialising the rest.
- */
- ndev->uninit = ieee80211_if_reinit;
-
- ieee80211_debugfs_add_netdev(nsdata);
-
- if (local->open_count > 0)
- dev_open(ndev);
- local->apdev = ndev;
- return 0;
-
-fail:
- free_netdev(ndev);
- return ret;
-}
-
-void ieee80211_if_del_mgmt(struct ieee80211_local *local)
-{
- struct net_device *apdev;
-
- ASSERT_RTNL();
- apdev = local->apdev;
- ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
- local->apdev = NULL;
- unregister_netdevice(apdev);
-}
-
void ieee80211_if_set_type(struct net_device *dev, int type)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- int oldtype = sdata->type;
+ int oldtype = sdata->vif.type;
/*
* We need to call this function on the master interface
* which already has a hard_start_xmit routine assigned
* which must not be changed.
*/
- if (!dev->hard_start_xmit)
+ if (dev != sdata->local->mdev)
dev->hard_start_xmit = ieee80211_subif_start_xmit;
/*
/* most have no BSS pointer */
sdata->bss = NULL;
- sdata->type = type;
+ sdata->vif.type = type;
+
+ sdata->basic_rates = 0;
switch (type) {
case IEEE80211_IF_TYPE_WDS:
sdata->u.vlan.ap = NULL;
break;
case IEEE80211_IF_TYPE_AP:
- sdata->u.ap.dtim_period = 2;
sdata->u.ap.force_unicast_rateidx = -1;
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
sdata->bss = &sdata->u.ap;
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: {
struct ieee80211_sub_if_data *msdata;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_mesh_init_sdata(sdata);
break;
}
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_IEEE80211_RADIOTAP;
dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+ sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+ MONITOR_FLAG_OTHER_BSS;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
- dev->name, __FUNCTION__, type);
+ dev->name, __func__, type);
}
ieee80211_debugfs_change_if_type(sdata, oldtype);
}
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sta_info *sta;
struct sk_buff *skb;
+ int flushed;
ASSERT_RTNL();
ieee80211_if_sdata_deinit(sdata);
- switch (sdata->type) {
+ /* Need to handle mesh specially to allow eliding the function call */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rmc_free(dev);
+
+ switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_INVALID:
+ /* cannot happen */
+ WARN_ON(1);
+ break;
case IEEE80211_IF_TYPE_AP: {
/* Remove all virtual interfaces that use this BSS
* as their sdata->bss */
struct ieee80211_sub_if_data *tsdata, *n;
+ struct beacon_data *beacon;
list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
}
}
- kfree(sdata->u.ap.beacon_head);
- kfree(sdata->u.ap.beacon_tail);
- kfree(sdata->u.ap.generic_elem);
+ beacon = sdata->u.ap.beacon;
+ rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ synchronize_rcu();
+ kfree(beacon);
while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
local->total_ps_buffered--;
break;
}
case IEEE80211_IF_TYPE_WDS:
- sta = sta_info_get(local, sdata->u.wds.remote_addr);
- if (sta) {
- sta_info_free(sta);
- sta_info_put(sta);
- } else {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Someone had deleted my STA "
- "entry for the WDS link\n", dev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- }
+ /* nothing to do */
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
kfree(sdata->u.sta.extra_ie);
break;
}
- /* remove all STAs that are bound to this virtual interface */
- sta_info_flush(local, dev);
+ flushed = sta_info_flush(local, sdata);
+ WARN_ON(flushed);
memset(&sdata->u, 0, sizeof(sdata->u));
ieee80211_if_sdata_init(sdata);
ASSERT_RTNL();
list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
- if ((sdata->type == id || id == -1) &&
+ if ((sdata->vif.type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 &&
sdata->dev != local->mdev) {
list_del_rcu(&sdata->list);
void ieee80211_if_free(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- /* local->apdev must be NULL when freeing management interface */
- BUG_ON(dev == local->apdev);
ieee80211_if_sdata_deinit(sdata);
free_netdev(dev);
}