* @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,
 };
 
 /**
 
 /* 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);
        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)
        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)
 
        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;
        }
 
        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++;
 
        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) {
 
        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;
 };
 
 struct ieee80211_if_vlan {
-       u8 id;
+       struct ieee80211_sub_if_data *ap;
+       struct list_head list;
 };
 
 /* flags used in struct ieee80211_if_sta.flags */
                        struct dentry *drop_unencrypted;
                        struct dentry *eapol;
                        struct dentry *ieee8021_x;
-                       struct dentry *vlan_id;
                } vlan;
                struct {
                        struct dentry *mode;
 
                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;
                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: {
        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 */