diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-06-15 08:33:17 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-07-09 08:51:46 -0400 |
commit | 89a54e48b9cbb44aed1bf6cd712e087b96b6ae65 (patch) | |
tree | f605a69704d49c5535adf2906b276ca2207a078f | |
parent | f72b85b8eb6657fae95ac8f5cb20954b4d87a520 (diff) |
nl80211: prepare for non-netdev wireless devs
In order to support a P2P device abstraction and
Bluetooth high-speed AMPs, we need to have a way
to identify virtual interfaces that don't have a
netdev associated.
Do this by adding a NL80211_ATTR_WDEV attribute
to identify a wdev which may or may not also be
a netdev.
To simplify things, use a 64-bit value with the
high 32 bits being the wiphy index for this new
wdev identifier in the nl80211 API.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/linux/nl80211.h | 5 | ||||
-rw-r--r-- | include/net/cfg80211.h | 22 | ||||
-rw-r--r-- | net/wireless/core.c | 13 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 135 | ||||
-rw-r--r-- | net/wireless/sme.c | 4 | ||||
-rw-r--r-- | net/wireless/util.c | 6 |
7 files changed, 144 insertions, 47 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index db961a59247..e791487ead3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -771,6 +771,9 @@ enum nl80211_commands { | |||
771 | * @NL80211_ATTR_IFNAME: network interface name | 771 | * @NL80211_ATTR_IFNAME: network interface name |
772 | * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype | 772 | * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype |
773 | * | 773 | * |
774 | * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices | ||
775 | * that don't have a netdev (u64) | ||
776 | * | ||
774 | * @NL80211_ATTR_MAC: MAC address (various uses) | 777 | * @NL80211_ATTR_MAC: MAC address (various uses) |
775 | * | 778 | * |
776 | * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of | 779 | * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of |
@@ -1493,6 +1496,8 @@ enum nl80211_attrs { | |||
1493 | 1496 | ||
1494 | NL80211_ATTR_BG_SCAN_PERIOD, | 1497 | NL80211_ATTR_BG_SCAN_PERIOD, |
1495 | 1498 | ||
1499 | NL80211_ATTR_WDEV, | ||
1500 | |||
1496 | /* add attributes here, update the policy in nl80211.c */ | 1501 | /* add attributes here, update the policy in nl80211.c */ |
1497 | 1502 | ||
1498 | __NL80211_ATTR_AFTER_LAST, | 1503 | __NL80211_ATTR_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 51f67a9003a..a14e6a40668 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -2341,17 +2341,25 @@ struct cfg80211_internal_bss; | |||
2341 | struct cfg80211_cached_keys; | 2341 | struct cfg80211_cached_keys; |
2342 | 2342 | ||
2343 | /** | 2343 | /** |
2344 | * struct wireless_dev - wireless per-netdev state | 2344 | * struct wireless_dev - wireless device state |
2345 | * | 2345 | * |
2346 | * This structure must be allocated by the driver/stack | 2346 | * For netdevs, this structure must be allocated by the driver |
2347 | * that uses the ieee80211_ptr field in struct net_device | 2347 | * that uses the ieee80211_ptr field in struct net_device (this |
2348 | * (this is intentional so it can be allocated along with | 2348 | * is intentional so it can be allocated along with the netdev.) |
2349 | * the netdev.) | 2349 | * It need not be registered then as netdev registration will |
2350 | * be intercepted by cfg80211 to see the new wireless device. | ||
2351 | * | ||
2352 | * For non-netdev uses, it must also be allocated by the driver | ||
2353 | * in response to the cfg80211 callbacks that require it, as | ||
2354 | * there's no netdev registration in that case it may not be | ||
2355 | * allocated outside of callback operations that return it. | ||
2350 | * | 2356 | * |
2351 | * @wiphy: pointer to hardware description | 2357 | * @wiphy: pointer to hardware description |
2352 | * @iftype: interface type | 2358 | * @iftype: interface type |
2353 | * @list: (private) Used to collect the interfaces | 2359 | * @list: (private) Used to collect the interfaces |
2354 | * @netdev: (private) Used to reference back to the netdev | 2360 | * @netdev: (private) Used to reference back to the netdev, may be %NULL |
2361 | * @identifier: (private) Identifier used in nl80211 to identify this | ||
2362 | * wireless device if it has no netdev | ||
2355 | * @current_bss: (private) Used by the internal configuration code | 2363 | * @current_bss: (private) Used by the internal configuration code |
2356 | * @channel: (private) Used by the internal configuration code to track | 2364 | * @channel: (private) Used by the internal configuration code to track |
2357 | * the user-set AP, monitor and WDS channel | 2365 | * the user-set AP, monitor and WDS channel |
@@ -2383,6 +2391,8 @@ struct wireless_dev { | |||
2383 | struct list_head list; | 2391 | struct list_head list; |
2384 | struct net_device *netdev; | 2392 | struct net_device *netdev; |
2385 | 2393 | ||
2394 | u32 identifier; | ||
2395 | |||
2386 | struct list_head mgmt_registrations; | 2396 | struct list_head mgmt_registrations; |
2387 | spinlock_t mgmt_registrations_lock; | 2397 | spinlock_t mgmt_registrations_lock; |
2388 | 2398 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index e42a97b5b97..b110a8a242d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -176,7 +176,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
176 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) | 176 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) |
177 | return -EOPNOTSUPP; | 177 | return -EOPNOTSUPP; |
178 | 178 | ||
179 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 179 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
180 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 180 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
181 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); | 181 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); |
182 | if (err) | 182 | if (err) |
@@ -188,7 +188,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
188 | /* failed -- clean up to old netns */ | 188 | /* failed -- clean up to old netns */ |
189 | net = wiphy_net(&rdev->wiphy); | 189 | net = wiphy_net(&rdev->wiphy); |
190 | 190 | ||
191 | list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, | 191 | list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, |
192 | list) { | 192 | list) { |
193 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 193 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
194 | err = dev_change_net_namespace(wdev->netdev, net, | 194 | err = dev_change_net_namespace(wdev->netdev, net, |
@@ -226,7 +226,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
226 | rtnl_lock(); | 226 | rtnl_lock(); |
227 | mutex_lock(&rdev->devlist_mtx); | 227 | mutex_lock(&rdev->devlist_mtx); |
228 | 228 | ||
229 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 229 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
230 | dev_close(wdev->netdev); | 230 | dev_close(wdev->netdev); |
231 | 231 | ||
232 | mutex_unlock(&rdev->devlist_mtx); | 232 | mutex_unlock(&rdev->devlist_mtx); |
@@ -304,7 +304,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
304 | mutex_init(&rdev->mtx); | 304 | mutex_init(&rdev->mtx); |
305 | mutex_init(&rdev->devlist_mtx); | 305 | mutex_init(&rdev->devlist_mtx); |
306 | mutex_init(&rdev->sched_scan_mtx); | 306 | mutex_init(&rdev->sched_scan_mtx); |
307 | INIT_LIST_HEAD(&rdev->netdev_list); | 307 | INIT_LIST_HEAD(&rdev->wdev_list); |
308 | spin_lock_init(&rdev->bss_lock); | 308 | spin_lock_init(&rdev->bss_lock); |
309 | INIT_LIST_HEAD(&rdev->bss_list); | 309 | INIT_LIST_HEAD(&rdev->bss_list); |
310 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 310 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
@@ -622,7 +622,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
622 | __count == 0; })); | 622 | __count == 0; })); |
623 | 623 | ||
624 | mutex_lock(&rdev->devlist_mtx); | 624 | mutex_lock(&rdev->devlist_mtx); |
625 | BUG_ON(!list_empty(&rdev->netdev_list)); | 625 | BUG_ON(!list_empty(&rdev->wdev_list)); |
626 | mutex_unlock(&rdev->devlist_mtx); | 626 | mutex_unlock(&rdev->devlist_mtx); |
627 | 627 | ||
628 | /* | 628 | /* |
@@ -821,7 +821,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
821 | spin_lock_init(&wdev->mgmt_registrations_lock); | 821 | spin_lock_init(&wdev->mgmt_registrations_lock); |
822 | 822 | ||
823 | mutex_lock(&rdev->devlist_mtx); | 823 | mutex_lock(&rdev->devlist_mtx); |
824 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 824 | wdev->identifier = ++rdev->wdev_id; |
825 | list_add_rcu(&wdev->list, &rdev->wdev_list); | ||
825 | rdev->devlist_generation++; | 826 | rdev->devlist_generation++; |
826 | /* can only change netns with wiphy */ | 827 | /* can only change netns with wiphy */ |
827 | dev->features |= NETIF_F_NETNS_LOCAL; | 828 | dev->features |= NETIF_F_NETNS_LOCAL; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 377dc394f48..6b0170a5f05 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -47,11 +47,11 @@ struct cfg80211_registered_device { | |||
47 | /* wiphy index, internal only */ | 47 | /* wiphy index, internal only */ |
48 | int wiphy_idx; | 48 | int wiphy_idx; |
49 | 49 | ||
50 | /* associate netdev list */ | 50 | /* associated wireless interfaces */ |
51 | struct mutex devlist_mtx; | 51 | struct mutex devlist_mtx; |
52 | /* protected by devlist_mtx or RCU */ | 52 | /* protected by devlist_mtx or RCU */ |
53 | struct list_head netdev_list; | 53 | struct list_head wdev_list; |
54 | int devlist_generation; | 54 | int devlist_generation, wdev_id; |
55 | int opencount; /* also protected by devlist_mtx */ | 55 | int opencount; /* also protected by devlist_mtx */ |
56 | wait_queue_head_t dev_wait; | 56 | wait_queue_head_t dev_wait; |
57 | 57 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2a5cdb60bc6..35a9b15289f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = { | |||
46 | .post_doit = nl80211_post_doit, | 46 | .post_doit = nl80211_post_doit, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* internal helper: get rdev and dev */ | 49 | /* returns ERR_PTR values */ |
50 | static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, | 50 | static struct wireless_dev * |
51 | struct cfg80211_registered_device **rdev, | 51 | __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) |
52 | struct net_device **dev) | ||
53 | { | 52 | { |
54 | int ifindex; | 53 | struct cfg80211_registered_device *rdev; |
54 | struct wireless_dev *result = NULL; | ||
55 | bool have_ifidx = attrs[NL80211_ATTR_IFINDEX]; | ||
56 | bool have_wdev_id = attrs[NL80211_ATTR_WDEV]; | ||
57 | u64 wdev_id; | ||
58 | int wiphy_idx = -1; | ||
59 | int ifidx = -1; | ||
55 | 60 | ||
56 | if (!attrs[NL80211_ATTR_IFINDEX]) | 61 | assert_cfg80211_lock(); |
57 | return -EINVAL; | ||
58 | 62 | ||
59 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 63 | if (!have_ifidx && !have_wdev_id) |
60 | *dev = dev_get_by_index(netns, ifindex); | 64 | return ERR_PTR(-EINVAL); |
61 | if (!*dev) | ||
62 | return -ENODEV; | ||
63 | 65 | ||
64 | *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); | 66 | if (have_ifidx) |
65 | if (IS_ERR(*rdev)) { | 67 | ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
66 | dev_put(*dev); | 68 | if (have_wdev_id) { |
67 | return PTR_ERR(*rdev); | 69 | wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); |
70 | wiphy_idx = wdev_id >> 32; | ||
68 | } | 71 | } |
69 | 72 | ||
70 | return 0; | 73 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
74 | struct wireless_dev *wdev; | ||
75 | |||
76 | if (wiphy_net(&rdev->wiphy) != netns) | ||
77 | continue; | ||
78 | |||
79 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) | ||
80 | continue; | ||
81 | |||
82 | mutex_lock(&rdev->devlist_mtx); | ||
83 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
84 | if (have_ifidx && wdev->netdev && | ||
85 | wdev->netdev->ifindex == ifidx) { | ||
86 | result = wdev; | ||
87 | break; | ||
88 | } | ||
89 | if (have_wdev_id && wdev->identifier == (u32)wdev_id) { | ||
90 | result = wdev; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | mutex_unlock(&rdev->devlist_mtx); | ||
95 | |||
96 | if (result) | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | if (result) | ||
101 | return result; | ||
102 | return ERR_PTR(-ENODEV); | ||
71 | } | 103 | } |
72 | 104 | ||
73 | static struct cfg80211_registered_device * | 105 | static struct cfg80211_registered_device * |
@@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
79 | assert_cfg80211_lock(); | 111 | assert_cfg80211_lock(); |
80 | 112 | ||
81 | if (!attrs[NL80211_ATTR_WIPHY] && | 113 | if (!attrs[NL80211_ATTR_WIPHY] && |
82 | !attrs[NL80211_ATTR_IFINDEX]) | 114 | !attrs[NL80211_ATTR_IFINDEX] && |
115 | !attrs[NL80211_ATTR_WDEV]) | ||
83 | return ERR_PTR(-EINVAL); | 116 | return ERR_PTR(-EINVAL); |
84 | 117 | ||
85 | if (attrs[NL80211_ATTR_WIPHY]) | 118 | if (attrs[NL80211_ATTR_WIPHY]) |
86 | rdev = cfg80211_rdev_by_wiphy_idx( | 119 | rdev = cfg80211_rdev_by_wiphy_idx( |
87 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); | 120 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); |
88 | 121 | ||
122 | if (attrs[NL80211_ATTR_WDEV]) { | ||
123 | u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); | ||
124 | struct wireless_dev *wdev; | ||
125 | bool found = false; | ||
126 | |||
127 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); | ||
128 | if (tmp) { | ||
129 | /* make sure wdev exists */ | ||
130 | mutex_lock(&tmp->devlist_mtx); | ||
131 | list_for_each_entry(wdev, &tmp->wdev_list, list) { | ||
132 | if (wdev->identifier != (u32)wdev_id) | ||
133 | continue; | ||
134 | found = true; | ||
135 | break; | ||
136 | } | ||
137 | mutex_unlock(&tmp->devlist_mtx); | ||
138 | |||
139 | if (!found) | ||
140 | tmp = NULL; | ||
141 | |||
142 | if (rdev && tmp != rdev) | ||
143 | return ERR_PTR(-EINVAL); | ||
144 | rdev = tmp; | ||
145 | } | ||
146 | } | ||
147 | |||
89 | if (attrs[NL80211_ATTR_IFINDEX]) { | 148 | if (attrs[NL80211_ATTR_IFINDEX]) { |
90 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 149 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
91 | netdev = dev_get_by_index(netns, ifindex); | 150 | netdev = dev_get_by_index(netns, ifindex); |
@@ -294,6 +353,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
294 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, | 353 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, |
295 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, | 354 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, |
296 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, | 355 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, |
356 | [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, | ||
297 | }; | 357 | }; |
298 | 358 | ||
299 | /* policy for the key attributes */ | 359 | /* policy for the key attributes */ |
@@ -1674,6 +1734,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1674 | struct net_device *dev) | 1734 | struct net_device *dev) |
1675 | { | 1735 | { |
1676 | void *hdr; | 1736 | void *hdr; |
1737 | u64 wdev_id = (u64)dev->ieee80211_ptr->identifier | | ||
1738 | ((u64)rdev->wiphy_idx << 32); | ||
1677 | 1739 | ||
1678 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 1740 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
1679 | if (!hdr) | 1741 | if (!hdr) |
@@ -1684,6 +1746,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1684 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || | 1746 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || |
1685 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, | 1747 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, |
1686 | dev->ieee80211_ptr->iftype) || | 1748 | dev->ieee80211_ptr->iftype) || |
1749 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id) || | ||
1687 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 1750 | nla_put_u32(msg, NL80211_ATTR_GENERATION, |
1688 | rdev->devlist_generation ^ | 1751 | rdev->devlist_generation ^ |
1689 | (cfg80211_rdev_list_generation << 2))) | 1752 | (cfg80211_rdev_list_generation << 2))) |
@@ -1724,7 +1787,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1724 | if_idx = 0; | 1787 | if_idx = 0; |
1725 | 1788 | ||
1726 | mutex_lock(&rdev->devlist_mtx); | 1789 | mutex_lock(&rdev->devlist_mtx); |
1727 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 1790 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1728 | if (if_idx < if_start) { | 1791 | if (if_idx < if_start) { |
1729 | if_idx++; | 1792 | if_idx++; |
1730 | continue; | 1793 | continue; |
@@ -2350,7 +2413,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
2350 | 2413 | ||
2351 | mutex_lock(&rdev->devlist_mtx); | 2414 | mutex_lock(&rdev->devlist_mtx); |
2352 | 2415 | ||
2353 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 2416 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2354 | if (wdev->iftype != NL80211_IFTYPE_AP && | 2417 | if (wdev->iftype != NL80211_IFTYPE_AP && |
2355 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 2418 | wdev->iftype != NL80211_IFTYPE_P2P_GO) |
2356 | continue; | 2419 | continue; |
@@ -6660,8 +6723,8 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6660 | struct genl_info *info) | 6723 | struct genl_info *info) |
6661 | { | 6724 | { |
6662 | struct cfg80211_registered_device *rdev; | 6725 | struct cfg80211_registered_device *rdev; |
6726 | struct wireless_dev *wdev; | ||
6663 | struct net_device *dev; | 6727 | struct net_device *dev; |
6664 | int err; | ||
6665 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | 6728 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; |
6666 | 6729 | ||
6667 | if (rtnl) | 6730 | if (rtnl) |
@@ -6676,21 +6739,39 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6676 | } | 6739 | } |
6677 | info->user_ptr[0] = rdev; | 6740 | info->user_ptr[0] = rdev; |
6678 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 6741 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
6679 | err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, | 6742 | mutex_lock(&cfg80211_mutex); |
6680 | &rdev, &dev); | 6743 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
6681 | if (err) { | 6744 | info->attrs); |
6745 | if (IS_ERR(wdev)) { | ||
6746 | mutex_unlock(&cfg80211_mutex); | ||
6682 | if (rtnl) | 6747 | if (rtnl) |
6683 | rtnl_unlock(); | 6748 | rtnl_unlock(); |
6684 | return err; | 6749 | return PTR_ERR(wdev); |
6685 | } | 6750 | } |
6751 | |||
6752 | if (!wdev->netdev) { | ||
6753 | mutex_unlock(&cfg80211_mutex); | ||
6754 | if (rtnl) | ||
6755 | rtnl_unlock(); | ||
6756 | return -EINVAL; | ||
6757 | } | ||
6758 | |||
6759 | dev = wdev->netdev; | ||
6760 | rdev = wiphy_to_dev(wdev->wiphy); | ||
6761 | |||
6686 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 6762 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && |
6687 | !netif_running(dev)) { | 6763 | !netif_running(dev)) { |
6688 | cfg80211_unlock_rdev(rdev); | 6764 | mutex_unlock(&cfg80211_mutex); |
6689 | dev_put(dev); | ||
6690 | if (rtnl) | 6765 | if (rtnl) |
6691 | rtnl_unlock(); | 6766 | rtnl_unlock(); |
6692 | return -ENETDOWN; | 6767 | return -ENETDOWN; |
6693 | } | 6768 | } |
6769 | |||
6770 | dev_hold(dev); | ||
6771 | cfg80211_lock_rdev(rdev); | ||
6772 | |||
6773 | mutex_unlock(&cfg80211_mutex); | ||
6774 | |||
6694 | info->user_ptr[0] = rdev; | 6775 | info->user_ptr[0] = rdev; |
6695 | info->user_ptr[1] = dev; | 6776 | info->user_ptr[1] = dev; |
6696 | } | 6777 | } |
@@ -8483,7 +8564,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8483 | rcu_read_lock(); | 8564 | rcu_read_lock(); |
8484 | 8565 | ||
8485 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 8566 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8486 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 8567 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8487 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 8568 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
8488 | if (rdev->ap_beacons_nlpid == notify->pid) | 8569 | if (rdev->ap_beacons_nlpid == notify->pid) |
8489 | rdev->ap_beacons_nlpid = 0; | 8570 | rdev->ap_beacons_nlpid = 0; |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f7e937ff897..dec97981e68 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void) | |||
51 | */ | 51 | */ |
52 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 52 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
53 | cfg80211_lock_rdev(rdev); | 53 | cfg80211_lock_rdev(rdev); |
54 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 54 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
55 | wdev_lock(wdev); | 55 | wdev_lock(wdev); |
56 | if (wdev->sme_state != CFG80211_SME_IDLE) | 56 | if (wdev->sme_state != CFG80211_SME_IDLE) |
57 | is_all_idle = false; | 57 | is_all_idle = false; |
@@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
221 | cfg80211_lock_rdev(rdev); | 221 | cfg80211_lock_rdev(rdev); |
222 | mutex_lock(&rdev->devlist_mtx); | 222 | mutex_lock(&rdev->devlist_mtx); |
223 | 223 | ||
224 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 224 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
225 | wdev_lock(wdev); | 225 | wdev_lock(wdev); |
226 | if (!netif_running(wdev->netdev)) { | 226 | if (!netif_running(wdev->netdev)) { |
227 | wdev_unlock(wdev); | 227 | wdev_unlock(wdev); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index e31f1dba79e..f7a0647bde9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -793,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | |||
793 | 793 | ||
794 | mutex_lock(&rdev->devlist_mtx); | 794 | mutex_lock(&rdev->devlist_mtx); |
795 | 795 | ||
796 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 796 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
797 | cfg80211_process_wdev_events(wdev); | 797 | cfg80211_process_wdev_events(wdev); |
798 | 798 | ||
799 | mutex_unlock(&rdev->devlist_mtx); | 799 | mutex_unlock(&rdev->devlist_mtx); |
@@ -994,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
994 | 994 | ||
995 | mutex_lock(&rdev->devlist_mtx); | 995 | mutex_lock(&rdev->devlist_mtx); |
996 | 996 | ||
997 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 997 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
998 | if (!wdev->beacon_interval) | 998 | if (!wdev->beacon_interval) |
999 | continue; | 999 | continue; |
1000 | if (wdev->beacon_interval != beacon_int) { | 1000 | if (wdev->beacon_interval != beacon_int) { |
@@ -1050,7 +1050,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1050 | break; | 1050 | break; |
1051 | } | 1051 | } |
1052 | 1052 | ||
1053 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1053 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { |
1054 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
1055 | continue; | 1055 | continue; |
1056 | if (!netif_running(wdev_iter->netdev)) | 1056 | if (!netif_running(wdev_iter->netdev)) |