Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: keep track of supported interface modes

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>

authored by

Luis R. Rodriguez and committed by
John W. Linville
f59ac048 c6e387a2

+95 -3
+1
drivers/net/wireless/adm8211.c
··· 1884 1884 dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); 1885 1885 /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ 1886 1886 dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; 1887 + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 1887 1888 1888 1889 dev->channel_change_time = 1000; 1889 1890 dev->max_signal = 100; /* FIXME: find better value */
+6
drivers/net/wireless/ath5k/base.c
··· 485 485 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | 486 486 IEEE80211_HW_SIGNAL_DBM | 487 487 IEEE80211_HW_NOISE_DBM; 488 + 489 + hw->wiphy->interface_modes = 490 + BIT(NL80211_IFTYPE_STATION) | 491 + BIT(NL80211_IFTYPE_ADHOC) | 492 + BIT(NL80211_IFTYPE_MESH_POINT); 493 + 488 494 hw->extra_tx_headroom = 2; 489 495 hw->channel_change_time = 5000; 490 496 sc = hw->priv;
+5
drivers/net/wireless/ath9k/main.c
··· 1482 1482 IEEE80211_HW_SIGNAL_DBM | 1483 1483 IEEE80211_HW_NOISE_DBM; 1484 1484 1485 + hw->wiphy->interface_modes = 1486 + BIT(NL80211_IFTYPE_AP) | 1487 + BIT(NL80211_IFTYPE_STATION) | 1488 + BIT(NL80211_IFTYPE_ADHOC); 1489 + 1485 1490 SET_IEEE80211_DEV(hw, &pdev->dev); 1486 1491 pci_set_drvdata(pdev, hw); 1487 1492
+7
drivers/net/wireless/b43/main.c
··· 4569 4569 IEEE80211_HW_SIGNAL_DBM | 4570 4570 IEEE80211_HW_NOISE_DBM; 4571 4571 4572 + hw->wiphy->interface_modes = 4573 + BIT(NL80211_IFTYPE_AP) | 4574 + BIT(NL80211_IFTYPE_MESH_POINT) | 4575 + BIT(NL80211_IFTYPE_STATION) | 4576 + BIT(NL80211_IFTYPE_WDS) | 4577 + BIT(NL80211_IFTYPE_ADHOC); 4578 + 4572 4579 hw->queues = b43_modparam_qos ? 4 : 1; 4573 4580 SET_IEEE80211_DEV(hw, dev->dev); 4574 4581 if (is_valid_ether_addr(sprom->et1mac))
+5
drivers/net/wireless/b43legacy/main.c
··· 3704 3704 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | 3705 3705 IEEE80211_HW_SIGNAL_DBM | 3706 3706 IEEE80211_HW_NOISE_DBM; 3707 + hw->wiphy->interface_modes = 3708 + BIT(NL80211_IFTYPE_AP) | 3709 + BIT(NL80211_IFTYPE_STATION) | 3710 + BIT(NL80211_IFTYPE_WDS) | 3711 + BIT(NL80211_IFTYPE_ADHOC); 3707 3712 hw->queues = 1; /* FIXME: hardware has more queues */ 3708 3713 SET_IEEE80211_DEV(hw, dev->dev); 3709 3714 if (is_valid_ether_addr(sprom->et1mac))
+4
drivers/net/wireless/iwlwifi/iwl-core.c
··· 819 819 /* Tell mac80211 our characteristics */ 820 820 hw->flags = IEEE80211_HW_SIGNAL_DBM | 821 821 IEEE80211_HW_NOISE_DBM; 822 + hw->wiphy->interface_modes = 823 + BIT(NL80211_IFTYPE_AP) | 824 + BIT(NL80211_IFTYPE_STATION) | 825 + BIT(NL80211_IFTYPE_ADHOC); 822 826 /* Default value; 4 EDCA QOS priorities */ 823 827 hw->queues = 4; 824 828 /* queues to support 11n aggregation */
+5
drivers/net/wireless/iwlwifi/iwl3945-base.c
··· 7888 7888 hw->flags = IEEE80211_HW_SIGNAL_DBM | 7889 7889 IEEE80211_HW_NOISE_DBM; 7890 7890 7891 + hw->wiphy->interface_modes = 7892 + BIT(NL80211_IFTYPE_AP) | 7893 + BIT(NL80211_IFTYPE_STATION) | 7894 + BIT(NL80211_IFTYPE_ADHOC); 7895 + 7891 7896 /* 4 EDCA QOS priorities */ 7892 7897 hw->queues = 4; 7893 7898
+3
drivers/net/wireless/mac80211_hwsim.c
··· 447 447 448 448 hw->channel_change_time = 1; 449 449 hw->queues = 4; 450 + hw->wiphy->interface_modes = 451 + BIT(NL80211_IFTYPE_STATION) | 452 + BIT(NL80211_IFTYPE_AP); 450 453 hw->ampdu_queues = 1; 451 454 452 455 memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
+3
drivers/net/wireless/p54/p54common.c
··· 1072 1072 dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ 1073 1073 IEEE80211_HW_RX_INCLUDES_FCS | 1074 1074 IEEE80211_HW_SIGNAL_UNSPEC; 1075 + 1076 + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 1077 + 1075 1078 dev->channel_change_time = 1000; /* TODO: find actual value */ 1076 1079 dev->max_signal = 127; 1077 1080
+5
drivers/net/wireless/rt2x00/rt2x00dev.c
··· 1052 1052 */ 1053 1053 rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); 1054 1054 1055 + rt2x00dev->hw->wiphy->interface_modes = 1056 + BIT(NL80211_IFTYPE_AP) | 1057 + BIT(NL80211_IFTYPE_STATION) | 1058 + BIT(NL80211_IFTYPE_ADHOC); 1059 + 1055 1060 /* 1056 1061 * Let the driver probe the device to detect the capabilities. 1057 1062 */
+2
drivers/net/wireless/rtl8187_dev.c
··· 1184 1184 dev->max_signal = 65; 1185 1185 } 1186 1186 1187 + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 1188 + 1187 1189 if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) 1188 1190 printk(KERN_INFO "rtl8187: inconsistency between id with OEM" 1189 1191 " info!\n");
+5
drivers/net/wireless/zd1211rw/zd_mac.c
··· 937 937 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | 938 938 IEEE80211_HW_SIGNAL_DB; 939 939 940 + hw->wiphy->interface_modes = 941 + BIT(NL80211_IFTYPE_MESH_POINT) | 942 + BIT(NL80211_IFTYPE_STATION) | 943 + BIT(NL80211_IFTYPE_ADHOC); 944 + 940 945 hw->max_signal = 100; 941 946 hw->queues = 1; 942 947 hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
+6
include/linux/nl80211.h
··· 210 210 * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from 211 211 * association request when used with NL80211_CMD_NEW_STATION) 212 212 * 213 + * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all 214 + * supported interface types, each a flag attribute with the number 215 + * of the interface mode. 216 + * 213 217 * @NL80211_ATTR_MAX: highest attribute number currently defined 214 218 * @__NL80211_ATTR_AFTER_LAST: internal use 215 219 */ ··· 262 258 NL80211_ATTR_BSS_SHORT_SLOT_TIME, 263 259 264 260 NL80211_ATTR_HT_CAPABILITY, 261 + 262 + NL80211_ATTR_SUPPORTED_IFTYPES, 265 263 266 264 /* add attributes here, update the policy in nl80211.c */ 267 265
+3
include/net/wireless.h
··· 185 185 /* permanent MAC address */ 186 186 u8 perm_addr[ETH_ALEN]; 187 187 188 + /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ 189 + u16 interface_modes; 190 + 188 191 /* If multiple wiphys are registered and you're handed e.g. 189 192 * a regular netdev with assigned ieee80211_ptr, you won't 190 193 * know whether it points to a wiphy your driver has registered
+7
net/mac80211/main.c
··· 1675 1675 } 1676 1676 } 1677 1677 1678 + /* if low-level driver supports AP, we also support VLAN */ 1679 + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) 1680 + local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); 1681 + 1682 + /* mac80211 always supports monitor */ 1683 + local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 1684 + 1678 1685 result = wiphy_register(local->hw.wiphy); 1679 1686 if (result < 0) 1680 1687 return result;
+8 -1
net/wireless/core.c
··· 1 1 /* 2 2 * This is the linux wireless configuration interface. 3 3 * 4 - * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> 4 + * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> 5 5 */ 6 6 7 7 #include <linux/if.h> ··· 259 259 struct ieee80211_supported_band *sband; 260 260 bool have_band = false; 261 261 int i; 262 + u16 ifmodes = wiphy->interface_modes; 263 + 264 + /* sanity check ifmodes */ 265 + WARN_ON(!ifmodes); 266 + ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; 267 + if (WARN_ON(ifmodes != wiphy->interface_modes)) 268 + wiphy->interface_modes = ifmodes; 262 269 263 270 /* sanity check supported bands/channels */ 264 271 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+20 -2
net/wireless/nl80211.c
··· 113 113 struct nlattr *nl_bands, *nl_band; 114 114 struct nlattr *nl_freqs, *nl_freq; 115 115 struct nlattr *nl_rates, *nl_rate; 116 + struct nlattr *nl_modes; 116 117 enum ieee80211_band band; 117 118 struct ieee80211_channel *chan; 118 119 struct ieee80211_rate *rate; 119 120 int i; 121 + u16 ifmodes = dev->wiphy.interface_modes; 120 122 121 123 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); 122 124 if (!hdr) ··· 126 124 127 125 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); 128 126 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); 127 + 128 + nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); 129 + if (!nl_modes) 130 + goto nla_put_failure; 131 + 132 + i = 0; 133 + while (ifmodes) { 134 + if (ifmodes & 1) 135 + NLA_PUT_FLAG(msg, i); 136 + ifmodes >>= 1; 137 + i++; 138 + } 139 + 140 + nla_nest_end(msg, nl_modes); 129 141 130 142 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); 131 143 if (!nl_bands) ··· 431 415 ifindex = dev->ifindex; 432 416 dev_put(dev); 433 417 434 - if (!drv->ops->change_virtual_intf) { 418 + if (!drv->ops->change_virtual_intf || 419 + !(drv->wiphy.interface_modes & (1 << type))) { 435 420 err = -EOPNOTSUPP; 436 421 goto unlock; 437 422 } ··· 479 462 if (IS_ERR(drv)) 480 463 return PTR_ERR(drv); 481 464 482 - if (!drv->ops->add_virtual_intf) { 465 + if (!drv->ops->add_virtual_intf || 466 + !(drv->wiphy.interface_modes & (1 << type))) { 483 467 err = -EOPNOTSUPP; 484 468 goto unlock; 485 469 }