diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 178 |
1 files changed, 36 insertions, 142 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5bcf3a5b6465..74cdb1a0cf31 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -59,7 +59,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
59 | int wiphy_idx = -1; | 59 | int wiphy_idx = -1; |
60 | int ifidx = -1; | 60 | int ifidx = -1; |
61 | 61 | ||
62 | assert_cfg80211_lock(); | 62 | ASSERT_RTNL(); |
63 | 63 | ||
64 | if (!have_ifidx && !have_wdev_id) | 64 | if (!have_ifidx && !have_wdev_id) |
65 | return ERR_PTR(-EINVAL); | 65 | return ERR_PTR(-EINVAL); |
@@ -80,7 +80,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
80 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) | 80 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) |
81 | continue; | 81 | continue; |
82 | 82 | ||
83 | mutex_lock(&rdev->devlist_mtx); | ||
84 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 83 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
85 | if (have_ifidx && wdev->netdev && | 84 | if (have_ifidx && wdev->netdev && |
86 | wdev->netdev->ifindex == ifidx) { | 85 | wdev->netdev->ifindex == ifidx) { |
@@ -92,7 +91,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
92 | break; | 91 | break; |
93 | } | 92 | } |
94 | } | 93 | } |
95 | mutex_unlock(&rdev->devlist_mtx); | ||
96 | 94 | ||
97 | if (result) | 95 | if (result) |
98 | break; | 96 | break; |
@@ -109,7 +107,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
109 | struct cfg80211_registered_device *rdev = NULL, *tmp; | 107 | struct cfg80211_registered_device *rdev = NULL, *tmp; |
110 | struct net_device *netdev; | 108 | struct net_device *netdev; |
111 | 109 | ||
112 | assert_cfg80211_lock(); | 110 | ASSERT_RTNL(); |
113 | 111 | ||
114 | if (!attrs[NL80211_ATTR_WIPHY] && | 112 | if (!attrs[NL80211_ATTR_WIPHY] && |
115 | !attrs[NL80211_ATTR_IFINDEX] && | 113 | !attrs[NL80211_ATTR_IFINDEX] && |
@@ -128,14 +126,12 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
128 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); | 126 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); |
129 | if (tmp) { | 127 | if (tmp) { |
130 | /* make sure wdev exists */ | 128 | /* make sure wdev exists */ |
131 | mutex_lock(&tmp->devlist_mtx); | ||
132 | list_for_each_entry(wdev, &tmp->wdev_list, list) { | 129 | list_for_each_entry(wdev, &tmp->wdev_list, list) { |
133 | if (wdev->identifier != (u32)wdev_id) | 130 | if (wdev->identifier != (u32)wdev_id) |
134 | continue; | 131 | continue; |
135 | found = true; | 132 | found = true; |
136 | break; | 133 | break; |
137 | } | 134 | } |
138 | mutex_unlock(&tmp->devlist_mtx); | ||
139 | 135 | ||
140 | if (!found) | 136 | if (!found) |
141 | tmp = NULL; | 137 | tmp = NULL; |
@@ -182,19 +178,6 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
182 | /* | 178 | /* |
183 | * This function returns a pointer to the driver | 179 | * This function returns a pointer to the driver |
184 | * that the genl_info item that is passed refers to. | 180 | * that the genl_info item that is passed refers to. |
185 | * If successful, it returns non-NULL and also locks | ||
186 | * the driver's mutex! | ||
187 | * | ||
188 | * This means that you need to call cfg80211_unlock_rdev() | ||
189 | * before being allowed to acquire &cfg80211_mutex! | ||
190 | * | ||
191 | * This is necessary because we need to lock the global | ||
192 | * mutex to get an item off the list safely, and then | ||
193 | * we lock the rdev mutex so it doesn't go away under us. | ||
194 | * | ||
195 | * We don't want to keep cfg80211_mutex locked | ||
196 | * for all the time in order to allow requests on | ||
197 | * other interfaces to go through at the same time. | ||
198 | * | 181 | * |
199 | * The result of this can be a PTR_ERR and hence must | 182 | * The result of this can be a PTR_ERR and hence must |
200 | * be checked with IS_ERR() for errors. | 183 | * be checked with IS_ERR() for errors. |
@@ -202,20 +185,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
202 | static struct cfg80211_registered_device * | 185 | static struct cfg80211_registered_device * |
203 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | 186 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) |
204 | { | 187 | { |
205 | struct cfg80211_registered_device *rdev; | 188 | return __cfg80211_rdev_from_attrs(netns, info->attrs); |
206 | |||
207 | mutex_lock(&cfg80211_mutex); | ||
208 | rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); | ||
209 | |||
210 | /* if it is not an error we grab the lock on | ||
211 | * it to assure it won't be going away while | ||
212 | * we operate on it */ | ||
213 | if (!IS_ERR(rdev)) | ||
214 | mutex_lock(&rdev->mtx); | ||
215 | |||
216 | mutex_unlock(&cfg80211_mutex); | ||
217 | |||
218 | return rdev; | ||
219 | } | 189 | } |
220 | 190 | ||
221 | /* policy for the attributes */ | 191 | /* policy for the attributes */ |
@@ -456,7 +426,6 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
456 | int err; | 426 | int err; |
457 | 427 | ||
458 | rtnl_lock(); | 428 | rtnl_lock(); |
459 | mutex_lock(&cfg80211_mutex); | ||
460 | 429 | ||
461 | if (!cb->args[0]) { | 430 | if (!cb->args[0]) { |
462 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 431 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
@@ -485,14 +454,12 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
485 | *rdev = wiphy_to_dev(wiphy); | 454 | *rdev = wiphy_to_dev(wiphy); |
486 | *wdev = NULL; | 455 | *wdev = NULL; |
487 | 456 | ||
488 | mutex_lock(&(*rdev)->devlist_mtx); | ||
489 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { | 457 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { |
490 | if (tmp->identifier == cb->args[1]) { | 458 | if (tmp->identifier == cb->args[1]) { |
491 | *wdev = tmp; | 459 | *wdev = tmp; |
492 | break; | 460 | break; |
493 | } | 461 | } |
494 | } | 462 | } |
495 | mutex_unlock(&(*rdev)->devlist_mtx); | ||
496 | 463 | ||
497 | if (!*wdev) { | 464 | if (!*wdev) { |
498 | err = -ENODEV; | 465 | err = -ENODEV; |
@@ -500,19 +467,14 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
500 | } | 467 | } |
501 | } | 468 | } |
502 | 469 | ||
503 | cfg80211_lock_rdev(*rdev); | ||
504 | |||
505 | mutex_unlock(&cfg80211_mutex); | ||
506 | return 0; | 470 | return 0; |
507 | out_unlock: | 471 | out_unlock: |
508 | mutex_unlock(&cfg80211_mutex); | ||
509 | rtnl_unlock(); | 472 | rtnl_unlock(); |
510 | return err; | 473 | return err; |
511 | } | 474 | } |
512 | 475 | ||
513 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) | 476 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) |
514 | { | 477 | { |
515 | cfg80211_unlock_rdev(rdev); | ||
516 | rtnl_unlock(); | 478 | rtnl_unlock(); |
517 | } | 479 | } |
518 | 480 | ||
@@ -1568,7 +1530,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1568 | struct nlattr **tb = nl80211_fam.attrbuf; | 1530 | struct nlattr **tb = nl80211_fam.attrbuf; |
1569 | int res; | 1531 | int res; |
1570 | 1532 | ||
1571 | mutex_lock(&cfg80211_mutex); | 1533 | rtnl_lock(); |
1572 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1534 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
1573 | tb, nl80211_fam.maxattr, nl80211_policy); | 1535 | tb, nl80211_fam.maxattr, nl80211_policy); |
1574 | if (res == 0) { | 1536 | if (res == 0) { |
@@ -1582,10 +1544,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1582 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | 1544 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); |
1583 | 1545 | ||
1584 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | 1546 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); |
1585 | if (!netdev) { | 1547 | if (!netdev) |
1586 | mutex_unlock(&cfg80211_mutex); | ||
1587 | return -ENODEV; | 1548 | return -ENODEV; |
1588 | } | ||
1589 | if (netdev->ieee80211_ptr) { | 1549 | if (netdev->ieee80211_ptr) { |
1590 | dev = wiphy_to_dev( | 1550 | dev = wiphy_to_dev( |
1591 | netdev->ieee80211_ptr->wiphy); | 1551 | netdev->ieee80211_ptr->wiphy); |
@@ -1629,7 +1589,6 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1629 | !skb->len && | 1589 | !skb->len && |
1630 | cb->min_dump_alloc < 4096) { | 1590 | cb->min_dump_alloc < 4096) { |
1631 | cb->min_dump_alloc = 4096; | 1591 | cb->min_dump_alloc = 4096; |
1632 | mutex_unlock(&cfg80211_mutex); | ||
1633 | return 1; | 1592 | return 1; |
1634 | } | 1593 | } |
1635 | idx--; | 1594 | idx--; |
@@ -1638,7 +1597,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1638 | } while (cb->args[1] > 0); | 1597 | } while (cb->args[1] > 0); |
1639 | break; | 1598 | break; |
1640 | } | 1599 | } |
1641 | mutex_unlock(&cfg80211_mutex); | 1600 | rtnl_unlock(); |
1642 | 1601 | ||
1643 | cb->args[0] = idx; | 1602 | cb->args[0] = idx; |
1644 | 1603 | ||
@@ -1793,7 +1752,6 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1793 | if (result) | 1752 | if (result) |
1794 | return result; | 1753 | return result; |
1795 | 1754 | ||
1796 | mutex_lock(&rdev->devlist_mtx); | ||
1797 | switch (iftype) { | 1755 | switch (iftype) { |
1798 | case NL80211_IFTYPE_AP: | 1756 | case NL80211_IFTYPE_AP: |
1799 | case NL80211_IFTYPE_P2P_GO: | 1757 | case NL80211_IFTYPE_P2P_GO: |
@@ -1817,7 +1775,6 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1817 | default: | 1775 | default: |
1818 | result = -EINVAL; | 1776 | result = -EINVAL; |
1819 | } | 1777 | } |
1820 | mutex_unlock(&rdev->devlist_mtx); | ||
1821 | 1778 | ||
1822 | return result; | 1779 | return result; |
1823 | } | 1780 | } |
@@ -1866,6 +1823,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1866 | u32 frag_threshold = 0, rts_threshold = 0; | 1823 | u32 frag_threshold = 0, rts_threshold = 0; |
1867 | u8 coverage_class = 0; | 1824 | u8 coverage_class = 0; |
1868 | 1825 | ||
1826 | ASSERT_RTNL(); | ||
1827 | |||
1869 | /* | 1828 | /* |
1870 | * Try to find the wiphy and netdev. Normally this | 1829 | * Try to find the wiphy and netdev. Normally this |
1871 | * function shouldn't need the netdev, but this is | 1830 | * function shouldn't need the netdev, but this is |
@@ -1875,31 +1834,25 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1875 | * also passed a netdev to set_wiphy, so that it is | 1834 | * also passed a netdev to set_wiphy, so that it is |
1876 | * possible to let that go to the right netdev! | 1835 | * possible to let that go to the right netdev! |
1877 | */ | 1836 | */ |
1878 | mutex_lock(&cfg80211_mutex); | ||
1879 | 1837 | ||
1880 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | 1838 | if (info->attrs[NL80211_ATTR_IFINDEX]) { |
1881 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | 1839 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); |
1882 | 1840 | ||
1883 | netdev = dev_get_by_index(genl_info_net(info), ifindex); | 1841 | netdev = dev_get_by_index(genl_info_net(info), ifindex); |
1884 | if (netdev && netdev->ieee80211_ptr) { | 1842 | if (netdev && netdev->ieee80211_ptr) |
1885 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); | 1843 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); |
1886 | mutex_lock(&rdev->mtx); | 1844 | else |
1887 | } else | ||
1888 | netdev = NULL; | 1845 | netdev = NULL; |
1889 | } | 1846 | } |
1890 | 1847 | ||
1891 | if (!netdev) { | 1848 | if (!netdev) { |
1892 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), | 1849 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), |
1893 | info->attrs); | 1850 | info->attrs); |
1894 | if (IS_ERR(rdev)) { | 1851 | if (IS_ERR(rdev)) |
1895 | mutex_unlock(&cfg80211_mutex); | ||
1896 | return PTR_ERR(rdev); | 1852 | return PTR_ERR(rdev); |
1897 | } | ||
1898 | wdev = NULL; | 1853 | wdev = NULL; |
1899 | netdev = NULL; | 1854 | netdev = NULL; |
1900 | result = 0; | 1855 | result = 0; |
1901 | |||
1902 | mutex_lock(&rdev->mtx); | ||
1903 | } else | 1856 | } else |
1904 | wdev = netdev->ieee80211_ptr; | 1857 | wdev = netdev->ieee80211_ptr; |
1905 | 1858 | ||
@@ -1912,8 +1865,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1912 | result = cfg80211_dev_rename( | 1865 | result = cfg80211_dev_rename( |
1913 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 1866 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
1914 | 1867 | ||
1915 | mutex_unlock(&cfg80211_mutex); | ||
1916 | |||
1917 | if (result) | 1868 | if (result) |
1918 | goto bad_res; | 1869 | goto bad_res; |
1919 | 1870 | ||
@@ -2120,7 +2071,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2120 | } | 2071 | } |
2121 | 2072 | ||
2122 | bad_res: | 2073 | bad_res: |
2123 | mutex_unlock(&rdev->mtx); | ||
2124 | if (netdev) | 2074 | if (netdev) |
2125 | dev_put(netdev); | 2075 | dev_put(netdev); |
2126 | return result; | 2076 | return result; |
@@ -2218,7 +2168,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2218 | struct cfg80211_registered_device *rdev; | 2168 | struct cfg80211_registered_device *rdev; |
2219 | struct wireless_dev *wdev; | 2169 | struct wireless_dev *wdev; |
2220 | 2170 | ||
2221 | mutex_lock(&cfg80211_mutex); | 2171 | rtnl_lock(); |
2222 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2172 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
2223 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) | 2173 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
2224 | continue; | 2174 | continue; |
@@ -2228,7 +2178,6 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2228 | } | 2178 | } |
2229 | if_idx = 0; | 2179 | if_idx = 0; |
2230 | 2180 | ||
2231 | mutex_lock(&rdev->devlist_mtx); | ||
2232 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 2181 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2233 | if (if_idx < if_start) { | 2182 | if (if_idx < if_start) { |
2234 | if_idx++; | 2183 | if_idx++; |
@@ -2237,17 +2186,15 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2237 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, | 2186 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, |
2238 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 2187 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2239 | rdev, wdev) < 0) { | 2188 | rdev, wdev) < 0) { |
2240 | mutex_unlock(&rdev->devlist_mtx); | ||
2241 | goto out; | 2189 | goto out; |
2242 | } | 2190 | } |
2243 | if_idx++; | 2191 | if_idx++; |
2244 | } | 2192 | } |
2245 | mutex_unlock(&rdev->devlist_mtx); | ||
2246 | 2193 | ||
2247 | wp_idx++; | 2194 | wp_idx++; |
2248 | } | 2195 | } |
2249 | out: | 2196 | out: |
2250 | mutex_unlock(&cfg80211_mutex); | 2197 | rtnl_unlock(); |
2251 | 2198 | ||
2252 | cb->args[0] = wp_idx; | 2199 | cb->args[0] = wp_idx; |
2253 | cb->args[1] = if_idx; | 2200 | cb->args[1] = if_idx; |
@@ -2480,11 +2427,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2480 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 2427 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
2481 | spin_lock_init(&wdev->mgmt_registrations_lock); | 2428 | spin_lock_init(&wdev->mgmt_registrations_lock); |
2482 | 2429 | ||
2483 | mutex_lock(&rdev->devlist_mtx); | ||
2484 | wdev->identifier = ++rdev->wdev_id; | 2430 | wdev->identifier = ++rdev->wdev_id; |
2485 | list_add_rcu(&wdev->list, &rdev->wdev_list); | 2431 | list_add_rcu(&wdev->list, &rdev->wdev_list); |
2486 | rdev->devlist_generation++; | 2432 | rdev->devlist_generation++; |
2487 | mutex_unlock(&rdev->devlist_mtx); | ||
2488 | break; | 2433 | break; |
2489 | default: | 2434 | default: |
2490 | break; | 2435 | break; |
@@ -2993,8 +2938,6 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
2993 | struct wireless_dev *wdev; | 2938 | struct wireless_dev *wdev; |
2994 | bool ret = false; | 2939 | bool ret = false; |
2995 | 2940 | ||
2996 | mutex_lock(&rdev->devlist_mtx); | ||
2997 | |||
2998 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 2941 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2999 | if (wdev->iftype != NL80211_IFTYPE_AP && | 2942 | if (wdev->iftype != NL80211_IFTYPE_AP && |
3000 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 2943 | wdev->iftype != NL80211_IFTYPE_P2P_GO) |
@@ -3008,8 +2951,6 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
3008 | break; | 2951 | break; |
3009 | } | 2952 | } |
3010 | 2953 | ||
3011 | mutex_unlock(&rdev->devlist_mtx); | ||
3012 | |||
3013 | return ret; | 2954 | return ret; |
3014 | } | 2955 | } |
3015 | 2956 | ||
@@ -3171,13 +3112,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3171 | params.radar_required = true; | 3112 | params.radar_required = true; |
3172 | } | 3113 | } |
3173 | 3114 | ||
3174 | mutex_lock(&rdev->devlist_mtx); | ||
3175 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 3115 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
3176 | params.chandef.chan, | 3116 | params.chandef.chan, |
3177 | CHAN_MODE_SHARED, | 3117 | CHAN_MODE_SHARED, |
3178 | radar_detect_width); | 3118 | radar_detect_width); |
3179 | mutex_unlock(&rdev->devlist_mtx); | ||
3180 | |||
3181 | if (err) | 3119 | if (err) |
3182 | return err; | 3120 | return err; |
3183 | 3121 | ||
@@ -4914,18 +4852,13 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
4914 | void *hdr = NULL; | 4852 | void *hdr = NULL; |
4915 | struct nlattr *nl_reg_rules; | 4853 | struct nlattr *nl_reg_rules; |
4916 | unsigned int i; | 4854 | unsigned int i; |
4917 | int err = -EINVAL; | ||
4918 | |||
4919 | mutex_lock(&cfg80211_mutex); | ||
4920 | 4855 | ||
4921 | if (!cfg80211_regdomain) | 4856 | if (!cfg80211_regdomain) |
4922 | goto out; | 4857 | return -EINVAL; |
4923 | 4858 | ||
4924 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4859 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4925 | if (!msg) { | 4860 | if (!msg) |
4926 | err = -ENOBUFS; | 4861 | return -ENOBUFS; |
4927 | goto out; | ||
4928 | } | ||
4929 | 4862 | ||
4930 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | 4863 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, |
4931 | NL80211_CMD_GET_REG); | 4864 | NL80211_CMD_GET_REG); |
@@ -4984,8 +4917,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
4984 | nla_nest_end(msg, nl_reg_rules); | 4917 | nla_nest_end(msg, nl_reg_rules); |
4985 | 4918 | ||
4986 | genlmsg_end(msg, hdr); | 4919 | genlmsg_end(msg, hdr); |
4987 | err = genlmsg_reply(msg, info); | 4920 | return genlmsg_reply(msg, info); |
4988 | goto out; | ||
4989 | 4921 | ||
4990 | nla_put_failure_rcu: | 4922 | nla_put_failure_rcu: |
4991 | rcu_read_unlock(); | 4923 | rcu_read_unlock(); |
@@ -4993,10 +4925,7 @@ nla_put_failure: | |||
4993 | genlmsg_cancel(msg, hdr); | 4925 | genlmsg_cancel(msg, hdr); |
4994 | put_failure: | 4926 | put_failure: |
4995 | nlmsg_free(msg); | 4927 | nlmsg_free(msg); |
4996 | err = -EMSGSIZE; | 4928 | return -EMSGSIZE; |
4997 | out: | ||
4998 | mutex_unlock(&cfg80211_mutex); | ||
4999 | return err; | ||
5000 | } | 4929 | } |
5001 | 4930 | ||
5002 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 4931 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
@@ -5062,12 +4991,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5062 | } | 4991 | } |
5063 | } | 4992 | } |
5064 | 4993 | ||
5065 | mutex_lock(&cfg80211_mutex); | ||
5066 | |||
5067 | r = set_regdom(rd); | 4994 | r = set_regdom(rd); |
5068 | /* set_regdom took ownership */ | 4995 | /* set_regdom took ownership */ |
5069 | rd = NULL; | 4996 | rd = NULL; |
5070 | mutex_unlock(&cfg80211_mutex); | ||
5071 | 4997 | ||
5072 | bad_reg: | 4998 | bad_reg: |
5073 | kfree(rd); | 4999 | kfree(rd); |
@@ -5117,7 +5043,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5117 | if (!rdev->ops->scan) | 5043 | if (!rdev->ops->scan) |
5118 | return -EOPNOTSUPP; | 5044 | return -EOPNOTSUPP; |
5119 | 5045 | ||
5120 | mutex_lock(&rdev->sched_scan_mtx); | ||
5121 | if (rdev->scan_req) { | 5046 | if (rdev->scan_req) { |
5122 | err = -EBUSY; | 5047 | err = -EBUSY; |
5123 | goto unlock; | 5048 | goto unlock; |
@@ -5303,7 +5228,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5303 | } | 5228 | } |
5304 | 5229 | ||
5305 | unlock: | 5230 | unlock: |
5306 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5307 | return err; | 5231 | return err; |
5308 | } | 5232 | } |
5309 | 5233 | ||
@@ -5375,8 +5299,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5375 | if (ie_len > wiphy->max_sched_scan_ie_len) | 5299 | if (ie_len > wiphy->max_sched_scan_ie_len) |
5376 | return -EINVAL; | 5300 | return -EINVAL; |
5377 | 5301 | ||
5378 | mutex_lock(&rdev->sched_scan_mtx); | ||
5379 | |||
5380 | if (rdev->sched_scan_req) { | 5302 | if (rdev->sched_scan_req) { |
5381 | err = -EINPROGRESS; | 5303 | err = -EINPROGRESS; |
5382 | goto out; | 5304 | goto out; |
@@ -5544,7 +5466,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5544 | out_free: | 5466 | out_free: |
5545 | kfree(request); | 5467 | kfree(request); |
5546 | out: | 5468 | out: |
5547 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5548 | return err; | 5469 | return err; |
5549 | } | 5470 | } |
5550 | 5471 | ||
@@ -5552,17 +5473,12 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
5552 | struct genl_info *info) | 5473 | struct genl_info *info) |
5553 | { | 5474 | { |
5554 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5475 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5555 | int err; | ||
5556 | 5476 | ||
5557 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5477 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
5558 | !rdev->ops->sched_scan_stop) | 5478 | !rdev->ops->sched_scan_stop) |
5559 | return -EOPNOTSUPP; | 5479 | return -EOPNOTSUPP; |
5560 | 5480 | ||
5561 | mutex_lock(&rdev->sched_scan_mtx); | 5481 | return __cfg80211_stop_sched_scan(rdev, false); |
5562 | err = __cfg80211_stop_sched_scan(rdev, false); | ||
5563 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5564 | |||
5565 | return err; | ||
5566 | } | 5482 | } |
5567 | 5483 | ||
5568 | static int nl80211_start_radar_detection(struct sk_buff *skb, | 5484 | static int nl80211_start_radar_detection(struct sk_buff *skb, |
@@ -5594,12 +5510,11 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5594 | if (!rdev->ops->start_radar_detection) | 5510 | if (!rdev->ops->start_radar_detection) |
5595 | return -EOPNOTSUPP; | 5511 | return -EOPNOTSUPP; |
5596 | 5512 | ||
5597 | mutex_lock(&rdev->devlist_mtx); | ||
5598 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 5513 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
5599 | chandef.chan, CHAN_MODE_SHARED, | 5514 | chandef.chan, CHAN_MODE_SHARED, |
5600 | BIT(chandef.width)); | 5515 | BIT(chandef.width)); |
5601 | if (err) | 5516 | if (err) |
5602 | goto err_locked; | 5517 | return err; |
5603 | 5518 | ||
5604 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | 5519 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); |
5605 | if (!err) { | 5520 | if (!err) { |
@@ -5607,9 +5522,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5607 | wdev->cac_started = true; | 5522 | wdev->cac_started = true; |
5608 | wdev->cac_start_time = jiffies; | 5523 | wdev->cac_start_time = jiffies; |
5609 | } | 5524 | } |
5610 | err_locked: | ||
5611 | mutex_unlock(&rdev->devlist_mtx); | ||
5612 | |||
5613 | return err; | 5525 | return err; |
5614 | } | 5526 | } |
5615 | 5527 | ||
@@ -6472,6 +6384,8 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6472 | void *data = NULL; | 6384 | void *data = NULL; |
6473 | int data_len = 0; | 6385 | int data_len = 0; |
6474 | 6386 | ||
6387 | rtnl_lock(); | ||
6388 | |||
6475 | if (cb->args[0]) { | 6389 | if (cb->args[0]) { |
6476 | /* | 6390 | /* |
6477 | * 0 is a valid index, but not valid for args[0], | 6391 | * 0 is a valid index, but not valid for args[0], |
@@ -6483,18 +6397,16 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6483 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 6397 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
6484 | nl80211_policy); | 6398 | nl80211_policy); |
6485 | if (err) | 6399 | if (err) |
6486 | return err; | 6400 | goto out_err; |
6487 | 6401 | ||
6488 | mutex_lock(&cfg80211_mutex); | ||
6489 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), | 6402 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), |
6490 | nl80211_fam.attrbuf); | 6403 | nl80211_fam.attrbuf); |
6491 | if (IS_ERR(rdev)) { | 6404 | if (IS_ERR(rdev)) { |
6492 | mutex_unlock(&cfg80211_mutex); | 6405 | err = PTR_ERR(rdev); |
6493 | return PTR_ERR(rdev); | 6406 | goto out_err; |
6494 | } | 6407 | } |
6495 | phy_idx = rdev->wiphy_idx; | 6408 | phy_idx = rdev->wiphy_idx; |
6496 | rdev = NULL; | 6409 | rdev = NULL; |
6497 | mutex_unlock(&cfg80211_mutex); | ||
6498 | 6410 | ||
6499 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | 6411 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) |
6500 | cb->args[1] = | 6412 | cb->args[1] = |
@@ -6506,14 +6418,11 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6506 | data_len = nla_len((void *)cb->args[1]); | 6418 | data_len = nla_len((void *)cb->args[1]); |
6507 | } | 6419 | } |
6508 | 6420 | ||
6509 | mutex_lock(&cfg80211_mutex); | ||
6510 | rdev = cfg80211_rdev_by_wiphy_idx(phy_idx); | 6421 | rdev = cfg80211_rdev_by_wiphy_idx(phy_idx); |
6511 | if (!rdev) { | 6422 | if (!rdev) { |
6512 | mutex_unlock(&cfg80211_mutex); | 6423 | err = -ENOENT; |
6513 | return -ENOENT; | 6424 | goto out_err; |
6514 | } | 6425 | } |
6515 | cfg80211_lock_rdev(rdev); | ||
6516 | mutex_unlock(&cfg80211_mutex); | ||
6517 | 6426 | ||
6518 | if (!rdev->ops->testmode_dump) { | 6427 | if (!rdev->ops->testmode_dump) { |
6519 | err = -EOPNOTSUPP; | 6428 | err = -EOPNOTSUPP; |
@@ -6554,7 +6463,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6554 | /* see above */ | 6463 | /* see above */ |
6555 | cb->args[0] = phy_idx + 1; | 6464 | cb->args[0] = phy_idx + 1; |
6556 | out_err: | 6465 | out_err: |
6557 | cfg80211_unlock_rdev(rdev); | 6466 | rtnl_unlock(); |
6558 | return err; | 6467 | return err; |
6559 | } | 6468 | } |
6560 | 6469 | ||
@@ -8189,9 +8098,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8189 | if (wdev->p2p_started) | 8098 | if (wdev->p2p_started) |
8190 | return 0; | 8099 | return 0; |
8191 | 8100 | ||
8192 | mutex_lock(&rdev->devlist_mtx); | ||
8193 | err = cfg80211_can_add_interface(rdev, wdev->iftype); | 8101 | err = cfg80211_can_add_interface(rdev, wdev->iftype); |
8194 | mutex_unlock(&rdev->devlist_mtx); | ||
8195 | if (err) | 8102 | if (err) |
8196 | return err; | 8103 | return err; |
8197 | 8104 | ||
@@ -8200,9 +8107,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8200 | return err; | 8107 | return err; |
8201 | 8108 | ||
8202 | wdev->p2p_started = true; | 8109 | wdev->p2p_started = true; |
8203 | mutex_lock(&rdev->devlist_mtx); | ||
8204 | rdev->opencount++; | 8110 | rdev->opencount++; |
8205 | mutex_unlock(&rdev->devlist_mtx); | ||
8206 | 8111 | ||
8207 | return 0; | 8112 | return 0; |
8208 | } | 8113 | } |
@@ -8218,11 +8123,7 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8218 | if (!rdev->ops->stop_p2p_device) | 8123 | if (!rdev->ops->stop_p2p_device) |
8219 | return -EOPNOTSUPP; | 8124 | return -EOPNOTSUPP; |
8220 | 8125 | ||
8221 | mutex_lock(&rdev->devlist_mtx); | ||
8222 | mutex_lock(&rdev->sched_scan_mtx); | ||
8223 | cfg80211_stop_p2p_device(rdev, wdev); | 8126 | cfg80211_stop_p2p_device(rdev, wdev); |
8224 | mutex_unlock(&rdev->sched_scan_mtx); | ||
8225 | mutex_unlock(&rdev->devlist_mtx); | ||
8226 | 8127 | ||
8227 | return 0; | 8128 | return 0; |
8228 | } | 8129 | } |
@@ -8365,11 +8266,11 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8365 | info->user_ptr[0] = rdev; | 8266 | info->user_ptr[0] = rdev; |
8366 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || | 8267 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
8367 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { | 8268 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
8368 | mutex_lock(&cfg80211_mutex); | 8269 | ASSERT_RTNL(); |
8270 | |||
8369 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), | 8271 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
8370 | info->attrs); | 8272 | info->attrs); |
8371 | if (IS_ERR(wdev)) { | 8273 | if (IS_ERR(wdev)) { |
8372 | mutex_unlock(&cfg80211_mutex); | ||
8373 | if (rtnl) | 8274 | if (rtnl) |
8374 | rtnl_unlock(); | 8275 | rtnl_unlock(); |
8375 | return PTR_ERR(wdev); | 8276 | return PTR_ERR(wdev); |
@@ -8380,7 +8281,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8380 | 8281 | ||
8381 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 8282 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
8382 | if (!dev) { | 8283 | if (!dev) { |
8383 | mutex_unlock(&cfg80211_mutex); | ||
8384 | if (rtnl) | 8284 | if (rtnl) |
8385 | rtnl_unlock(); | 8285 | rtnl_unlock(); |
8386 | return -EINVAL; | 8286 | return -EINVAL; |
@@ -8394,7 +8294,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8394 | if (dev) { | 8294 | if (dev) { |
8395 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 8295 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && |
8396 | !netif_running(dev)) { | 8296 | !netif_running(dev)) { |
8397 | mutex_unlock(&cfg80211_mutex); | ||
8398 | if (rtnl) | 8297 | if (rtnl) |
8399 | rtnl_unlock(); | 8298 | rtnl_unlock(); |
8400 | return -ENETDOWN; | 8299 | return -ENETDOWN; |
@@ -8403,17 +8302,12 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8403 | dev_hold(dev); | 8302 | dev_hold(dev); |
8404 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { | 8303 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { |
8405 | if (!wdev->p2p_started) { | 8304 | if (!wdev->p2p_started) { |
8406 | mutex_unlock(&cfg80211_mutex); | ||
8407 | if (rtnl) | 8305 | if (rtnl) |
8408 | rtnl_unlock(); | 8306 | rtnl_unlock(); |
8409 | return -ENETDOWN; | 8307 | return -ENETDOWN; |
8410 | } | 8308 | } |
8411 | } | 8309 | } |
8412 | 8310 | ||
8413 | cfg80211_lock_rdev(rdev); | ||
8414 | |||
8415 | mutex_unlock(&cfg80211_mutex); | ||
8416 | |||
8417 | info->user_ptr[0] = rdev; | 8311 | info->user_ptr[0] = rdev; |
8418 | } | 8312 | } |
8419 | 8313 | ||
@@ -8423,8 +8317,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8423 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | 8317 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, |
8424 | struct genl_info *info) | 8318 | struct genl_info *info) |
8425 | { | 8319 | { |
8426 | if (info->user_ptr[0]) | ||
8427 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
8428 | if (info->user_ptr[1]) { | 8320 | if (info->user_ptr[1]) { |
8429 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { | 8321 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
8430 | struct wireless_dev *wdev = info->user_ptr[1]; | 8322 | struct wireless_dev *wdev = info->user_ptr[1]; |
@@ -8446,7 +8338,8 @@ static struct genl_ops nl80211_ops[] = { | |||
8446 | .dumpit = nl80211_dump_wiphy, | 8338 | .dumpit = nl80211_dump_wiphy, |
8447 | .policy = nl80211_policy, | 8339 | .policy = nl80211_policy, |
8448 | /* can be retrieved by unprivileged users */ | 8340 | /* can be retrieved by unprivileged users */ |
8449 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | 8341 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
8342 | NL80211_FLAG_NEED_RTNL, | ||
8450 | }, | 8343 | }, |
8451 | { | 8344 | { |
8452 | .cmd = NL80211_CMD_SET_WIPHY, | 8345 | .cmd = NL80211_CMD_SET_WIPHY, |
@@ -8461,7 +8354,8 @@ static struct genl_ops nl80211_ops[] = { | |||
8461 | .dumpit = nl80211_dump_interface, | 8354 | .dumpit = nl80211_dump_interface, |
8462 | .policy = nl80211_policy, | 8355 | .policy = nl80211_policy, |
8463 | /* can be retrieved by unprivileged users */ | 8356 | /* can be retrieved by unprivileged users */ |
8464 | .internal_flags = NL80211_FLAG_NEED_WDEV, | 8357 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
8358 | NL80211_FLAG_NEED_RTNL, | ||
8465 | }, | 8359 | }, |
8466 | { | 8360 | { |
8467 | .cmd = NL80211_CMD_SET_INTERFACE, | 8361 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -8620,6 +8514,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8620 | .cmd = NL80211_CMD_GET_REG, | 8514 | .cmd = NL80211_CMD_GET_REG, |
8621 | .doit = nl80211_get_reg, | 8515 | .doit = nl80211_get_reg, |
8622 | .policy = nl80211_policy, | 8516 | .policy = nl80211_policy, |
8517 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
8623 | /* can be retrieved by unprivileged users */ | 8518 | /* can be retrieved by unprivileged users */ |
8624 | }, | 8519 | }, |
8625 | { | 8520 | { |
@@ -8627,6 +8522,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8627 | .doit = nl80211_set_reg, | 8522 | .doit = nl80211_set_reg, |
8628 | .policy = nl80211_policy, | 8523 | .policy = nl80211_policy, |
8629 | .flags = GENL_ADMIN_PERM, | 8524 | .flags = GENL_ADMIN_PERM, |
8525 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
8630 | }, | 8526 | }, |
8631 | { | 8527 | { |
8632 | .cmd = NL80211_CMD_REQ_SET_REG, | 8528 | .cmd = NL80211_CMD_REQ_SET_REG, |
@@ -9082,8 +8978,6 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
9082 | struct nlattr *nest; | 8978 | struct nlattr *nest; |
9083 | int i; | 8979 | int i; |
9084 | 8980 | ||
9085 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
9086 | |||
9087 | if (WARN_ON(!req)) | 8981 | if (WARN_ON(!req)) |
9088 | return 0; | 8982 | return 0; |
9089 | 8983 | ||