diff options
-rw-r--r-- | include/linux/nl80211.h | 122 | ||||
-rw-r--r-- | include/net/cfg80211.h | 88 | ||||
-rw-r--r-- | net/mac80211/main.c | 16 | ||||
-rw-r--r-- | net/wireless/core.c | 69 | ||||
-rw-r--r-- | net/wireless/core.h | 11 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 105 | ||||
-rw-r--r-- | net/wireless/util.c | 80 |
7 files changed, 472 insertions, 19 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 281a2bb6a6ec..0ea497cb607c 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -77,6 +77,39 @@ | |||
77 | */ | 77 | */ |
78 | 78 | ||
79 | /** | 79 | /** |
80 | * DOC: Virtual interface / concurrency capabilities | ||
81 | * | ||
82 | * Some devices are able to operate with virtual MACs, they can have | ||
83 | * more than one virtual interface. The capability handling for this | ||
84 | * is a bit complex though, as there may be a number of restrictions | ||
85 | * on the types of concurrency that are supported. | ||
86 | * | ||
87 | * To start with, each device supports the interface types listed in | ||
88 | * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the | ||
89 | * types there no concurrency is implied. | ||
90 | * | ||
91 | * Once concurrency is desired, more attributes must be observed: | ||
92 | * To start with, since some interface types are purely managed in | ||
93 | * software, like the AP-VLAN type in mac80211 for example, there's | ||
94 | * an additional list of these, they can be added at any time and | ||
95 | * are only restricted by some semantic restrictions (e.g. AP-VLAN | ||
96 | * cannot be added without a corresponding AP interface). This list | ||
97 | * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. | ||
98 | * | ||
99 | * Further, the list of supported combinations is exported. This is | ||
100 | * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, | ||
101 | * it exports a list of "groups", and at any point in time the | ||
102 | * interfaces that are currently active must fall into any one of | ||
103 | * the advertised groups. Within each group, there are restrictions | ||
104 | * on the number of interfaces of different types that are supported | ||
105 | * and also the number of different channels, along with potentially | ||
106 | * some other restrictions. See &enum nl80211_if_combination_attrs. | ||
107 | * | ||
108 | * All together, these attributes define the concurrency of virtual | ||
109 | * interfaces that a given device supports. | ||
110 | */ | ||
111 | |||
112 | /** | ||
80 | * enum nl80211_commands - supported nl80211 commands | 113 | * enum nl80211_commands - supported nl80211 commands |
81 | * | 114 | * |
82 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors | 115 | * @NL80211_CMD_UNSPEC: unspecified command to catch errors |
@@ -954,6 +987,14 @@ enum nl80211_commands { | |||
954 | * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan | 987 | * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan |
955 | * cycles, in msecs. | 988 | * cycles, in msecs. |
956 | * | 989 | * |
990 | * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported | ||
991 | * interface combinations. In each nested item, it contains attributes | ||
992 | * defined in &enum nl80211_if_combination_attrs. | ||
993 | * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like | ||
994 | * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that | ||
995 | * are managed in software: interfaces of these types aren't subject to | ||
996 | * any restrictions in their number or combinations. | ||
997 | * | ||
957 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 998 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
958 | * @__NL80211_ATTR_AFTER_LAST: internal use | 999 | * @__NL80211_ATTR_AFTER_LAST: internal use |
959 | */ | 1000 | */ |
@@ -1149,6 +1190,9 @@ enum nl80211_attrs { | |||
1149 | 1190 | ||
1150 | NL80211_ATTR_SCHED_SCAN_INTERVAL, | 1191 | NL80211_ATTR_SCHED_SCAN_INTERVAL, |
1151 | 1192 | ||
1193 | NL80211_ATTR_INTERFACE_COMBINATIONS, | ||
1194 | NL80211_ATTR_SOFTWARE_IFTYPES, | ||
1195 | |||
1152 | /* add attributes here, update the policy in nl80211.c */ | 1196 | /* add attributes here, update the policy in nl80211.c */ |
1153 | 1197 | ||
1154 | __NL80211_ATTR_AFTER_LAST, | 1198 | __NL80211_ATTR_AFTER_LAST, |
@@ -1201,7 +1245,9 @@ enum nl80211_attrs { | |||
1201 | * @NL80211_IFTYPE_ADHOC: independent BSS member | 1245 | * @NL80211_IFTYPE_ADHOC: independent BSS member |
1202 | * @NL80211_IFTYPE_STATION: managed BSS member | 1246 | * @NL80211_IFTYPE_STATION: managed BSS member |
1203 | * @NL80211_IFTYPE_AP: access point | 1247 | * @NL80211_IFTYPE_AP: access point |
1204 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points | 1248 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces |
1249 | * are a bit special in that they must always be tied to a pre-existing | ||
1250 | * AP type interface. | ||
1205 | * @NL80211_IFTYPE_WDS: wireless distribution interface | 1251 | * @NL80211_IFTYPE_WDS: wireless distribution interface |
1206 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames | 1252 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames |
1207 | * @NL80211_IFTYPE_MESH_POINT: mesh point | 1253 | * @NL80211_IFTYPE_MESH_POINT: mesh point |
@@ -2206,4 +2252,78 @@ enum nl80211_wowlan_triggers { | |||
2206 | MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 | 2252 | MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 |
2207 | }; | 2253 | }; |
2208 | 2254 | ||
2255 | /** | ||
2256 | * enum nl80211_iface_limit_attrs - limit attributes | ||
2257 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) | ||
2258 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that | ||
2259 | * can be chosen from this set of interface types (u32) | ||
2260 | * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a | ||
2261 | * flag attribute for each interface type in this set | ||
2262 | * @NUM_NL80211_IFACE_LIMIT: number of attributes | ||
2263 | * @MAX_NL80211_IFACE_LIMIT: highest attribute number | ||
2264 | */ | ||
2265 | enum nl80211_iface_limit_attrs { | ||
2266 | NL80211_IFACE_LIMIT_UNSPEC, | ||
2267 | NL80211_IFACE_LIMIT_MAX, | ||
2268 | NL80211_IFACE_LIMIT_TYPES, | ||
2269 | |||
2270 | /* keep last */ | ||
2271 | NUM_NL80211_IFACE_LIMIT, | ||
2272 | MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 | ||
2273 | }; | ||
2274 | |||
2275 | /** | ||
2276 | * enum nl80211_if_combination_attrs -- interface combination attributes | ||
2277 | * | ||
2278 | * @NL80211_IFACE_COMB_UNSPEC: (reserved) | ||
2279 | * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits | ||
2280 | * for given interface types, see &enum nl80211_iface_limit_attrs. | ||
2281 | * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of | ||
2282 | * interfaces that can be created in this group. This number doesn't | ||
2283 | * apply to interfaces purely managed in software, which are listed | ||
2284 | * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. | ||
2285 | * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that | ||
2286 | * beacon intervals within this group must be all the same even for | ||
2287 | * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt | ||
2288 | * the infrastructure network's beacon interval. | ||
2289 | * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many | ||
2290 | * different channels may be used within this group. | ||
2291 | * @NUM_NL80211_IFACE_COMB: number of attributes | ||
2292 | * @MAX_NL80211_IFACE_COMB: highest attribute number | ||
2293 | * | ||
2294 | * Examples: | ||
2295 | * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 | ||
2296 | * => allows an AP and a STA that must match BIs | ||
2297 | * | ||
2298 | * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 | ||
2299 | * => allows 8 of AP/GO | ||
2300 | * | ||
2301 | * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 | ||
2302 | * => allows two STAs on different channels | ||
2303 | * | ||
2304 | * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 | ||
2305 | * => allows a STA plus three P2P interfaces | ||
2306 | * | ||
2307 | * The list of these four possiblities could completely be contained | ||
2308 | * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate | ||
2309 | * that any of these groups must match. | ||
2310 | * | ||
2311 | * "Combinations" of just a single interface will not be listed here, | ||
2312 | * a single interface of any valid interface type is assumed to always | ||
2313 | * be possible by itself. This means that implicitly, for each valid | ||
2314 | * interface type, the following group always exists: | ||
2315 | * numbers = [ #{<type>} <= 1 ], channels = 1, max = 1 | ||
2316 | */ | ||
2317 | enum nl80211_if_combination_attrs { | ||
2318 | NL80211_IFACE_COMB_UNSPEC, | ||
2319 | NL80211_IFACE_COMB_LIMITS, | ||
2320 | NL80211_IFACE_COMB_MAXNUM, | ||
2321 | NL80211_IFACE_COMB_STA_AP_BI_MATCH, | ||
2322 | NL80211_IFACE_COMB_NUM_CHANNELS, | ||
2323 | |||
2324 | /* keep last */ | ||
2325 | NUM_NL80211_IFACE_COMB, | ||
2326 | MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 | ||
2327 | }; | ||
2328 | |||
2209 | #endif /* __LINUX_NL80211_H */ | 2329 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e1f1b41f7b13..04afcfb9eaf4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1547,6 +1547,10 @@ struct cfg80211_ops { | |||
1547 | * hints read the documenation for regulatory_hint_found_beacon() | 1547 | * hints read the documenation for regulatory_hint_found_beacon() |
1548 | * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this | 1548 | * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this |
1549 | * wiphy at all | 1549 | * wiphy at all |
1550 | * @WIPHY_FLAG_ENFORCE_COMBINATIONS: Set this flag to enforce interface | ||
1551 | * combinations for this device. This flag is used for backward | ||
1552 | * compatibility only until all drivers advertise combinations and | ||
1553 | * they will always be enforced. | ||
1550 | * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled | 1554 | * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled |
1551 | * by default -- this flag will be set depending on the kernel's default | 1555 | * by default -- this flag will be set depending on the kernel's default |
1552 | * on wiphy_new(), but can be changed by the driver if it has a good | 1556 | * on wiphy_new(), but can be changed by the driver if it has a good |
@@ -1574,6 +1578,81 @@ enum wiphy_flags { | |||
1574 | WIPHY_FLAG_IBSS_RSN = BIT(8), | 1578 | WIPHY_FLAG_IBSS_RSN = BIT(8), |
1575 | WIPHY_FLAG_MESH_AUTH = BIT(10), | 1579 | WIPHY_FLAG_MESH_AUTH = BIT(10), |
1576 | WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), | 1580 | WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), |
1581 | WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), | ||
1582 | }; | ||
1583 | |||
1584 | /** | ||
1585 | * struct ieee80211_iface_limit - limit on certain interface types | ||
1586 | * @max: maximum number of interfaces of these types | ||
1587 | * @types: interface types (bits) | ||
1588 | */ | ||
1589 | struct ieee80211_iface_limit { | ||
1590 | u16 max; | ||
1591 | u16 types; | ||
1592 | }; | ||
1593 | |||
1594 | /** | ||
1595 | * struct ieee80211_iface_combination - possible interface combination | ||
1596 | * @limits: limits for the given interface types | ||
1597 | * @n_limits: number of limitations | ||
1598 | * @num_different_channels: can use up to this many different channels | ||
1599 | * @max_interfaces: maximum number of interfaces in total allowed in this | ||
1600 | * group | ||
1601 | * @beacon_int_infra_match: In this combination, the beacon intervals | ||
1602 | * between infrastructure and AP types must match. This is required | ||
1603 | * only in special cases. | ||
1604 | * | ||
1605 | * These examples can be expressed as follows: | ||
1606 | * | ||
1607 | * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: | ||
1608 | * | ||
1609 | * struct ieee80211_iface_limit limits1[] = { | ||
1610 | * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, | ||
1611 | * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, }, | ||
1612 | * }; | ||
1613 | * struct ieee80211_iface_combination combination1 = { | ||
1614 | * .limits = limits1, | ||
1615 | * .n_limits = ARRAY_SIZE(limits1), | ||
1616 | * .max_interfaces = 2, | ||
1617 | * .beacon_int_infra_match = true, | ||
1618 | * }; | ||
1619 | * | ||
1620 | * | ||
1621 | * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: | ||
1622 | * | ||
1623 | * struct ieee80211_iface_limit limits2[] = { | ||
1624 | * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | | ||
1625 | * BIT(NL80211_IFTYPE_P2P_GO), }, | ||
1626 | * }; | ||
1627 | * struct ieee80211_iface_combination combination2 = { | ||
1628 | * .limits = limits2, | ||
1629 | * .n_limits = ARRAY_SIZE(limits2), | ||
1630 | * .max_interfaces = 8, | ||
1631 | * .num_different_channels = 1, | ||
1632 | * }; | ||
1633 | * | ||
1634 | * | ||
1635 | * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. | ||
1636 | * This allows for an infrastructure connection and three P2P connections. | ||
1637 | * | ||
1638 | * struct ieee80211_iface_limit limits3[] = { | ||
1639 | * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, | ||
1640 | * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) | | ||
1641 | * BIT(NL80211_IFTYPE_P2P_CLIENT), }, | ||
1642 | * }; | ||
1643 | * struct ieee80211_iface_combination combination3 = { | ||
1644 | * .limits = limits3, | ||
1645 | * .n_limits = ARRAY_SIZE(limits3), | ||
1646 | * .max_interfaces = 4, | ||
1647 | * .num_different_channels = 2, | ||
1648 | * }; | ||
1649 | */ | ||
1650 | struct ieee80211_iface_combination { | ||
1651 | const struct ieee80211_iface_limit *limits; | ||
1652 | u32 num_different_channels; | ||
1653 | u16 max_interfaces; | ||
1654 | u8 n_limits; | ||
1655 | bool beacon_int_infra_match; | ||
1577 | }; | 1656 | }; |
1578 | 1657 | ||
1579 | struct mac_address { | 1658 | struct mac_address { |
@@ -1653,6 +1732,11 @@ struct wiphy_wowlan_support { | |||
1653 | * @priv: driver private data (sized according to wiphy_new() parameter) | 1732 | * @priv: driver private data (sized according to wiphy_new() parameter) |
1654 | * @interface_modes: bitmask of interfaces types valid for this wiphy, | 1733 | * @interface_modes: bitmask of interfaces types valid for this wiphy, |
1655 | * must be set by driver | 1734 | * must be set by driver |
1735 | * @iface_combinations: Valid interface combinations array, should not | ||
1736 | * list single interface types. | ||
1737 | * @n_iface_combinations: number of entries in @iface_combinations array. | ||
1738 | * @software_iftypes: bitmask of software interface types, these are not | ||
1739 | * subject to any restrictions since they are purely managed in SW. | ||
1656 | * @flags: wiphy flags, see &enum wiphy_flags | 1740 | * @flags: wiphy flags, see &enum wiphy_flags |
1657 | * @bss_priv_size: each BSS struct has private data allocated with it, | 1741 | * @bss_priv_size: each BSS struct has private data allocated with it, |
1658 | * this variable determines its size | 1742 | * this variable determines its size |
@@ -1697,6 +1781,10 @@ struct wiphy { | |||
1697 | 1781 | ||
1698 | const struct ieee80211_txrx_stypes *mgmt_stypes; | 1782 | const struct ieee80211_txrx_stypes *mgmt_stypes; |
1699 | 1783 | ||
1784 | const struct ieee80211_iface_combination *iface_combinations; | ||
1785 | int n_iface_combinations; | ||
1786 | u16 software_iftypes; | ||
1787 | |||
1700 | u16 n_addresses; | 1788 | u16 n_addresses; |
1701 | 1789 | ||
1702 | /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ | 1790 | /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7f89011fa22d..79a2281678bf 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -685,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); | |||
685 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 685 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
686 | { | 686 | { |
687 | struct ieee80211_local *local = hw_to_local(hw); | 687 | struct ieee80211_local *local = hw_to_local(hw); |
688 | int result; | 688 | int result, i; |
689 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
690 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
691 | bool supp_ht; | 691 | bool supp_ht; |
@@ -743,11 +743,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
743 | return -ENOMEM; | 743 | return -ENOMEM; |
744 | 744 | ||
745 | /* if low-level driver supports AP, we also support VLAN */ | 745 | /* if low-level driver supports AP, we also support VLAN */ |
746 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 746 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
747 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 747 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
748 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); | ||
749 | } | ||
748 | 750 | ||
749 | /* mac80211 always supports monitor */ | 751 | /* mac80211 always supports monitor */ |
750 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 752 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
753 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); | ||
754 | |||
755 | /* mac80211 doesn't support more than 1 channel */ | ||
756 | for (i = 0; i < hw->wiphy->n_iface_combinations; i++) | ||
757 | if (hw->wiphy->iface_combinations[i].num_different_channels > 1) | ||
758 | return -EINVAL; | ||
751 | 759 | ||
752 | #ifndef CONFIG_MAC80211_MESH | 760 | #ifndef CONFIG_MAC80211_MESH |
753 | /* mesh depends on Kconfig, but drivers should set it if they want */ | 761 | /* mesh depends on Kconfig, but drivers should set it if they want */ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 18b002f16860..c22ef3492ee6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -416,6 +416,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
416 | } | 416 | } |
417 | EXPORT_SYMBOL(wiphy_new); | 417 | EXPORT_SYMBOL(wiphy_new); |
418 | 418 | ||
419 | static int wiphy_verify_combinations(struct wiphy *wiphy) | ||
420 | { | ||
421 | const struct ieee80211_iface_combination *c; | ||
422 | int i, j; | ||
423 | |||
424 | /* If we have combinations enforce them */ | ||
425 | if (wiphy->n_iface_combinations) | ||
426 | wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; | ||
427 | |||
428 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
429 | u32 cnt = 0; | ||
430 | u16 all_iftypes = 0; | ||
431 | |||
432 | c = &wiphy->iface_combinations[i]; | ||
433 | |||
434 | /* Combinations with just one interface aren't real */ | ||
435 | if (WARN_ON(c->max_interfaces < 2)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | /* Need at least one channel */ | ||
439 | if (WARN_ON(!c->num_different_channels)) | ||
440 | return -EINVAL; | ||
441 | |||
442 | if (WARN_ON(!c->n_limits)) | ||
443 | return -EINVAL; | ||
444 | |||
445 | for (j = 0; j < c->n_limits; j++) { | ||
446 | u16 types = c->limits[j].types; | ||
447 | |||
448 | /* | ||
449 | * interface types shouldn't overlap, this is | ||
450 | * used in cfg80211_can_change_interface() | ||
451 | */ | ||
452 | if (WARN_ON(types & all_iftypes)) | ||
453 | return -EINVAL; | ||
454 | all_iftypes |= types; | ||
455 | |||
456 | if (WARN_ON(!c->limits[j].max)) | ||
457 | return -EINVAL; | ||
458 | |||
459 | /* Shouldn't list software iftypes in combinations! */ | ||
460 | if (WARN_ON(wiphy->software_iftypes & types)) | ||
461 | return -EINVAL; | ||
462 | |||
463 | cnt += c->limits[j].max; | ||
464 | /* | ||
465 | * Don't advertise an unsupported type | ||
466 | * in a combination. | ||
467 | */ | ||
468 | if (WARN_ON((wiphy->interface_modes & types) != types)) | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | /* You can't even choose that many! */ | ||
473 | if (WARN_ON(cnt < c->max_interfaces)) | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
419 | int wiphy_register(struct wiphy *wiphy) | 480 | int wiphy_register(struct wiphy *wiphy) |
420 | { | 481 | { |
421 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 482 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
@@ -444,6 +505,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
444 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 505 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
445 | wiphy->interface_modes = ifmodes; | 506 | wiphy->interface_modes = ifmodes; |
446 | 507 | ||
508 | res = wiphy_verify_combinations(wiphy); | ||
509 | if (res) | ||
510 | return res; | ||
511 | |||
447 | /* sanity check supported bands/channels */ | 512 | /* sanity check supported bands/channels */ |
448 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 513 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
449 | sband = wiphy->bands[band]; | 514 | sband = wiphy->bands[band]; |
@@ -698,6 +763,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
698 | struct net_device *dev = ndev; | 763 | struct net_device *dev = ndev; |
699 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 764 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
700 | struct cfg80211_registered_device *rdev; | 765 | struct cfg80211_registered_device *rdev; |
766 | int ret; | ||
701 | 767 | ||
702 | if (!wdev) | 768 | if (!wdev) |
703 | return NOTIFY_DONE; | 769 | return NOTIFY_DONE; |
@@ -893,6 +959,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
893 | return notifier_from_errno(-EOPNOTSUPP); | 959 | return notifier_from_errno(-EOPNOTSUPP); |
894 | if (rfkill_blocked(rdev->rfkill)) | 960 | if (rfkill_blocked(rdev->rfkill)) |
895 | return notifier_from_errno(-ERFKILL); | 961 | return notifier_from_errno(-ERFKILL); |
962 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | ||
963 | if (ret) | ||
964 | return notifier_from_errno(ret); | ||
896 | break; | 965 | break; |
897 | } | 966 | } |
898 | 967 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index d4b8f4c0bbbb..bf0fb40e3c8b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -422,6 +422,17 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
422 | u32 *flags, struct vif_params *params); | 422 | u32 *flags, struct vif_params *params); |
423 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 423 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
424 | 424 | ||
425 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
426 | struct wireless_dev *wdev, | ||
427 | enum nl80211_iftype iftype); | ||
428 | |||
429 | static inline int | ||
430 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | ||
431 | enum nl80211_iftype iftype) | ||
432 | { | ||
433 | return cfg80211_can_change_interface(rdev, NULL, iftype); | ||
434 | } | ||
435 | |||
425 | struct ieee80211_channel * | 436 | struct ieee80211_channel * |
426 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 437 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
427 | int freq, enum nl80211_channel_type channel_type); | 438 | int freq, enum nl80211_channel_type channel_type); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9ef8e287d61b..beac296b1fde 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -564,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
564 | return 0; | 564 | return 0; |
565 | } | 565 | } |
566 | 566 | ||
567 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | ||
568 | { | ||
569 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | ||
570 | int i; | ||
571 | |||
572 | if (!nl_modes) | ||
573 | goto nla_put_failure; | ||
574 | |||
575 | i = 0; | ||
576 | while (ifmodes) { | ||
577 | if (ifmodes & 1) | ||
578 | NLA_PUT_FLAG(msg, i); | ||
579 | ifmodes >>= 1; | ||
580 | i++; | ||
581 | } | ||
582 | |||
583 | nla_nest_end(msg, nl_modes); | ||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOBUFS; | ||
588 | } | ||
589 | |||
590 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | ||
591 | struct sk_buff *msg) | ||
592 | { | ||
593 | struct nlattr *nl_combis; | ||
594 | int i, j; | ||
595 | |||
596 | nl_combis = nla_nest_start(msg, | ||
597 | NL80211_ATTR_INTERFACE_COMBINATIONS); | ||
598 | if (!nl_combis) | ||
599 | goto nla_put_failure; | ||
600 | |||
601 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
602 | const struct ieee80211_iface_combination *c; | ||
603 | struct nlattr *nl_combi, *nl_limits; | ||
604 | |||
605 | c = &wiphy->iface_combinations[i]; | ||
606 | |||
607 | nl_combi = nla_nest_start(msg, i + 1); | ||
608 | if (!nl_combi) | ||
609 | goto nla_put_failure; | ||
610 | |||
611 | nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); | ||
612 | if (!nl_limits) | ||
613 | goto nla_put_failure; | ||
614 | |||
615 | for (j = 0; j < c->n_limits; j++) { | ||
616 | struct nlattr *nl_limit; | ||
617 | |||
618 | nl_limit = nla_nest_start(msg, j + 1); | ||
619 | if (!nl_limit) | ||
620 | goto nla_put_failure; | ||
621 | NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, | ||
622 | c->limits[j].max); | ||
623 | if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, | ||
624 | c->limits[j].types)) | ||
625 | goto nla_put_failure; | ||
626 | nla_nest_end(msg, nl_limit); | ||
627 | } | ||
628 | |||
629 | nla_nest_end(msg, nl_limits); | ||
630 | |||
631 | if (c->beacon_int_infra_match) | ||
632 | NLA_PUT_FLAG(msg, | ||
633 | NL80211_IFACE_COMB_STA_AP_BI_MATCH); | ||
634 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, | ||
635 | c->num_different_channels); | ||
636 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, | ||
637 | c->max_interfaces); | ||
638 | |||
639 | nla_nest_end(msg, nl_combi); | ||
640 | } | ||
641 | |||
642 | nla_nest_end(msg, nl_combis); | ||
643 | |||
644 | return 0; | ||
645 | nla_put_failure: | ||
646 | return -ENOBUFS; | ||
647 | } | ||
648 | |||
567 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 649 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
568 | struct cfg80211_registered_device *dev) | 650 | struct cfg80211_registered_device *dev) |
569 | { | 651 | { |
@@ -571,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
571 | struct nlattr *nl_bands, *nl_band; | 653 | struct nlattr *nl_bands, *nl_band; |
572 | struct nlattr *nl_freqs, *nl_freq; | 654 | struct nlattr *nl_freqs, *nl_freq; |
573 | struct nlattr *nl_rates, *nl_rate; | 655 | struct nlattr *nl_rates, *nl_rate; |
574 | struct nlattr *nl_modes; | ||
575 | struct nlattr *nl_cmds; | 656 | struct nlattr *nl_cmds; |
576 | enum ieee80211_band band; | 657 | enum ieee80211_band band; |
577 | struct ieee80211_channel *chan; | 658 | struct ieee80211_channel *chan; |
578 | struct ieee80211_rate *rate; | 659 | struct ieee80211_rate *rate; |
579 | int i; | 660 | int i; |
580 | u16 ifmodes = dev->wiphy.interface_modes; | ||
581 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 661 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
582 | dev->wiphy.mgmt_stypes; | 662 | dev->wiphy.mgmt_stypes; |
583 | 663 | ||
@@ -637,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
637 | } | 717 | } |
638 | } | 718 | } |
639 | 719 | ||
640 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 720 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
641 | if (!nl_modes) | 721 | dev->wiphy.interface_modes)) |
642 | goto nla_put_failure; | 722 | goto nla_put_failure; |
643 | 723 | ||
644 | i = 0; | ||
645 | while (ifmodes) { | ||
646 | if (ifmodes & 1) | ||
647 | NLA_PUT_FLAG(msg, i); | ||
648 | ifmodes >>= 1; | ||
649 | i++; | ||
650 | } | ||
651 | |||
652 | nla_nest_end(msg, nl_modes); | ||
653 | |||
654 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 724 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
655 | if (!nl_bands) | 725 | if (!nl_bands) |
656 | goto nla_put_failure; | 726 | goto nla_put_failure; |
@@ -865,6 +935,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
865 | nla_nest_end(msg, nl_wowlan); | 935 | nla_nest_end(msg, nl_wowlan); |
866 | } | 936 | } |
867 | 937 | ||
938 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
939 | dev->wiphy.software_iftypes)) | ||
940 | goto nla_put_failure; | ||
941 | |||
942 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | ||
943 | goto nla_put_failure; | ||
944 | |||
868 | return genlmsg_end(msg, hdr); | 945 | return genlmsg_end(msg, hdr); |
869 | 946 | ||
870 | nla_put_failure: | 947 | nla_put_failure: |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 414c9f604df6..95e4e254da0a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -803,6 +803,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
803 | return -EBUSY; | 803 | return -EBUSY; |
804 | 804 | ||
805 | if (ntype != otype) { | 805 | if (ntype != otype) { |
806 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | ||
807 | ntype); | ||
808 | if (err) | ||
809 | return err; | ||
810 | |||
806 | dev->ieee80211_ptr->use_4addr = false; | 811 | dev->ieee80211_ptr->use_4addr = false; |
807 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 812 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
808 | 813 | ||
@@ -921,3 +926,78 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
921 | 926 | ||
922 | return res; | 927 | return res; |
923 | } | 928 | } |
929 | |||
930 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
931 | struct wireless_dev *wdev, | ||
932 | enum nl80211_iftype iftype) | ||
933 | { | ||
934 | struct wireless_dev *wdev_iter; | ||
935 | int num[NUM_NL80211_IFTYPES]; | ||
936 | int total = 1; | ||
937 | int i, j; | ||
938 | |||
939 | ASSERT_RTNL(); | ||
940 | |||
941 | /* Always allow software iftypes */ | ||
942 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
943 | return 0; | ||
944 | |||
945 | /* | ||
946 | * Drivers will gradually all set this flag, until all | ||
947 | * have it we only enforce for those that set it. | ||
948 | */ | ||
949 | if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS)) | ||
950 | return 0; | ||
951 | |||
952 | memset(num, 0, sizeof(num)); | ||
953 | |||
954 | num[iftype] = 1; | ||
955 | |||
956 | mutex_lock(&rdev->devlist_mtx); | ||
957 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | ||
958 | if (wdev_iter == wdev) | ||
959 | continue; | ||
960 | if (!netif_running(wdev_iter->netdev)) | ||
961 | continue; | ||
962 | |||
963 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | ||
964 | continue; | ||
965 | |||
966 | num[wdev_iter->iftype]++; | ||
967 | total++; | ||
968 | } | ||
969 | mutex_unlock(&rdev->devlist_mtx); | ||
970 | |||
971 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { | ||
972 | const struct ieee80211_iface_combination *c; | ||
973 | struct ieee80211_iface_limit *limits; | ||
974 | |||
975 | c = &rdev->wiphy.iface_combinations[i]; | ||
976 | |||
977 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | ||
978 | GFP_KERNEL); | ||
979 | if (!limits) | ||
980 | return -ENOMEM; | ||
981 | if (total > c->max_interfaces) | ||
982 | goto cont; | ||
983 | |||
984 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | ||
985 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
986 | continue; | ||
987 | for (j = 0; j < c->n_limits; j++) { | ||
988 | if (!(limits[j].types & iftype)) | ||
989 | continue; | ||
990 | if (limits[j].max < num[iftype]) | ||
991 | goto cont; | ||
992 | limits[j].max -= num[iftype]; | ||
993 | } | ||
994 | } | ||
995 | /* yay, it fits */ | ||
996 | kfree(limits); | ||
997 | return 0; | ||
998 | cont: | ||
999 | kfree(limits); | ||
1000 | } | ||
1001 | |||
1002 | return -EBUSY; | ||
1003 | } | ||