diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-13 18:33:35 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-27 15:24:07 -0400 |
commit | 463d018323851a608eef52a9427b0585005c647f (patch) | |
tree | b5ad2ee6115e6b780c264022cbc20b36d22fe80c /net/wireless/nl80211.c | |
parent | 5061b0c2b9066de426fbc63f1278d2210e789412 (diff) |
cfg80211: make aware of net namespaces
In order to make cfg80211/nl80211 aware of network namespaces,
we have to do the following things:
* del_virtual_intf method takes an interface index rather
than a netdev pointer - simply change this
* nl80211 uses init_net a lot, it changes to use the sender's
network namespace
* scan requests use the interface index, hold a netdev pointer
and reference instead
* we want a wiphy and its associated virtual interfaces to be
in one netns together, so
- we need to be able to change ns for a given interface, so
export dev_change_net_namespace()
- for each virtual interface set the NETIF_F_NETNS_LOCAL
flag, and clear that flag only when the wiphy changes ns,
to disallow breaking this invariant
* when a network namespace goes away, we need to reparent the
wiphy to init_net
* cfg80211 users that support creating virtual interfaces must
create them in the wiphy's namespace, currently this affects
only mac80211
The end result is that you can now switch an entire wiphy into
a different network namespace with the new command
iw phy#<idx> set netns <pid>
and all virtual interfaces will follow (or the operation fails).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 202 |
1 files changed, 141 insertions, 61 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index da450ef1fc7e..7880a9c4cdda 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -14,8 +14,10 @@ | |||
14 | #include <linux/rtnetlink.h> | 14 | #include <linux/rtnetlink.h> |
15 | #include <linux/netlink.h> | 15 | #include <linux/netlink.h> |
16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
17 | #include <net/net_namespace.h> | ||
17 | #include <net/genetlink.h> | 18 | #include <net/genetlink.h> |
18 | #include <net/cfg80211.h> | 19 | #include <net/cfg80211.h> |
20 | #include <net/sock.h> | ||
19 | #include "core.h" | 21 | #include "core.h" |
20 | #include "nl80211.h" | 22 | #include "nl80211.h" |
21 | #include "reg.h" | 23 | #include "reg.h" |
@@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = { | |||
27 | .hdrsize = 0, /* no private header */ | 29 | .hdrsize = 0, /* no private header */ |
28 | .version = 1, /* no particular meaning now */ | 30 | .version = 1, /* no particular meaning now */ |
29 | .maxattr = NL80211_ATTR_MAX, | 31 | .maxattr = NL80211_ATTR_MAX, |
32 | .netnsok = true, | ||
30 | }; | 33 | }; |
31 | 34 | ||
32 | /* internal helper: get rdev and dev */ | 35 | /* internal helper: get rdev and dev */ |
33 | static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, | 36 | static int get_rdev_dev_by_info_ifindex(struct genl_info *info, |
34 | struct cfg80211_registered_device **rdev, | 37 | struct cfg80211_registered_device **rdev, |
35 | struct net_device **dev) | 38 | struct net_device **dev) |
36 | { | 39 | { |
40 | struct nlattr **attrs = info->attrs; | ||
37 | int ifindex; | 41 | int ifindex; |
38 | 42 | ||
39 | if (!attrs[NL80211_ATTR_IFINDEX]) | 43 | if (!attrs[NL80211_ATTR_IFINDEX]) |
40 | return -EINVAL; | 44 | return -EINVAL; |
41 | 45 | ||
42 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 46 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
43 | *dev = dev_get_by_index(&init_net, ifindex); | 47 | *dev = dev_get_by_index(genl_info_net(info), ifindex); |
44 | if (!*dev) | 48 | if (!*dev) |
45 | return -ENODEV; | 49 | return -ENODEV; |
46 | 50 | ||
47 | *rdev = cfg80211_get_dev_from_ifindex(ifindex); | 51 | *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); |
48 | if (IS_ERR(*rdev)) { | 52 | if (IS_ERR(*rdev)) { |
49 | dev_put(*dev); | 53 | dev_put(*dev); |
50 | return PTR_ERR(*rdev); | 54 | return PTR_ERR(*rdev); |
@@ -133,6 +137,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
133 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | 137 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, |
134 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
135 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | ||
136 | }; | 141 | }; |
137 | 142 | ||
138 | /* policy for the attributes */ | 143 | /* policy for the attributes */ |
@@ -532,6 +537,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
532 | CMD(deauth, DEAUTHENTICATE); | 537 | CMD(deauth, DEAUTHENTICATE); |
533 | CMD(disassoc, DISASSOCIATE); | 538 | CMD(disassoc, DISASSOCIATE); |
534 | CMD(join_ibss, JOIN_IBSS); | 539 | CMD(join_ibss, JOIN_IBSS); |
540 | if (dev->wiphy.netnsok) { | ||
541 | i++; | ||
542 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | ||
543 | } | ||
535 | 544 | ||
536 | #undef CMD | 545 | #undef CMD |
537 | 546 | ||
@@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
562 | 571 | ||
563 | mutex_lock(&cfg80211_mutex); | 572 | mutex_lock(&cfg80211_mutex); |
564 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 573 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
574 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | ||
575 | continue; | ||
565 | if (++idx <= start) | 576 | if (++idx <= start) |
566 | continue; | 577 | continue; |
567 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, | 578 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, |
@@ -867,6 +878,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
867 | 878 | ||
868 | mutex_lock(&cfg80211_mutex); | 879 | mutex_lock(&cfg80211_mutex); |
869 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 880 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
881 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | ||
882 | continue; | ||
870 | if (wp_idx < wp_start) { | 883 | if (wp_idx < wp_start) { |
871 | wp_idx++; | 884 | wp_idx++; |
872 | continue; | 885 | continue; |
@@ -907,7 +920,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
907 | struct net_device *netdev; | 920 | struct net_device *netdev; |
908 | int err; | 921 | int err; |
909 | 922 | ||
910 | err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); | 923 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); |
911 | if (err) | 924 | if (err) |
912 | return err; | 925 | return err; |
913 | 926 | ||
@@ -975,7 +988,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
975 | 988 | ||
976 | rtnl_lock(); | 989 | rtnl_lock(); |
977 | 990 | ||
978 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 991 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
979 | if (err) | 992 | if (err) |
980 | goto unlock_rtnl; | 993 | goto unlock_rtnl; |
981 | 994 | ||
@@ -1098,26 +1111,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1098 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1111 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1099 | { | 1112 | { |
1100 | struct cfg80211_registered_device *rdev; | 1113 | struct cfg80211_registered_device *rdev; |
1101 | int ifindex, err; | 1114 | int err; |
1102 | struct net_device *dev; | 1115 | struct net_device *dev; |
1103 | 1116 | ||
1104 | rtnl_lock(); | 1117 | rtnl_lock(); |
1105 | 1118 | ||
1106 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1119 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1107 | if (err) | 1120 | if (err) |
1108 | goto unlock_rtnl; | 1121 | goto unlock_rtnl; |
1109 | ifindex = dev->ifindex; | ||
1110 | dev_put(dev); | ||
1111 | 1122 | ||
1112 | if (!rdev->ops->del_virtual_intf) { | 1123 | if (!rdev->ops->del_virtual_intf) { |
1113 | err = -EOPNOTSUPP; | 1124 | err = -EOPNOTSUPP; |
1114 | goto out; | 1125 | goto out; |
1115 | } | 1126 | } |
1116 | 1127 | ||
1117 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); | 1128 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1118 | 1129 | ||
1119 | out: | 1130 | out: |
1120 | cfg80211_unlock_rdev(rdev); | 1131 | cfg80211_unlock_rdev(rdev); |
1132 | dev_put(dev); | ||
1121 | unlock_rtnl: | 1133 | unlock_rtnl: |
1122 | rtnl_unlock(); | 1134 | rtnl_unlock(); |
1123 | return err; | 1135 | return err; |
@@ -1195,7 +1207,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1195 | 1207 | ||
1196 | rtnl_lock(); | 1208 | rtnl_lock(); |
1197 | 1209 | ||
1198 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1210 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1199 | if (err) | 1211 | if (err) |
1200 | goto unlock_rtnl; | 1212 | goto unlock_rtnl; |
1201 | 1213 | ||
@@ -1274,7 +1286,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1274 | 1286 | ||
1275 | rtnl_lock(); | 1287 | rtnl_lock(); |
1276 | 1288 | ||
1277 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1289 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1278 | if (err) | 1290 | if (err) |
1279 | goto unlock_rtnl; | 1291 | goto unlock_rtnl; |
1280 | 1292 | ||
@@ -1333,7 +1345,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1333 | 1345 | ||
1334 | rtnl_lock(); | 1346 | rtnl_lock(); |
1335 | 1347 | ||
1336 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1348 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1337 | if (err) | 1349 | if (err) |
1338 | goto unlock_rtnl; | 1350 | goto unlock_rtnl; |
1339 | 1351 | ||
@@ -1380,7 +1392,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1380 | 1392 | ||
1381 | rtnl_lock(); | 1393 | rtnl_lock(); |
1382 | 1394 | ||
1383 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1395 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1384 | if (err) | 1396 | if (err) |
1385 | goto unlock_rtnl; | 1397 | goto unlock_rtnl; |
1386 | 1398 | ||
@@ -1429,7 +1441,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1429 | 1441 | ||
1430 | rtnl_lock(); | 1442 | rtnl_lock(); |
1431 | 1443 | ||
1432 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1444 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1433 | if (err) | 1445 | if (err) |
1434 | goto unlock_rtnl; | 1446 | goto unlock_rtnl; |
1435 | 1447 | ||
@@ -1516,7 +1528,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1516 | 1528 | ||
1517 | rtnl_lock(); | 1529 | rtnl_lock(); |
1518 | 1530 | ||
1519 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1531 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1520 | if (err) | 1532 | if (err) |
1521 | goto unlock_rtnl; | 1533 | goto unlock_rtnl; |
1522 | 1534 | ||
@@ -1726,13 +1738,13 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1726 | 1738 | ||
1727 | rtnl_lock(); | 1739 | rtnl_lock(); |
1728 | 1740 | ||
1729 | netdev = __dev_get_by_index(&init_net, ifidx); | 1741 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
1730 | if (!netdev) { | 1742 | if (!netdev) { |
1731 | err = -ENODEV; | 1743 | err = -ENODEV; |
1732 | goto out_rtnl; | 1744 | goto out_rtnl; |
1733 | } | 1745 | } |
1734 | 1746 | ||
1735 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1747 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
1736 | if (IS_ERR(dev)) { | 1748 | if (IS_ERR(dev)) { |
1737 | err = PTR_ERR(dev); | 1749 | err = PTR_ERR(dev); |
1738 | goto out_rtnl; | 1750 | goto out_rtnl; |
@@ -1791,7 +1803,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1791 | 1803 | ||
1792 | rtnl_lock(); | 1804 | rtnl_lock(); |
1793 | 1805 | ||
1794 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1806 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1795 | if (err) | 1807 | if (err) |
1796 | goto out_rtnl; | 1808 | goto out_rtnl; |
1797 | 1809 | ||
@@ -1829,14 +1841,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1829 | /* | 1841 | /* |
1830 | * Get vlan interface making sure it is on the right wiphy. | 1842 | * Get vlan interface making sure it is on the right wiphy. |
1831 | */ | 1843 | */ |
1832 | static int get_vlan(struct nlattr *vlanattr, | 1844 | static int get_vlan(struct genl_info *info, |
1833 | struct cfg80211_registered_device *rdev, | 1845 | struct cfg80211_registered_device *rdev, |
1834 | struct net_device **vlan) | 1846 | struct net_device **vlan) |
1835 | { | 1847 | { |
1848 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; | ||
1836 | *vlan = NULL; | 1849 | *vlan = NULL; |
1837 | 1850 | ||
1838 | if (vlanattr) { | 1851 | if (vlanattr) { |
1839 | *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); | 1852 | *vlan = dev_get_by_index(genl_info_net(info), |
1853 | nla_get_u32(vlanattr)); | ||
1840 | if (!*vlan) | 1854 | if (!*vlan) |
1841 | return -ENODEV; | 1855 | return -ENODEV; |
1842 | if (!(*vlan)->ieee80211_ptr) | 1856 | if (!(*vlan)->ieee80211_ptr) |
@@ -1891,11 +1905,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1891 | 1905 | ||
1892 | rtnl_lock(); | 1906 | rtnl_lock(); |
1893 | 1907 | ||
1894 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 1908 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
1895 | if (err) | 1909 | if (err) |
1896 | goto out_rtnl; | 1910 | goto out_rtnl; |
1897 | 1911 | ||
1898 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); | 1912 | err = get_vlan(info, rdev, ¶ms.vlan); |
1899 | if (err) | 1913 | if (err) |
1900 | goto out; | 1914 | goto out; |
1901 | 1915 | ||
@@ -2004,11 +2018,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2004 | 2018 | ||
2005 | rtnl_lock(); | 2019 | rtnl_lock(); |
2006 | 2020 | ||
2007 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2021 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2008 | if (err) | 2022 | if (err) |
2009 | goto out_rtnl; | 2023 | goto out_rtnl; |
2010 | 2024 | ||
2011 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); | 2025 | err = get_vlan(info, rdev, ¶ms.vlan); |
2012 | if (err) | 2026 | if (err) |
2013 | goto out; | 2027 | goto out; |
2014 | 2028 | ||
@@ -2079,7 +2093,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
2079 | 2093 | ||
2080 | rtnl_lock(); | 2094 | rtnl_lock(); |
2081 | 2095 | ||
2082 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2096 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2083 | if (err) | 2097 | if (err) |
2084 | goto out_rtnl; | 2098 | goto out_rtnl; |
2085 | 2099 | ||
@@ -2185,13 +2199,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2185 | 2199 | ||
2186 | rtnl_lock(); | 2200 | rtnl_lock(); |
2187 | 2201 | ||
2188 | netdev = __dev_get_by_index(&init_net, ifidx); | 2202 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); |
2189 | if (!netdev) { | 2203 | if (!netdev) { |
2190 | err = -ENODEV; | 2204 | err = -ENODEV; |
2191 | goto out_rtnl; | 2205 | goto out_rtnl; |
2192 | } | 2206 | } |
2193 | 2207 | ||
2194 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 2208 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
2195 | if (IS_ERR(dev)) { | 2209 | if (IS_ERR(dev)) { |
2196 | err = PTR_ERR(dev); | 2210 | err = PTR_ERR(dev); |
2197 | goto out_rtnl; | 2211 | goto out_rtnl; |
@@ -2255,7 +2269,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2255 | 2269 | ||
2256 | rtnl_lock(); | 2270 | rtnl_lock(); |
2257 | 2271 | ||
2258 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2272 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2259 | if (err) | 2273 | if (err) |
2260 | goto out_rtnl; | 2274 | goto out_rtnl; |
2261 | 2275 | ||
@@ -2314,7 +2328,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2314 | 2328 | ||
2315 | rtnl_lock(); | 2329 | rtnl_lock(); |
2316 | 2330 | ||
2317 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2331 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2318 | if (err) | 2332 | if (err) |
2319 | goto out_rtnl; | 2333 | goto out_rtnl; |
2320 | 2334 | ||
@@ -2362,7 +2376,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2362 | 2376 | ||
2363 | rtnl_lock(); | 2377 | rtnl_lock(); |
2364 | 2378 | ||
2365 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2379 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2366 | if (err) | 2380 | if (err) |
2367 | goto out_rtnl; | 2381 | goto out_rtnl; |
2368 | 2382 | ||
@@ -2404,7 +2418,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2404 | 2418 | ||
2405 | rtnl_lock(); | 2419 | rtnl_lock(); |
2406 | 2420 | ||
2407 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2421 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2408 | if (err) | 2422 | if (err) |
2409 | goto out_rtnl; | 2423 | goto out_rtnl; |
2410 | 2424 | ||
@@ -2455,7 +2469,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2455 | 2469 | ||
2456 | rtnl_lock(); | 2470 | rtnl_lock(); |
2457 | 2471 | ||
2458 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2472 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2459 | if (err) | 2473 | if (err) |
2460 | goto out_rtnl; | 2474 | goto out_rtnl; |
2461 | 2475 | ||
@@ -2574,7 +2588,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2574 | rtnl_lock(); | 2588 | rtnl_lock(); |
2575 | 2589 | ||
2576 | /* Look up our device */ | 2590 | /* Look up our device */ |
2577 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2591 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2578 | if (err) | 2592 | if (err) |
2579 | goto out_rtnl; | 2593 | goto out_rtnl; |
2580 | 2594 | ||
@@ -2691,7 +2705,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2691 | 2705 | ||
2692 | rtnl_lock(); | 2706 | rtnl_lock(); |
2693 | 2707 | ||
2694 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2708 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2695 | if (err) | 2709 | if (err) |
2696 | goto out_rtnl; | 2710 | goto out_rtnl; |
2697 | 2711 | ||
@@ -2947,7 +2961,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2947 | 2961 | ||
2948 | rtnl_lock(); | 2962 | rtnl_lock(); |
2949 | 2963 | ||
2950 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 2964 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
2951 | if (err) | 2965 | if (err) |
2952 | goto out_rtnl; | 2966 | goto out_rtnl; |
2953 | 2967 | ||
@@ -3069,14 +3083,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3069 | request->ie_len); | 3083 | request->ie_len); |
3070 | } | 3084 | } |
3071 | 3085 | ||
3072 | request->ifidx = dev->ifindex; | 3086 | request->dev = dev; |
3073 | request->wiphy = &rdev->wiphy; | 3087 | request->wiphy = &rdev->wiphy; |
3074 | 3088 | ||
3075 | rdev->scan_req = request; | 3089 | rdev->scan_req = request; |
3076 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 3090 | err = rdev->ops->scan(&rdev->wiphy, dev, request); |
3077 | 3091 | ||
3078 | if (!err) | 3092 | if (!err) { |
3079 | nl80211_send_scan_start(rdev, dev); | 3093 | nl80211_send_scan_start(rdev, dev); |
3094 | dev_hold(dev); | ||
3095 | } | ||
3080 | 3096 | ||
3081 | out_free: | 3097 | out_free: |
3082 | if (err) { | 3098 | if (err) { |
@@ -3198,11 +3214,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3198 | cb->args[0] = ifidx; | 3214 | cb->args[0] = ifidx; |
3199 | } | 3215 | } |
3200 | 3216 | ||
3201 | dev = dev_get_by_index(&init_net, ifidx); | 3217 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); |
3202 | if (!dev) | 3218 | if (!dev) |
3203 | return -ENODEV; | 3219 | return -ENODEV; |
3204 | 3220 | ||
3205 | rdev = cfg80211_get_dev_from_ifindex(ifidx); | 3221 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); |
3206 | if (IS_ERR(rdev)) { | 3222 | if (IS_ERR(rdev)) { |
3207 | err = PTR_ERR(rdev); | 3223 | err = PTR_ERR(rdev); |
3208 | goto out_put_netdev; | 3224 | goto out_put_netdev; |
@@ -3312,7 +3328,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3312 | 3328 | ||
3313 | rtnl_lock(); | 3329 | rtnl_lock(); |
3314 | 3330 | ||
3315 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3331 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3316 | if (err) | 3332 | if (err) |
3317 | goto unlock_rtnl; | 3333 | goto unlock_rtnl; |
3318 | 3334 | ||
@@ -3448,7 +3464,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3448 | 3464 | ||
3449 | rtnl_lock(); | 3465 | rtnl_lock(); |
3450 | 3466 | ||
3451 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3467 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3452 | if (err) | 3468 | if (err) |
3453 | goto unlock_rtnl; | 3469 | goto unlock_rtnl; |
3454 | 3470 | ||
@@ -3531,7 +3547,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3531 | 3547 | ||
3532 | rtnl_lock(); | 3548 | rtnl_lock(); |
3533 | 3549 | ||
3534 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3550 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3535 | if (err) | 3551 | if (err) |
3536 | goto unlock_rtnl; | 3552 | goto unlock_rtnl; |
3537 | 3553 | ||
@@ -3593,7 +3609,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3593 | 3609 | ||
3594 | rtnl_lock(); | 3610 | rtnl_lock(); |
3595 | 3611 | ||
3596 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3612 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3597 | if (err) | 3613 | if (err) |
3598 | goto unlock_rtnl; | 3614 | goto unlock_rtnl; |
3599 | 3615 | ||
@@ -3666,7 +3682,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3666 | 3682 | ||
3667 | rtnl_lock(); | 3683 | rtnl_lock(); |
3668 | 3684 | ||
3669 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3685 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3670 | if (err) | 3686 | if (err) |
3671 | goto unlock_rtnl; | 3687 | goto unlock_rtnl; |
3672 | 3688 | ||
@@ -3739,7 +3755,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3739 | 3755 | ||
3740 | rtnl_lock(); | 3756 | rtnl_lock(); |
3741 | 3757 | ||
3742 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3758 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3743 | if (err) | 3759 | if (err) |
3744 | goto unlock_rtnl; | 3760 | goto unlock_rtnl; |
3745 | 3761 | ||
@@ -3924,7 +3940,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
3924 | return err; | 3940 | return err; |
3925 | rtnl_lock(); | 3941 | rtnl_lock(); |
3926 | 3942 | ||
3927 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 3943 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
3928 | if (err) | 3944 | if (err) |
3929 | goto unlock_rtnl; | 3945 | goto unlock_rtnl; |
3930 | 3946 | ||
@@ -4000,7 +4016,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4000 | 4016 | ||
4001 | rtnl_lock(); | 4017 | rtnl_lock(); |
4002 | 4018 | ||
4003 | err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); | 4019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4004 | if (err) | 4020 | if (err) |
4005 | goto unlock_rtnl; | 4021 | goto unlock_rtnl; |
4006 | 4022 | ||
@@ -4024,6 +4040,47 @@ unlock_rtnl: | |||
4024 | return err; | 4040 | return err; |
4025 | } | 4041 | } |
4026 | 4042 | ||
4043 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | ||
4044 | { | ||
4045 | struct cfg80211_registered_device *rdev; | ||
4046 | struct net *net; | ||
4047 | int err; | ||
4048 | u32 pid; | ||
4049 | |||
4050 | if (!info->attrs[NL80211_ATTR_PID]) | ||
4051 | return -EINVAL; | ||
4052 | |||
4053 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | ||
4054 | |||
4055 | rtnl_lock(); | ||
4056 | |||
4057 | rdev = cfg80211_get_dev_from_info(info); | ||
4058 | if (IS_ERR(rdev)) { | ||
4059 | err = PTR_ERR(rdev); | ||
4060 | goto out; | ||
4061 | } | ||
4062 | |||
4063 | net = get_net_ns_by_pid(pid); | ||
4064 | if (IS_ERR(net)) { | ||
4065 | err = PTR_ERR(net); | ||
4066 | goto out; | ||
4067 | } | ||
4068 | |||
4069 | err = 0; | ||
4070 | |||
4071 | /* check if anything to do */ | ||
4072 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | ||
4073 | goto out_put_net; | ||
4074 | |||
4075 | err = cfg80211_switch_netns(rdev, net); | ||
4076 | out_put_net: | ||
4077 | put_net(net); | ||
4078 | out: | ||
4079 | cfg80211_unlock_rdev(rdev); | ||
4080 | rtnl_unlock(); | ||
4081 | return err; | ||
4082 | } | ||
4083 | |||
4027 | static struct genl_ops nl80211_ops[] = { | 4084 | static struct genl_ops nl80211_ops[] = { |
4028 | { | 4085 | { |
4029 | .cmd = NL80211_CMD_GET_WIPHY, | 4086 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4257,6 +4314,12 @@ static struct genl_ops nl80211_ops[] = { | |||
4257 | .policy = nl80211_policy, | 4314 | .policy = nl80211_policy, |
4258 | .flags = GENL_ADMIN_PERM, | 4315 | .flags = GENL_ADMIN_PERM, |
4259 | }, | 4316 | }, |
4317 | { | ||
4318 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | ||
4319 | .doit = nl80211_wiphy_netns, | ||
4320 | .policy = nl80211_policy, | ||
4321 | .flags = GENL_ADMIN_PERM, | ||
4322 | }, | ||
4260 | }; | 4323 | }; |
4261 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4324 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4262 | .name = "mlme", | 4325 | .name = "mlme", |
@@ -4288,7 +4351,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
4288 | return; | 4351 | return; |
4289 | } | 4352 | } |
4290 | 4353 | ||
4291 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 4354 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4355 | nl80211_config_mcgrp.id, GFP_KERNEL); | ||
4292 | } | 4356 | } |
4293 | 4357 | ||
4294 | static int nl80211_add_scan_req(struct sk_buff *msg, | 4358 | static int nl80211_add_scan_req(struct sk_buff *msg, |
@@ -4365,7 +4429,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
4365 | return; | 4429 | return; |
4366 | } | 4430 | } |
4367 | 4431 | ||
4368 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4432 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4433 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4369 | } | 4434 | } |
4370 | 4435 | ||
4371 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 4436 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
@@ -4383,7 +4448,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
4383 | return; | 4448 | return; |
4384 | } | 4449 | } |
4385 | 4450 | ||
4386 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4451 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4452 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4387 | } | 4453 | } |
4388 | 4454 | ||
4389 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 4455 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
@@ -4401,7 +4467,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
4401 | return; | 4467 | return; |
4402 | } | 4468 | } |
4403 | 4469 | ||
4404 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 4470 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4471 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
4405 | } | 4472 | } |
4406 | 4473 | ||
4407 | /* | 4474 | /* |
@@ -4450,7 +4517,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
4450 | return; | 4517 | return; |
4451 | } | 4518 | } |
4452 | 4519 | ||
4453 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); | 4520 | rtnl_lock(); |
4521 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | ||
4522 | GFP_KERNEL); | ||
4523 | rtnl_unlock(); | ||
4454 | 4524 | ||
4455 | return; | 4525 | return; |
4456 | 4526 | ||
@@ -4486,7 +4556,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
4486 | return; | 4556 | return; |
4487 | } | 4557 | } |
4488 | 4558 | ||
4489 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4559 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4560 | nl80211_mlme_mcgrp.id, gfp); | ||
4490 | return; | 4561 | return; |
4491 | 4562 | ||
4492 | nla_put_failure: | 4563 | nla_put_failure: |
@@ -4553,7 +4624,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | |||
4553 | return; | 4624 | return; |
4554 | } | 4625 | } |
4555 | 4626 | ||
4556 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4627 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4628 | nl80211_mlme_mcgrp.id, gfp); | ||
4557 | return; | 4629 | return; |
4558 | 4630 | ||
4559 | nla_put_failure: | 4631 | nla_put_failure: |
@@ -4611,7 +4683,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
4611 | return; | 4683 | return; |
4612 | } | 4684 | } |
4613 | 4685 | ||
4614 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4686 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4687 | nl80211_mlme_mcgrp.id, gfp); | ||
4615 | return; | 4688 | return; |
4616 | 4689 | ||
4617 | nla_put_failure: | 4690 | nla_put_failure: |
@@ -4651,7 +4724,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
4651 | return; | 4724 | return; |
4652 | } | 4725 | } |
4653 | 4726 | ||
4654 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4727 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4728 | nl80211_mlme_mcgrp.id, gfp); | ||
4655 | return; | 4729 | return; |
4656 | 4730 | ||
4657 | nla_put_failure: | 4731 | nla_put_failure: |
@@ -4691,7 +4765,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
4691 | return; | 4765 | return; |
4692 | } | 4766 | } |
4693 | 4767 | ||
4694 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | 4768 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4769 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
4695 | return; | 4770 | return; |
4696 | 4771 | ||
4697 | nla_put_failure: | 4772 | nla_put_failure: |
@@ -4726,7 +4801,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
4726 | return; | 4801 | return; |
4727 | } | 4802 | } |
4728 | 4803 | ||
4729 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4804 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4805 | nl80211_mlme_mcgrp.id, gfp); | ||
4730 | return; | 4806 | return; |
4731 | 4807 | ||
4732 | nla_put_failure: | 4808 | nla_put_failure: |
@@ -4766,7 +4842,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
4766 | return; | 4842 | return; |
4767 | } | 4843 | } |
4768 | 4844 | ||
4769 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4845 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
4846 | nl80211_mlme_mcgrp.id, gfp); | ||
4770 | return; | 4847 | return; |
4771 | 4848 | ||
4772 | nla_put_failure: | 4849 | nla_put_failure: |
@@ -4819,7 +4896,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
4819 | return; | 4896 | return; |
4820 | } | 4897 | } |
4821 | 4898 | ||
4822 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); | 4899 | rcu_read_lock(); |
4900 | genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, | ||
4901 | GFP_ATOMIC); | ||
4902 | rcu_read_unlock(); | ||
4823 | 4903 | ||
4824 | return; | 4904 | return; |
4825 | 4905 | ||