Skip to content

Commit

Permalink
cfg80211: keep track of supported interface modes
Browse files Browse the repository at this point in the history
It is obviously good for userspace to know up front which
interface modes a given piece of hardware might support (even
if adding such an interface might fail later because of
concurrency issues), so let's make cfg80211 aware of that.
For good measure, disallow adding interfaces in all other
modes so drivers don't forget to announce support for one mode
when they add it.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Stephen Blackheath <tramp.enshrine.stephen@blacksapphire.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Luis R. Rodriguez authored and John W. Linville committed Sep 5, 2008
1 parent c6e387a commit f59ac04
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 3 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/adm8211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
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 */
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/ath5k/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,12 @@ ath5k_pci_probe(struct pci_dev *pdev,
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;
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,11 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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);

Expand Down
7 changes: 7 additions & 0 deletions drivers/net/wireless/b43/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4569,6 +4569,13 @@ static int b43_wireless_init(struct ssb_device *dev)
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))
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/b43legacy/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3704,6 +3704,11 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
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))
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,10 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* 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 */
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl3945-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -7888,6 +7888,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
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;

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ static int __init init_mac80211_hwsim(void)

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));
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/p54/p54common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
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;

Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/rt2x00/rt2x00dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
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.
*/
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/rtl8187_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
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");
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/zd1211rw/zd_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,11 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
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);
Expand Down
6 changes: 6 additions & 0 deletions include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ enum nl80211_commands {
* @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
*/
Expand Down Expand Up @@ -259,6 +263,8 @@ enum nl80211_attrs {

NL80211_ATTR_HT_CAPABILITY,

NL80211_ATTR_SUPPORTED_IFTYPES,

/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
Expand Down
3 changes: 3 additions & 0 deletions include/net/wireless.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ struct wiphy {
/* 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
Expand Down
7 changes: 7 additions & 0 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}

/* 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;
Expand Down
9 changes: 8 additions & 1 deletion net/wireless/core.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* 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>
Expand Down Expand Up @@ -259,6 +259,13 @@ int wiphy_register(struct wiphy *wiphy)
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++) {
Expand Down
22 changes: 20 additions & 2 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
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)
Expand All @@ -125,6 +127,20 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
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;
Expand Down Expand Up @@ -415,7 +431,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
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;
}
Expand Down Expand Up @@ -462,7 +479,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
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;
}
Expand Down

0 comments on commit f59ac04

Please sign in to comment.