dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
        /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
        dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
        dev->channel_change_time = 1000;
        dev->max_signal = 100;    /* FIXME: find better value */
 
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
+
        hw->extra_tx_headroom = 2;
        hw->channel_change_time = 5000;
        sc = hw->priv;
 
                IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_NOISE_DBM;
 
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
        SET_IEEE80211_DEV(hw, &pdev->dev);
        pci_set_drvdata(pdev, hw);
 
 
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_MESH_POINT) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_WDS) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
        hw->queues = b43_modparam_qos ? 4 : 1;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
 
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_WDS) |
+               BIT(NL80211_IFTYPE_ADHOC);
        hw->queues = 1; /* FIXME: hardware has more queues */
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
        /* queues to support 11n aggregation */
 
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
        /* 4 EDCA QOS priorities */
        hw->queues = 4;
 
 
 
                hw->channel_change_time = 1;
                hw->queues = 4;
+               hw->wiphy->interface_modes =
+                       BIT(NL80211_IFTYPE_STATION) |
+                       BIT(NL80211_IFTYPE_AP);
                hw->ampdu_queues = 1;
 
                memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
 
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
                     IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_SIGNAL_UNSPEC;
+
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
        dev->channel_change_time = 1000;        /* TODO: find actual value */
        dev->max_signal = 127;
 
 
         */
        rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
 
+       rt2x00dev->hw->wiphy->interface_modes =
+           BIT(NL80211_IFTYPE_AP) |
+           BIT(NL80211_IFTYPE_STATION) |
+           BIT(NL80211_IFTYPE_ADHOC);
+
        /*
         * Let the driver probe the device to detect the capabilities.
         */
 
                dev->max_signal = 65;
        }
 
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
        if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
                printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
                       " info!\n");
 
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_SIGNAL_DB;
 
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_MESH_POINT) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
        hw->max_signal = 100;
        hw->queues = 1;
        hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
 
  * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
  *     association request when used with NL80211_CMD_NEW_STATION)
  *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *     supported interface types, each a flag attribute with the number
+ *     of the interface mode.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
 
        NL80211_ATTR_HT_CAPABILITY,
 
+       NL80211_ATTR_SUPPORTED_IFTYPES,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
 
        /* permanent MAC address */
        u8 perm_addr[ETH_ALEN];
 
+       /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
+       u16 interface_modes;
+
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
         * know whether it points to a wiphy your driver has registered
 
                }
        }
 
+       /* if low-level driver supports AP, we also support VLAN */
+       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
+               local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+
+       /* mac80211 always supports monitor */
+       local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                return result;
 
 /*
  * This is the linux wireless configuration interface.
  *
- * Copyright 2006, 2007                Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008         Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/if.h>
        struct ieee80211_supported_band *sband;
        bool have_band = false;
        int i;
+       u16 ifmodes = wiphy->interface_modes;
+
+       /* sanity check ifmodes */
+       WARN_ON(!ifmodes);
+       ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
+       if (WARN_ON(ifmodes != wiphy->interface_modes))
+               wiphy->interface_modes = ifmodes;
 
        /* sanity check supported bands/channels */
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_rates, *nl_rate;
+       struct nlattr *nl_modes;
        enum ieee80211_band band;
        struct ieee80211_channel *chan;
        struct ieee80211_rate *rate;
        int i;
+       u16 ifmodes = dev->wiphy.interface_modes;
 
        hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
        if (!hdr)
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
        NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 
+       nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
+       if (!nl_modes)
+               goto nla_put_failure;
+
+       i = 0;
+       while (ifmodes) {
+               if (ifmodes & 1)
+                       NLA_PUT_FLAG(msg, i);
+               ifmodes >>= 1;
+               i++;
+       }
+
+       nla_nest_end(msg, nl_modes);
+
        nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
        if (!nl_bands)
                goto nla_put_failure;
        ifindex = dev->ifindex;
        dev_put(dev);
 
-       if (!drv->ops->change_virtual_intf) {
+       if (!drv->ops->change_virtual_intf ||
+           !(drv->wiphy.interface_modes & (1 << type))) {
                err = -EOPNOTSUPP;
                goto unlock;
        }
        if (IS_ERR(drv))
                return PTR_ERR(drv);
 
-       if (!drv->ops->add_virtual_intf) {
+       if (!drv->ops->add_virtual_intf ||
+           !(drv->wiphy.interface_modes & (1 << type))) {
                err = -EOPNOTSUPP;
                goto unlock;
        }