aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h17
-rw-r--r--net/mac80211/debugfs_netdev.c5
-rw-r--r--net/mac80211/ieee80211.c54
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/ieee80211_iface.c5
5 files changed, 65 insertions, 22 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 855754d4c50d..494a4c022a9b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -442,16 +442,17 @@ struct ieee80211_conf {
* @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
* @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
* @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
- * @IEEE80211_IF_TYPE_VLAN: not used.
+ * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
+ * will never see this type.
*/
enum ieee80211_if_types {
- IEEE80211_IF_TYPE_AP = 0x00000000,
- IEEE80211_IF_TYPE_MGMT = 0x00000001,
- IEEE80211_IF_TYPE_STA = 0x00000002,
- IEEE80211_IF_TYPE_IBSS = 0x00000003,
- IEEE80211_IF_TYPE_MNTR = 0x00000004,
- IEEE80211_IF_TYPE_WDS = 0x5A580211,
- IEEE80211_IF_TYPE_VLAN = 0x00080211,
+ IEEE80211_IF_TYPE_AP,
+ IEEE80211_IF_TYPE_MGMT,
+ IEEE80211_IF_TYPE_STA,
+ IEEE80211_IF_TYPE_IBSS,
+ IEEE80211_IF_TYPE_MNTR,
+ IEEE80211_IF_TYPE_WDS,
+ IEEE80211_IF_TYPE_VLAN,
};
/**
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c9948fa58e08..f0e6ab7eb624 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -162,9 +162,6 @@ __IEEE80211_IF_FILE(beacon_tail_len);
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
-/* VLAN attributes */
-IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
-
#define DEBUGFS_ADD(name, type)\
sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
sdata->debugfsdir, sdata, &name##_ops);
@@ -223,7 +220,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(drop_unencrypted, vlan);
DEBUGFS_ADD(eapol, vlan);
DEBUGFS_ADD(ieee8021_x, vlan);
- DEBUGFS_ADD(vlan_id, vlan);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -317,7 +313,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_DEL(drop_unencrypted, vlan);
DEBUGFS_DEL(eapol, vlan);
DEBUGFS_DEL(ieee8021_x, vlan);
- DEBUGFS_DEL(vlan_id, vlan);
}
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 319ec2a1d84f..4e345f82f044 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -314,22 +314,43 @@ static int ieee80211_open(struct net_device *dev)
int res;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
read_lock(&local->sub_if_lock);
list_for_each_entry(nsdata, &local->sub_if_list, list) {
struct net_device *ndev = nsdata->dev;
if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
- compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
- !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
- read_unlock(&local->sub_if_lock);
- return -ENOTUNIQ;
+ compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
+ /*
+ * check whether it may have the same address
+ */
+ if (!identical_mac_addr_allowed(sdata->type,
+ nsdata->type)) {
+ read_unlock(&local->sub_if_lock);
+ return -ENOTUNIQ;
+ }
+
+ /*
+ * can only add VLANs to enabled APs
+ */
+ if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
+ nsdata->type == IEEE80211_IF_TYPE_AP &&
+ netif_running(nsdata->dev))
+ sdata->u.vlan.ap = nsdata;
}
}
read_unlock(&local->sub_if_lock);
- if (sdata->type == IEEE80211_IF_TYPE_WDS &&
- is_zero_ether_addr(sdata->u.wds.remote_addr))
- return -ENOLINK;
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_WDS:
+ if (is_zero_ether_addr(sdata->u.wds.remote_addr))
+ return -ENOLINK;
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ if (!sdata->u.vlan.ap)
+ return -ENOLINK;
+ break;
+ }
if (local->open_count == 0) {
res = 0;
@@ -340,6 +361,10 @@ static int ieee80211_open(struct net_device *dev)
}
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_VLAN:
+ list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
+ /* no need to tell driver */
+ break;
case IEEE80211_IF_TYPE_MNTR:
/* must be before the call to ieee80211_configure_filter */
local->monitors++;
@@ -407,9 +432,24 @@ static int ieee80211_stop(struct net_device *dev)
dev_mc_unsync(local->mdev, dev);
+ /* down all dependent devices, that is VLANs */
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ struct ieee80211_sub_if_data *vlan, *tmp;
+
+ list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
+ u.vlan.list)
+ dev_close(vlan->dev);
+ WARN_ON(!list_empty(&sdata->u.ap.vlans));
+ }
+
local->open_count--;
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_VLAN:
+ list_del(&sdata->u.vlan.list);
+ sdata->u.vlan.ap = NULL;
+ /* no need to tell driver */
+ break;
case IEEE80211_IF_TYPE_MNTR:
local->monitors--;
if (local->monitors == 0) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74deecd09677..1a43f3e9b6bd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -191,6 +191,8 @@ struct ieee80211_if_ap {
u8 *beacon_head, *beacon_tail;
int beacon_head_len, beacon_tail_len;
+ struct list_head vlans;
+
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
u8 *generic_elem;
@@ -214,7 +216,8 @@ struct ieee80211_if_wds {
};
struct ieee80211_if_vlan {
- u8 id;
+ struct ieee80211_sub_if_data *ap;
+ struct list_head list;
};
/* flags used in struct ieee80211_if_sta.flags */
@@ -377,7 +380,6 @@ struct ieee80211_sub_if_data {
struct dentry *drop_unencrypted;
struct dentry *eapol;
struct dentry *ieee8021_x;
- struct dentry *vlan_id;
} vlan;
struct {
struct dentry *mode;
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index f9c74bb09d31..4590205fdf4b 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -164,6 +164,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
sdata->bss = NULL;
break;
case IEEE80211_IF_TYPE_VLAN:
+ sdata->u.vlan.ap = NULL;
break;
case IEEE80211_IF_TYPE_AP:
sdata->u.ap.dtim_period = 2;
@@ -171,6 +172,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
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_STA:
case IEEE80211_IF_TYPE_IBSS: {
@@ -284,6 +286,9 @@ void ieee80211_if_reinit(struct net_device *dev)
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_ETHER;
break;
+ case IEEE80211_IF_TYPE_VLAN:
+ sdata->u.vlan.ap = NULL;
+ break;
}
/* remove all STAs that are bound to this virtual interface */