diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 13:01:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 13:01:50 -0400 |
commit | 3c4cfadef6a1665d9cd02a543782d03d3e6740c6 (patch) | |
tree | 3df72faaacd494d5ac8c9668df4f529b1b5e4457 /net/wireless/nl80211.c | |
parent | e017507f37d5cb8b541df165a824958bc333bec3 (diff) | |
parent | 320f5ea0cedc08ef65d67e056bcb9d181386ef2c (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking changes from David S Miller:
1) Remove the ipv4 routing cache. Now lookups go directly into the FIB
trie and use prebuilt routes cached there.
No more garbage collection, no more rDOS attacks on the routing
cache. Instead we now get predictable and consistent performance,
no matter what the pattern of traffic we service.
This has been almost 2 years in the making. Special thanks to
Julian Anastasov, Eric Dumazet, Steffen Klassert, and others who
have helped along the way.
I'm sure that with a change of this magnitude there will be some
kind of fallout, but such things ought the be simple to fix at this
point. Luckily I'm not European so I'll be around all of August to
fix things :-)
The major stages of this work here are each fronted by a forced
merge commit whose commit message contains a top-level description
of the motivations and implementation issues.
2) Pre-demux of established ipv4 TCP sockets, saves a route demux on
input.
3) TCP SYN/ACK performance tweaks from Eric Dumazet.
4) Add namespace support for netfilter L4 conntrack helpers, from Gao
Feng.
5) Add config mechanism for Energy Efficient Ethernet to ethtool, from
Yuval Mintz.
6) Remove quadratic behavior from /proc/net/unix, from Eric Dumazet.
7) Support for connection tracker helpers in userspace, from Pablo
Neira Ayuso.
8) Allow userspace driven TX load balancing functions in TEAM driver,
from Jiri Pirko.
9) Kill off NLMSG_PUT and RTA_PUT macros, more gross stuff with
embedded gotos.
10) TCP Small Queues, essentially minimize the amount of TCP data queued
up in the packet scheduler layer. Whereas the existing BQL (Byte
Queue Limits) limits the pkt_sched --> netdevice queuing levels,
this controls the TCP --> pkt_sched queueing levels.
From Eric Dumazet.
11) Reduce the number of get_page/put_page ops done on SKB fragments,
from Alexander Duyck.
12) Implement protection against blind resets in TCP (RFC 5961), from
Eric Dumazet.
13) Support the client side of TCP Fast Open, basically the ability to
send data in the SYN exchange, from Yuchung Cheng.
Basically, the sender queues up data with a sendmsg() call using
MSG_FASTOPEN, then they do the connect() which emits the queued up
fastopen data.
14) Avoid all the problems we get into in TCP when timers or PMTU events
hit a locked socket. The TCP Small Queues changes added a
tcp_release_cb() that allows us to queue work up to the
release_sock() caller, and that's what we use here too. From Eric
Dumazet.
15) Zero copy on TX support for TUN driver, from Michael S. Tsirkin.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1870 commits)
genetlink: define lockdep_genl_is_held() when CONFIG_LOCKDEP
r8169: revert "add byte queue limit support".
ipv4: Change rt->rt_iif encoding.
net: Make skb->skb_iif always track skb->dev
ipv4: Prepare for change of rt->rt_iif encoding.
ipv4: Remove all RTCF_DIRECTSRC handliing.
ipv4: Really ignore ICMP address requests/replies.
decnet: Don't set RTCF_DIRECTSRC.
net/ipv4/ip_vti.c: Fix __rcu warnings detected by sparse.
ipv4: Remove redundant assignment
rds: set correct msg_namelen
openvswitch: potential NULL deref in sample()
tcp: dont drop MTU reduction indications
bnx2x: Add new 57840 device IDs
tcp: avoid oops in tcp_metrics and reset tcpm_stamp
niu: Change niu_rbr_fill() to use unlikely() to check niu_rbr_add_page() return value
niu: Fix to check for dma mapping errors.
net: Fix references to out-of-scope variables in put_cmsg_compat()
net: ethernet: davinci_emac: add pm_runtime support
net: ethernet: davinci_emac: Remove unnecessary #include
...
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 1009 |
1 files changed, 755 insertions, 254 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 206465dc0cab..97026f3b215a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -46,28 +46,175 @@ 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); | ||
103 | } | ||
104 | |||
105 | static struct cfg80211_registered_device * | ||
106 | __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | ||
107 | { | ||
108 | struct cfg80211_registered_device *rdev = NULL, *tmp; | ||
109 | struct net_device *netdev; | ||
110 | |||
111 | assert_cfg80211_lock(); | ||
112 | |||
113 | if (!attrs[NL80211_ATTR_WIPHY] && | ||
114 | !attrs[NL80211_ATTR_IFINDEX] && | ||
115 | !attrs[NL80211_ATTR_WDEV]) | ||
116 | return ERR_PTR(-EINVAL); | ||
117 | |||
118 | if (attrs[NL80211_ATTR_WIPHY]) | ||
119 | rdev = cfg80211_rdev_by_wiphy_idx( | ||
120 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); | ||
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 | |||
148 | if (attrs[NL80211_ATTR_IFINDEX]) { | ||
149 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | ||
150 | netdev = dev_get_by_index(netns, ifindex); | ||
151 | if (netdev) { | ||
152 | if (netdev->ieee80211_ptr) | ||
153 | tmp = wiphy_to_dev( | ||
154 | netdev->ieee80211_ptr->wiphy); | ||
155 | else | ||
156 | tmp = NULL; | ||
157 | |||
158 | dev_put(netdev); | ||
159 | |||
160 | /* not wireless device -- return error */ | ||
161 | if (!tmp) | ||
162 | return ERR_PTR(-EINVAL); | ||
163 | |||
164 | /* mismatch -- return error */ | ||
165 | if (rdev && tmp != rdev) | ||
166 | return ERR_PTR(-EINVAL); | ||
167 | |||
168 | rdev = tmp; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if (!rdev) | ||
173 | return ERR_PTR(-ENODEV); | ||
174 | |||
175 | if (netns != wiphy_net(&rdev->wiphy)) | ||
176 | return ERR_PTR(-ENODEV); | ||
177 | |||
178 | return rdev; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * This function returns a pointer to the driver | ||
183 | * that the genl_info item that is passed refers to. | ||
184 | * If successful, it returns non-NULL and also locks | ||
185 | * the driver's mutex! | ||
186 | * | ||
187 | * This means that you need to call cfg80211_unlock_rdev() | ||
188 | * before being allowed to acquire &cfg80211_mutex! | ||
189 | * | ||
190 | * This is necessary because we need to lock the global | ||
191 | * mutex to get an item off the list safely, and then | ||
192 | * we lock the rdev mutex so it doesn't go away under us. | ||
193 | * | ||
194 | * We don't want to keep cfg80211_mutex locked | ||
195 | * for all the time in order to allow requests on | ||
196 | * other interfaces to go through at the same time. | ||
197 | * | ||
198 | * The result of this can be a PTR_ERR and hence must | ||
199 | * be checked with IS_ERR() for errors. | ||
200 | */ | ||
201 | static struct cfg80211_registered_device * | ||
202 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | ||
203 | { | ||
204 | struct cfg80211_registered_device *rdev; | ||
205 | |||
206 | mutex_lock(&cfg80211_mutex); | ||
207 | rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); | ||
208 | |||
209 | /* if it is not an error we grab the lock on | ||
210 | * it to assure it won't be going away while | ||
211 | * we operate on it */ | ||
212 | if (!IS_ERR(rdev)) | ||
213 | mutex_lock(&rdev->mtx); | ||
214 | |||
215 | mutex_unlock(&cfg80211_mutex); | ||
216 | |||
217 | return rdev; | ||
71 | } | 218 | } |
72 | 219 | ||
73 | /* policy for the attributes */ | 220 | /* policy for the attributes */ |
@@ -115,7 +262,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
115 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 262 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
116 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 263 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
117 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 264 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
118 | .len = IEEE80211_MAX_MESH_ID_LEN }, | 265 | .len = IEEE80211_MAX_MESH_ID_LEN }, |
119 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | 266 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, |
120 | 267 | ||
121 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, | 268 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, |
@@ -206,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
206 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, | 353 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, |
207 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, | 354 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, |
208 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, | 355 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, |
356 | [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, | ||
357 | [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, | ||
209 | }; | 358 | }; |
210 | 359 | ||
211 | /* policy for the key attributes */ | 360 | /* policy for the key attributes */ |
@@ -250,8 +399,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | |||
250 | 399 | ||
251 | static const struct nla_policy | 400 | static const struct nla_policy |
252 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | 401 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { |
253 | [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY, | 402 | [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, |
254 | .len = IEEE80211_MAX_SSID_LEN }, | 403 | .len = IEEE80211_MAX_SSID_LEN }, |
404 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | ||
255 | }; | 405 | }; |
256 | 406 | ||
257 | /* ifidx get helper */ | 407 | /* ifidx get helper */ |
@@ -832,6 +982,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
832 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 982 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
833 | goto nla_put_failure; | 983 | goto nla_put_failure; |
834 | 984 | ||
985 | /* add VHT info */ | ||
986 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
987 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
988 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
989 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
990 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
991 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
992 | goto nla_put_failure; | ||
993 | |||
835 | /* add frequencies */ | 994 | /* add frequencies */ |
836 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 995 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
837 | if (!nl_freqs) | 996 | if (!nl_freqs) |
@@ -921,7 +1080,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | 1080 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) |
922 | goto nla_put_failure; | 1081 | goto nla_put_failure; |
923 | } | 1082 | } |
924 | CMD(set_channel, SET_CHANNEL); | 1083 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1084 | dev->ops->join_mesh) { | ||
1085 | i++; | ||
1086 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1087 | goto nla_put_failure; | ||
1088 | } | ||
925 | CMD(set_wds_peer, SET_WDS_PEER); | 1089 | CMD(set_wds_peer, SET_WDS_PEER); |
926 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1090 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
927 | CMD(tdls_mgmt, TDLS_MGMT); | 1091 | CMD(tdls_mgmt, TDLS_MGMT); |
@@ -1018,6 +1182,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1018 | nla_nest_end(msg, nl_ifs); | 1182 | nla_nest_end(msg, nl_ifs); |
1019 | } | 1183 | } |
1020 | 1184 | ||
1185 | #ifdef CONFIG_PM | ||
1021 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1186 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1022 | struct nlattr *nl_wowlan; | 1187 | struct nlattr *nl_wowlan; |
1023 | 1188 | ||
@@ -1058,6 +1223,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1058 | 1223 | ||
1059 | nla_nest_end(msg, nl_wowlan); | 1224 | nla_nest_end(msg, nl_wowlan); |
1060 | } | 1225 | } |
1226 | #endif | ||
1061 | 1227 | ||
1062 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1228 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1063 | dev->wiphy.software_iftypes)) | 1229 | dev->wiphy.software_iftypes)) |
@@ -1162,18 +1328,22 @@ static int parse_txq_params(struct nlattr *tb[], | |||
1162 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | 1328 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) |
1163 | { | 1329 | { |
1164 | /* | 1330 | /* |
1165 | * You can only set the channel explicitly for AP, mesh | 1331 | * You can only set the channel explicitly for WDS interfaces, |
1166 | * and WDS type interfaces; all others have their channel | 1332 | * all others have their channel managed via their respective |
1167 | * managed via their respective "establish a connection" | 1333 | * "establish a connection" command (connect, join, ...) |
1168 | * command (connect, join, ...) | 1334 | * |
1335 | * For AP/GO and mesh mode, the channel can be set with the | ||
1336 | * channel userspace API, but is only stored and passed to the | ||
1337 | * low-level driver when the AP starts or the mesh is joined. | ||
1338 | * This is for backward compatibility, userspace can also give | ||
1339 | * the channel in the start-ap or join-mesh commands instead. | ||
1169 | * | 1340 | * |
1170 | * Monitors are special as they are normally slaved to | 1341 | * Monitors are special as they are normally slaved to |
1171 | * whatever else is going on, so they behave as though | 1342 | * whatever else is going on, so they have their own special |
1172 | * you tried setting the wiphy channel itself. | 1343 | * operation to set the monitor channel if possible. |
1173 | */ | 1344 | */ |
1174 | return !wdev || | 1345 | return !wdev || |
1175 | wdev->iftype == NL80211_IFTYPE_AP || | 1346 | wdev->iftype == NL80211_IFTYPE_AP || |
1176 | wdev->iftype == NL80211_IFTYPE_WDS || | ||
1177 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 1347 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || |
1178 | wdev->iftype == NL80211_IFTYPE_MONITOR || | 1348 | wdev->iftype == NL80211_IFTYPE_MONITOR || |
1179 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 1349 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
@@ -1204,9 +1374,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1204 | struct wireless_dev *wdev, | 1374 | struct wireless_dev *wdev, |
1205 | struct genl_info *info) | 1375 | struct genl_info *info) |
1206 | { | 1376 | { |
1377 | struct ieee80211_channel *channel; | ||
1207 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 1378 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
1208 | u32 freq; | 1379 | u32 freq; |
1209 | int result; | 1380 | int result; |
1381 | enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; | ||
1382 | |||
1383 | if (wdev) | ||
1384 | iftype = wdev->iftype; | ||
1210 | 1385 | ||
1211 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 1386 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
1212 | return -EINVAL; | 1387 | return -EINVAL; |
@@ -1221,12 +1396,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1221 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 1396 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
1222 | 1397 | ||
1223 | mutex_lock(&rdev->devlist_mtx); | 1398 | mutex_lock(&rdev->devlist_mtx); |
1224 | if (wdev) { | 1399 | switch (iftype) { |
1225 | wdev_lock(wdev); | 1400 | case NL80211_IFTYPE_AP: |
1226 | result = cfg80211_set_freq(rdev, wdev, freq, channel_type); | 1401 | case NL80211_IFTYPE_P2P_GO: |
1227 | wdev_unlock(wdev); | 1402 | if (wdev->beacon_interval) { |
1228 | } else { | 1403 | result = -EBUSY; |
1229 | result = cfg80211_set_freq(rdev, NULL, freq, channel_type); | 1404 | break; |
1405 | } | ||
1406 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
1407 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
1408 | channel, | ||
1409 | channel_type)) { | ||
1410 | result = -EINVAL; | ||
1411 | break; | ||
1412 | } | ||
1413 | wdev->preset_chan = channel; | ||
1414 | wdev->preset_chantype = channel_type; | ||
1415 | result = 0; | ||
1416 | break; | ||
1417 | case NL80211_IFTYPE_MESH_POINT: | ||
1418 | result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); | ||
1419 | break; | ||
1420 | case NL80211_IFTYPE_MONITOR: | ||
1421 | result = cfg80211_set_monitor_channel(rdev, freq, channel_type); | ||
1422 | break; | ||
1423 | default: | ||
1424 | result = -EINVAL; | ||
1230 | } | 1425 | } |
1231 | mutex_unlock(&rdev->devlist_mtx); | 1426 | mutex_unlock(&rdev->devlist_mtx); |
1232 | 1427 | ||
@@ -1300,7 +1495,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1300 | } | 1495 | } |
1301 | 1496 | ||
1302 | if (!netdev) { | 1497 | if (!netdev) { |
1303 | rdev = __cfg80211_rdev_from_info(info); | 1498 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), |
1499 | info->attrs); | ||
1304 | if (IS_ERR(rdev)) { | 1500 | if (IS_ERR(rdev)) { |
1305 | mutex_unlock(&cfg80211_mutex); | 1501 | mutex_unlock(&cfg80211_mutex); |
1306 | return PTR_ERR(rdev); | 1502 | return PTR_ERR(rdev); |
@@ -1310,8 +1506,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1310 | result = 0; | 1506 | result = 0; |
1311 | 1507 | ||
1312 | mutex_lock(&rdev->mtx); | 1508 | mutex_lock(&rdev->mtx); |
1313 | } else if (netif_running(netdev) && | 1509 | } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) |
1314 | nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) | ||
1315 | wdev = netdev->ieee80211_ptr; | 1510 | wdev = netdev->ieee80211_ptr; |
1316 | else | 1511 | else |
1317 | wdev = NULL; | 1512 | wdev = NULL; |
@@ -1534,22 +1729,32 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1534 | return result; | 1729 | return result; |
1535 | } | 1730 | } |
1536 | 1731 | ||
1732 | static inline u64 wdev_id(struct wireless_dev *wdev) | ||
1733 | { | ||
1734 | return (u64)wdev->identifier | | ||
1735 | ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); | ||
1736 | } | ||
1537 | 1737 | ||
1538 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 1738 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
1539 | struct cfg80211_registered_device *rdev, | 1739 | struct cfg80211_registered_device *rdev, |
1540 | struct net_device *dev) | 1740 | struct wireless_dev *wdev) |
1541 | { | 1741 | { |
1742 | struct net_device *dev = wdev->netdev; | ||
1542 | void *hdr; | 1743 | void *hdr; |
1543 | 1744 | ||
1544 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 1745 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
1545 | if (!hdr) | 1746 | if (!hdr) |
1546 | return -1; | 1747 | return -1; |
1547 | 1748 | ||
1548 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | 1749 | if (dev && |
1549 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 1750 | (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
1550 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || | 1751 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || |
1551 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, | 1752 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) |
1552 | dev->ieee80211_ptr->iftype) || | 1753 | goto nla_put_failure; |
1754 | |||
1755 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
1756 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || | ||
1757 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
1553 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 1758 | nla_put_u32(msg, NL80211_ATTR_GENERATION, |
1554 | rdev->devlist_generation ^ | 1759 | rdev->devlist_generation ^ |
1555 | (cfg80211_rdev_list_generation << 2))) | 1760 | (cfg80211_rdev_list_generation << 2))) |
@@ -1559,12 +1764,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1559 | struct ieee80211_channel *chan; | 1764 | struct ieee80211_channel *chan; |
1560 | enum nl80211_channel_type channel_type; | 1765 | enum nl80211_channel_type channel_type; |
1561 | 1766 | ||
1562 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1767 | chan = rdev->ops->get_channel(&rdev->wiphy, wdev, |
1768 | &channel_type); | ||
1563 | if (chan && | 1769 | if (chan && |
1564 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1770 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1565 | chan->center_freq) || | 1771 | chan->center_freq) || |
1566 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | 1772 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
1567 | channel_type))) | 1773 | channel_type))) |
1568 | goto nla_put_failure; | 1774 | goto nla_put_failure; |
1569 | } | 1775 | } |
1570 | 1776 | ||
@@ -1595,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1595 | if_idx = 0; | 1801 | if_idx = 0; |
1596 | 1802 | ||
1597 | mutex_lock(&rdev->devlist_mtx); | 1803 | mutex_lock(&rdev->devlist_mtx); |
1598 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 1804 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1599 | if (if_idx < if_start) { | 1805 | if (if_idx < if_start) { |
1600 | if_idx++; | 1806 | if_idx++; |
1601 | continue; | 1807 | continue; |
1602 | } | 1808 | } |
1603 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 1809 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
1604 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1810 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1605 | rdev, wdev->netdev) < 0) { | 1811 | rdev, wdev) < 0) { |
1606 | mutex_unlock(&rdev->devlist_mtx); | 1812 | mutex_unlock(&rdev->devlist_mtx); |
1607 | goto out; | 1813 | goto out; |
1608 | } | 1814 | } |
@@ -1625,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
1625 | { | 1831 | { |
1626 | struct sk_buff *msg; | 1832 | struct sk_buff *msg; |
1627 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1833 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1628 | struct net_device *netdev = info->user_ptr[1]; | 1834 | struct wireless_dev *wdev = info->user_ptr[1]; |
1629 | 1835 | ||
1630 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1836 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1631 | if (!msg) | 1837 | if (!msg) |
1632 | return -ENOMEM; | 1838 | return -ENOMEM; |
1633 | 1839 | ||
1634 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1840 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1635 | dev, netdev) < 0) { | 1841 | dev, wdev) < 0) { |
1636 | nlmsg_free(msg); | 1842 | nlmsg_free(msg); |
1637 | return -ENOBUFS; | 1843 | return -ENOBUFS; |
1638 | } | 1844 | } |
@@ -1772,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1772 | { | 1978 | { |
1773 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1979 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1774 | struct vif_params params; | 1980 | struct vif_params params; |
1775 | struct net_device *dev; | 1981 | struct wireless_dev *wdev; |
1982 | struct sk_buff *msg; | ||
1776 | int err; | 1983 | int err; |
1777 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1984 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1778 | u32 flags; | 1985 | u32 flags; |
@@ -1799,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1799 | return err; | 2006 | return err; |
1800 | } | 2007 | } |
1801 | 2008 | ||
2009 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2010 | if (!msg) | ||
2011 | return -ENOMEM; | ||
2012 | |||
1802 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 2013 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1803 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 2014 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1804 | &flags); | 2015 | &flags); |
1805 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, | 2016 | wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1806 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2017 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1807 | type, err ? NULL : &flags, ¶ms); | 2018 | type, err ? NULL : &flags, ¶ms); |
1808 | if (IS_ERR(dev)) | 2019 | if (IS_ERR(wdev)) { |
1809 | return PTR_ERR(dev); | 2020 | nlmsg_free(msg); |
2021 | return PTR_ERR(wdev); | ||
2022 | } | ||
1810 | 2023 | ||
1811 | if (type == NL80211_IFTYPE_MESH_POINT && | 2024 | if (type == NL80211_IFTYPE_MESH_POINT && |
1812 | info->attrs[NL80211_ATTR_MESH_ID]) { | 2025 | info->attrs[NL80211_ATTR_MESH_ID]) { |
1813 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1814 | |||
1815 | wdev_lock(wdev); | 2026 | wdev_lock(wdev); |
1816 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | 2027 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != |
1817 | IEEE80211_MAX_MESH_ID_LEN); | 2028 | IEEE80211_MAX_MESH_ID_LEN); |
@@ -1822,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1822 | wdev_unlock(wdev); | 2033 | wdev_unlock(wdev); |
1823 | } | 2034 | } |
1824 | 2035 | ||
1825 | return 0; | 2036 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
2037 | rdev, wdev) < 0) { | ||
2038 | nlmsg_free(msg); | ||
2039 | return -ENOBUFS; | ||
2040 | } | ||
2041 | |||
2042 | return genlmsg_reply(msg, info); | ||
1826 | } | 2043 | } |
1827 | 2044 | ||
1828 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 2045 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1829 | { | 2046 | { |
1830 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2047 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1831 | struct net_device *dev = info->user_ptr[1]; | 2048 | struct wireless_dev *wdev = info->user_ptr[1]; |
1832 | 2049 | ||
1833 | if (!rdev->ops->del_virtual_intf) | 2050 | if (!rdev->ops->del_virtual_intf) |
1834 | return -EOPNOTSUPP; | 2051 | return -EOPNOTSUPP; |
1835 | 2052 | ||
1836 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | 2053 | /* |
2054 | * If we remove a wireless device without a netdev then clear | ||
2055 | * user_ptr[1] so that nl80211_post_doit won't dereference it | ||
2056 | * to check if it needs to do dev_put(). Otherwise it crashes | ||
2057 | * since the wdev has been freed, unlike with a netdev where | ||
2058 | * we need the dev_put() for the netdev to really be freed. | ||
2059 | */ | ||
2060 | if (!wdev->netdev) | ||
2061 | info->user_ptr[1] = NULL; | ||
2062 | |||
2063 | return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); | ||
1837 | } | 2064 | } |
1838 | 2065 | ||
1839 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) | 2066 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) |
@@ -2213,6 +2440,33 @@ static int nl80211_parse_beacon(struct genl_info *info, | |||
2213 | return 0; | 2440 | return 0; |
2214 | } | 2441 | } |
2215 | 2442 | ||
2443 | static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | ||
2444 | struct cfg80211_ap_settings *params) | ||
2445 | { | ||
2446 | struct wireless_dev *wdev; | ||
2447 | bool ret = false; | ||
2448 | |||
2449 | mutex_lock(&rdev->devlist_mtx); | ||
2450 | |||
2451 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
2452 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
2453 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
2454 | continue; | ||
2455 | |||
2456 | if (!wdev->preset_chan) | ||
2457 | continue; | ||
2458 | |||
2459 | params->channel = wdev->preset_chan; | ||
2460 | params->channel_type = wdev->preset_chantype; | ||
2461 | ret = true; | ||
2462 | break; | ||
2463 | } | ||
2464 | |||
2465 | mutex_unlock(&rdev->devlist_mtx); | ||
2466 | |||
2467 | return ret; | ||
2468 | } | ||
2469 | |||
2216 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | 2470 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) |
2217 | { | 2471 | { |
2218 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2472 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -2299,9 +2553,44 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2299 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); | 2553 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); |
2300 | } | 2554 | } |
2301 | 2555 | ||
2556 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2557 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
2558 | |||
2559 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
2560 | !nl80211_valid_channel_type(info, &channel_type)) | ||
2561 | return -EINVAL; | ||
2562 | |||
2563 | params.channel = rdev_freq_to_chan(rdev, | ||
2564 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
2565 | channel_type); | ||
2566 | if (!params.channel) | ||
2567 | return -EINVAL; | ||
2568 | params.channel_type = channel_type; | ||
2569 | } else if (wdev->preset_chan) { | ||
2570 | params.channel = wdev->preset_chan; | ||
2571 | params.channel_type = wdev->preset_chantype; | ||
2572 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) | ||
2573 | return -EINVAL; | ||
2574 | |||
2575 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, | ||
2576 | params.channel_type)) | ||
2577 | return -EINVAL; | ||
2578 | |||
2579 | mutex_lock(&rdev->devlist_mtx); | ||
2580 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2581 | CHAN_MODE_SHARED); | ||
2582 | mutex_unlock(&rdev->devlist_mtx); | ||
2583 | |||
2584 | if (err) | ||
2585 | return err; | ||
2586 | |||
2302 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2587 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2303 | if (!err) | 2588 | if (!err) { |
2589 | wdev->preset_chan = params.channel; | ||
2590 | wdev->preset_chantype = params.channel_type; | ||
2304 | wdev->beacon_interval = params.beacon_interval; | 2591 | wdev->beacon_interval = params.beacon_interval; |
2592 | wdev->channel = params.channel; | ||
2593 | } | ||
2305 | return err; | 2594 | return err; |
2306 | } | 2595 | } |
2307 | 2596 | ||
@@ -2334,23 +2623,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2334 | { | 2623 | { |
2335 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2624 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2336 | struct net_device *dev = info->user_ptr[1]; | 2625 | struct net_device *dev = info->user_ptr[1]; |
2337 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2338 | int err; | ||
2339 | 2626 | ||
2340 | if (!rdev->ops->stop_ap) | 2627 | return cfg80211_stop_ap(rdev, dev); |
2341 | return -EOPNOTSUPP; | ||
2342 | |||
2343 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2344 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2345 | return -EOPNOTSUPP; | ||
2346 | |||
2347 | if (!wdev->beacon_interval) | ||
2348 | return -ENOENT; | ||
2349 | |||
2350 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2351 | if (!err) | ||
2352 | wdev->beacon_interval = 0; | ||
2353 | return err; | ||
2354 | } | 2628 | } |
2355 | 2629 | ||
2356 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2630 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2442,7 +2716,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2442 | int attr) | 2716 | int attr) |
2443 | { | 2717 | { |
2444 | struct nlattr *rate; | 2718 | struct nlattr *rate; |
2445 | u16 bitrate; | 2719 | u32 bitrate; |
2720 | u16 bitrate_compat; | ||
2446 | 2721 | ||
2447 | rate = nla_nest_start(msg, attr); | 2722 | rate = nla_nest_start(msg, attr); |
2448 | if (!rate) | 2723 | if (!rate) |
@@ -2450,8 +2725,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2450 | 2725 | ||
2451 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2726 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2452 | bitrate = cfg80211_calculate_bitrate(info); | 2727 | bitrate = cfg80211_calculate_bitrate(info); |
2728 | /* report 16-bit bitrate only if we can */ | ||
2729 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2453 | if ((bitrate > 0 && | 2730 | if ((bitrate > 0 && |
2454 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2731 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2732 | (bitrate_compat > 0 && | ||
2733 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2455 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2734 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2456 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2735 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2457 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2736 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -3304,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3304 | { | 3583 | { |
3305 | int r; | 3584 | int r; |
3306 | char *data = NULL; | 3585 | char *data = NULL; |
3586 | enum nl80211_user_reg_hint_type user_reg_hint_type; | ||
3307 | 3587 | ||
3308 | /* | 3588 | /* |
3309 | * You should only get this when cfg80211 hasn't yet initialized | 3589 | * You should only get this when cfg80211 hasn't yet initialized |
@@ -3323,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3323 | 3603 | ||
3324 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3604 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3325 | 3605 | ||
3326 | r = regulatory_hint_user(data); | 3606 | if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) |
3607 | user_reg_hint_type = | ||
3608 | nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); | ||
3609 | else | ||
3610 | user_reg_hint_type = NL80211_USER_REG_HINT_USER; | ||
3611 | |||
3612 | switch (user_reg_hint_type) { | ||
3613 | case NL80211_USER_REG_HINT_USER: | ||
3614 | case NL80211_USER_REG_HINT_CELL_BASE: | ||
3615 | break; | ||
3616 | default: | ||
3617 | return -EINVAL; | ||
3618 | } | ||
3619 | |||
3620 | r = regulatory_hint_user(data, user_reg_hint_type); | ||
3327 | 3621 | ||
3328 | return r; | 3622 | return r; |
3329 | } | 3623 | } |
@@ -3413,7 +3707,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, | |||
3413 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, | 3707 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, |
3414 | cur_params.rssi_threshold) || | 3708 | cur_params.rssi_threshold) || |
3415 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, | 3709 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, |
3416 | cur_params.ht_opmode)) | 3710 | cur_params.ht_opmode) || |
3711 | nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3712 | cur_params.dot11MeshHWMPactivePathToRootTimeout) || | ||
3713 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3714 | cur_params.dot11MeshHWMProotInterval) || | ||
3715 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3716 | cur_params.dot11MeshHWMPconfirmationInterval)) | ||
3417 | goto nla_put_failure; | 3717 | goto nla_put_failure; |
3418 | nla_nest_end(msg, pinfoattr); | 3718 | nla_nest_end(msg, pinfoattr); |
3419 | genlmsg_end(msg, hdr); | 3719 | genlmsg_end(msg, hdr); |
@@ -3436,7 +3736,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3436 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, | 3736 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, |
3437 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 3737 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
3438 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, | 3738 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, |
3439 | |||
3440 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 3739 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
3441 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, | 3740 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, |
3442 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, | 3741 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, |
@@ -3448,8 +3747,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3448 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, | 3747 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, |
3449 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, | 3748 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, |
3450 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, | 3749 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, |
3451 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, | 3750 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 }, |
3452 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16}, | 3751 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 }, |
3752 | [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, | ||
3753 | [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, | ||
3754 | [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, | ||
3453 | }; | 3755 | }; |
3454 | 3756 | ||
3455 | static const struct nla_policy | 3757 | static const struct nla_policy |
@@ -3459,7 +3761,7 @@ static const struct nla_policy | |||
3459 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 3761 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
3460 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 3762 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
3461 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 3763 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
3462 | .len = IEEE80211_MAX_DATA_LEN }, | 3764 | .len = IEEE80211_MAX_DATA_LEN }, |
3463 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 3765 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
3464 | }; | 3766 | }; |
3465 | 3767 | ||
@@ -3492,63 +3794,82 @@ do {\ | |||
3492 | 3794 | ||
3493 | /* Fill in the params struct */ | 3795 | /* Fill in the params struct */ |
3494 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 3796 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
3495 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 3797 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, |
3798 | nla_get_u16); | ||
3496 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 3799 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
3497 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); | 3800 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, |
3801 | nla_get_u16); | ||
3498 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, | 3802 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, |
3499 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); | 3803 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, |
3804 | nla_get_u16); | ||
3500 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, | 3805 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, |
3501 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); | 3806 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, |
3807 | nla_get_u16); | ||
3502 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, | 3808 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, |
3503 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 3809 | mask, NL80211_MESHCONF_MAX_RETRIES, |
3810 | nla_get_u8); | ||
3504 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 3811 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
3505 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 3812 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
3506 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, | 3813 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, |
3507 | mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); | 3814 | mask, NL80211_MESHCONF_ELEMENT_TTL, |
3815 | nla_get_u8); | ||
3508 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 3816 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
3509 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 3817 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
3510 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, | 3818 | nla_get_u8); |
3511 | mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, | 3819 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask, |
3512 | nla_get_u32); | 3820 | NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, |
3821 | nla_get_u32); | ||
3513 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 3822 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
3514 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 3823 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
3515 | nla_get_u8); | 3824 | nla_get_u8); |
3516 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, | 3825 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, |
3517 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); | 3826 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, |
3827 | nla_get_u32); | ||
3518 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, | 3828 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, |
3519 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 3829 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
3520 | nla_get_u16); | 3830 | nla_get_u16); |
3521 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, | 3831 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask, |
3522 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 3832 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
3523 | nla_get_u32); | 3833 | nla_get_u32); |
3524 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, | 3834 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, |
3525 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 3835 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
3526 | nla_get_u16); | 3836 | nla_get_u16); |
3527 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, | 3837 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, |
3528 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, | 3838 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, |
3529 | nla_get_u16); | 3839 | nla_get_u16); |
3530 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3840 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3531 | dot11MeshHWMPnetDiameterTraversalTime, | 3841 | dot11MeshHWMPnetDiameterTraversalTime, mask, |
3532 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 3842 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
3533 | nla_get_u16); | 3843 | nla_get_u16); |
3844 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask, | ||
3845 | NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8); | ||
3846 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask, | ||
3847 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3848 | nla_get_u16); | ||
3534 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3849 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3535 | dot11MeshHWMPRootMode, mask, | 3850 | dot11MeshGateAnnouncementProtocol, mask, |
3536 | NL80211_MESHCONF_HWMP_ROOTMODE, | 3851 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, |
3537 | nla_get_u8); | 3852 | nla_get_u8); |
3538 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3539 | dot11MeshHWMPRannInterval, mask, | ||
3540 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3541 | nla_get_u16); | ||
3542 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3543 | dot11MeshGateAnnouncementProtocol, mask, | ||
3544 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, | ||
3545 | nla_get_u8); | ||
3546 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, | 3853 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, |
3547 | mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); | 3854 | mask, NL80211_MESHCONF_FORWARDING, |
3855 | nla_get_u8); | ||
3548 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, | 3856 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, |
3549 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); | 3857 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, |
3858 | nla_get_u32); | ||
3550 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, | 3859 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, |
3551 | mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16); | 3860 | mask, NL80211_MESHCONF_HT_OPMODE, |
3861 | nla_get_u16); | ||
3862 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout, | ||
3863 | mask, | ||
3864 | NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3865 | nla_get_u32); | ||
3866 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, | ||
3867 | mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3868 | nla_get_u16); | ||
3869 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3870 | dot11MeshHWMPconfirmationInterval, mask, | ||
3871 | NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3872 | nla_get_u16); | ||
3552 | if (mask_out) | 3873 | if (mask_out) |
3553 | *mask_out = mask; | 3874 | *mask_out = mask; |
3554 | 3875 | ||
@@ -3666,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3666 | cfg80211_regdomain->dfs_region))) | 3987 | cfg80211_regdomain->dfs_region))) |
3667 | goto nla_put_failure; | 3988 | goto nla_put_failure; |
3668 | 3989 | ||
3990 | if (reg_last_request_cell_base() && | ||
3991 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
3992 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
3993 | goto nla_put_failure; | ||
3994 | |||
3669 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3995 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3670 | if (!nl_reg_rules) | 3996 | if (!nl_reg_rules) |
3671 | goto nla_put_failure; | 3997 | goto nla_put_failure; |
@@ -3831,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3831 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 4157 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3832 | { | 4158 | { |
3833 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4159 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3834 | struct net_device *dev = info->user_ptr[1]; | 4160 | struct wireless_dev *wdev = info->user_ptr[1]; |
3835 | struct cfg80211_scan_request *request; | 4161 | struct cfg80211_scan_request *request; |
3836 | struct nlattr *attr; | 4162 | struct nlattr *attr; |
3837 | struct wiphy *wiphy; | 4163 | struct wiphy *wiphy; |
@@ -3991,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3991 | request->no_cck = | 4317 | request->no_cck = |
3992 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 4318 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
3993 | 4319 | ||
3994 | request->dev = dev; | 4320 | request->wdev = wdev; |
3995 | request->wiphy = &rdev->wiphy; | 4321 | request->wiphy = &rdev->wiphy; |
3996 | 4322 | ||
3997 | rdev->scan_req = request; | 4323 | rdev->scan_req = request; |
3998 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 4324 | err = rdev->ops->scan(&rdev->wiphy, request); |
3999 | 4325 | ||
4000 | if (!err) { | 4326 | if (!err) { |
4001 | nl80211_send_scan_start(rdev, dev); | 4327 | nl80211_send_scan_start(rdev, wdev); |
4002 | dev_hold(dev); | 4328 | if (wdev->netdev) |
4329 | dev_hold(wdev->netdev); | ||
4003 | } else { | 4330 | } else { |
4004 | out_free: | 4331 | out_free: |
4005 | rdev->scan_req = NULL; | 4332 | rdev->scan_req = NULL; |
@@ -4185,12 +4512,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4185 | nla_for_each_nested(attr, | 4512 | nla_for_each_nested(attr, |
4186 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 4513 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
4187 | tmp) { | 4514 | tmp) { |
4188 | struct nlattr *ssid; | 4515 | struct nlattr *ssid, *rssi; |
4189 | 4516 | ||
4190 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | 4517 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, |
4191 | nla_data(attr), nla_len(attr), | 4518 | nla_data(attr), nla_len(attr), |
4192 | nl80211_match_policy); | 4519 | nl80211_match_policy); |
4193 | ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID]; | 4520 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
4194 | if (ssid) { | 4521 | if (ssid) { |
4195 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 4522 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { |
4196 | err = -EINVAL; | 4523 | err = -EINVAL; |
@@ -4201,6 +4528,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4201 | request->match_sets[i].ssid.ssid_len = | 4528 | request->match_sets[i].ssid.ssid_len = |
4202 | nla_len(ssid); | 4529 | nla_len(ssid); |
4203 | } | 4530 | } |
4531 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
4532 | if (rssi) | ||
4533 | request->rssi_thold = nla_get_u32(rssi); | ||
4534 | else | ||
4535 | request->rssi_thold = | ||
4536 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
4204 | i++; | 4537 | i++; |
4205 | } | 4538 | } |
4206 | } | 4539 | } |
@@ -5058,21 +5391,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
5058 | nl80211_policy); | 5391 | nl80211_policy); |
5059 | if (err) | 5392 | if (err) |
5060 | return err; | 5393 | return err; |
5061 | if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) { | ||
5062 | phy_idx = nla_get_u32( | ||
5063 | nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
5064 | } else { | ||
5065 | struct net_device *netdev; | ||
5066 | 5394 | ||
5067 | err = get_rdev_dev_by_ifindex(sock_net(skb->sk), | 5395 | mutex_lock(&cfg80211_mutex); |
5068 | nl80211_fam.attrbuf, | 5396 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), |
5069 | &rdev, &netdev); | 5397 | nl80211_fam.attrbuf); |
5070 | if (err) | 5398 | if (IS_ERR(rdev)) { |
5071 | return err; | 5399 | mutex_unlock(&cfg80211_mutex); |
5072 | dev_put(netdev); | 5400 | return PTR_ERR(rdev); |
5073 | phy_idx = rdev->wiphy_idx; | ||
5074 | cfg80211_unlock_rdev(rdev); | ||
5075 | } | 5401 | } |
5402 | phy_idx = rdev->wiphy_idx; | ||
5403 | rdev = NULL; | ||
5404 | mutex_unlock(&cfg80211_mutex); | ||
5405 | |||
5076 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | 5406 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) |
5077 | cb->args[1] = | 5407 | cb->args[1] = |
5078 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | 5408 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; |
@@ -5474,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5474 | struct genl_info *info) | 5804 | struct genl_info *info) |
5475 | { | 5805 | { |
5476 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5806 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5477 | struct net_device *dev = info->user_ptr[1]; | 5807 | struct wireless_dev *wdev = info->user_ptr[1]; |
5478 | struct ieee80211_channel *chan; | 5808 | struct ieee80211_channel *chan; |
5479 | struct sk_buff *msg; | 5809 | struct sk_buff *msg; |
5480 | void *hdr; | 5810 | void *hdr; |
@@ -5489,18 +5819,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5489 | 5819 | ||
5490 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 5820 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
5491 | 5821 | ||
5822 | if (!rdev->ops->remain_on_channel || | ||
5823 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5824 | return -EOPNOTSUPP; | ||
5825 | |||
5492 | /* | 5826 | /* |
5493 | * We should be on that channel for at least one jiffie, | 5827 | * We should be on that channel for at least a minimum amount of |
5494 | * and more than 5 seconds seems excessive. | 5828 | * time (10ms) but no longer than the driver supports. |
5495 | */ | 5829 | */ |
5496 | if (!duration || !msecs_to_jiffies(duration) || | 5830 | if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || |
5497 | duration > rdev->wiphy.max_remain_on_channel_duration) | 5831 | duration > rdev->wiphy.max_remain_on_channel_duration) |
5498 | return -EINVAL; | 5832 | return -EINVAL; |
5499 | 5833 | ||
5500 | if (!rdev->ops->remain_on_channel || | ||
5501 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5502 | return -EOPNOTSUPP; | ||
5503 | |||
5504 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 5834 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && |
5505 | !nl80211_valid_channel_type(info, &channel_type)) | 5835 | !nl80211_valid_channel_type(info, &channel_type)) |
5506 | return -EINVAL; | 5836 | return -EINVAL; |
@@ -5522,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5522 | goto free_msg; | 5852 | goto free_msg; |
5523 | } | 5853 | } |
5524 | 5854 | ||
5525 | err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | 5855 | err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, |
5526 | channel_type, duration, &cookie); | 5856 | channel_type, duration, &cookie); |
5527 | 5857 | ||
5528 | if (err) | 5858 | if (err) |
@@ -5546,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5546 | struct genl_info *info) | 5876 | struct genl_info *info) |
5547 | { | 5877 | { |
5548 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5878 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5549 | struct net_device *dev = info->user_ptr[1]; | 5879 | struct wireless_dev *wdev = info->user_ptr[1]; |
5550 | u64 cookie; | 5880 | u64 cookie; |
5551 | 5881 | ||
5552 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 5882 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5557,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5557 | 5887 | ||
5558 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 5888 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5559 | 5889 | ||
5560 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 5890 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); |
5561 | } | 5891 | } |
5562 | 5892 | ||
5563 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 5893 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -5706,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
5706 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | 6036 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
5707 | { | 6037 | { |
5708 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6038 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5709 | struct net_device *dev = info->user_ptr[1]; | 6039 | struct wireless_dev *wdev = info->user_ptr[1]; |
5710 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 6040 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
5711 | 6041 | ||
5712 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 6042 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
@@ -5715,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5715 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 6045 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
5716 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 6046 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
5717 | 6047 | ||
5718 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6048 | switch (wdev->iftype) { |
5719 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6049 | case NL80211_IFTYPE_STATION: |
5720 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6050 | case NL80211_IFTYPE_ADHOC: |
5721 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6051 | case NL80211_IFTYPE_P2P_CLIENT: |
5722 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6052 | case NL80211_IFTYPE_AP: |
5723 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6053 | case NL80211_IFTYPE_AP_VLAN: |
5724 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6054 | case NL80211_IFTYPE_MESH_POINT: |
6055 | case NL80211_IFTYPE_P2P_GO: | ||
6056 | break; | ||
6057 | default: | ||
5725 | return -EOPNOTSUPP; | 6058 | return -EOPNOTSUPP; |
6059 | } | ||
5726 | 6060 | ||
5727 | /* not much point in registering if we can't reply */ | 6061 | /* not much point in registering if we can't reply */ |
5728 | if (!rdev->ops->mgmt_tx) | 6062 | if (!rdev->ops->mgmt_tx) |
5729 | return -EOPNOTSUPP; | 6063 | return -EOPNOTSUPP; |
5730 | 6064 | ||
5731 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 6065 | return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, |
5732 | frame_type, | ||
5733 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 6066 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
5734 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 6067 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
5735 | } | 6068 | } |
@@ -5737,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5737 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | 6070 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
5738 | { | 6071 | { |
5739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6072 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5740 | struct net_device *dev = info->user_ptr[1]; | 6073 | struct wireless_dev *wdev = info->user_ptr[1]; |
5741 | struct ieee80211_channel *chan; | 6074 | struct ieee80211_channel *chan; |
5742 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6075 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
5743 | bool channel_type_valid = false; | 6076 | bool channel_type_valid = false; |
@@ -5758,19 +6091,32 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5758 | if (!rdev->ops->mgmt_tx) | 6091 | if (!rdev->ops->mgmt_tx) |
5759 | return -EOPNOTSUPP; | 6092 | return -EOPNOTSUPP; |
5760 | 6093 | ||
5761 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6094 | switch (wdev->iftype) { |
5762 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6095 | case NL80211_IFTYPE_STATION: |
5763 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6096 | case NL80211_IFTYPE_ADHOC: |
5764 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6097 | case NL80211_IFTYPE_P2P_CLIENT: |
5765 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6098 | case NL80211_IFTYPE_AP: |
5766 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6099 | case NL80211_IFTYPE_AP_VLAN: |
5767 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6100 | case NL80211_IFTYPE_MESH_POINT: |
6101 | case NL80211_IFTYPE_P2P_GO: | ||
6102 | break; | ||
6103 | default: | ||
5768 | return -EOPNOTSUPP; | 6104 | return -EOPNOTSUPP; |
6105 | } | ||
5769 | 6106 | ||
5770 | if (info->attrs[NL80211_ATTR_DURATION]) { | 6107 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5771 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 6108 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
5772 | return -EINVAL; | 6109 | return -EINVAL; |
5773 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 6110 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
6111 | |||
6112 | /* | ||
6113 | * We should wait on the channel for at least a minimum amount | ||
6114 | * of time (10ms) but no longer than the driver supports. | ||
6115 | */ | ||
6116 | if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || | ||
6117 | wait > rdev->wiphy.max_remain_on_channel_duration) | ||
6118 | return -EINVAL; | ||
6119 | |||
5774 | } | 6120 | } |
5775 | 6121 | ||
5776 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 6122 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -5805,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5805 | } | 6151 | } |
5806 | } | 6152 | } |
5807 | 6153 | ||
5808 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, | 6154 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, |
5809 | channel_type_valid, wait, | 6155 | channel_type_valid, wait, |
5810 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 6156 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
5811 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 6157 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
@@ -5833,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5833 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) | 6179 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) |
5834 | { | 6180 | { |
5835 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6181 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5836 | struct net_device *dev = info->user_ptr[1]; | 6182 | struct wireless_dev *wdev = info->user_ptr[1]; |
5837 | u64 cookie; | 6183 | u64 cookie; |
5838 | 6184 | ||
5839 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 6185 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5842,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in | |||
5842 | if (!rdev->ops->mgmt_tx_cancel_wait) | 6188 | if (!rdev->ops->mgmt_tx_cancel_wait) |
5843 | return -EOPNOTSUPP; | 6189 | return -EOPNOTSUPP; |
5844 | 6190 | ||
5845 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6191 | switch (wdev->iftype) { |
5846 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6192 | case NL80211_IFTYPE_STATION: |
5847 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6193 | case NL80211_IFTYPE_ADHOC: |
5848 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6194 | case NL80211_IFTYPE_P2P_CLIENT: |
5849 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6195 | case NL80211_IFTYPE_AP: |
5850 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6196 | case NL80211_IFTYPE_AP_VLAN: |
6197 | case NL80211_IFTYPE_P2P_GO: | ||
6198 | break; | ||
6199 | default: | ||
5851 | return -EOPNOTSUPP; | 6200 | return -EOPNOTSUPP; |
6201 | } | ||
5852 | 6202 | ||
5853 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 6203 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5854 | 6204 | ||
5855 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); | 6205 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); |
5856 | } | 6206 | } |
5857 | 6207 | ||
5858 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 6208 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
@@ -5938,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
5938 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 6288 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
5939 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 6289 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
5940 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 6290 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
6291 | [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, | ||
6292 | [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, | ||
6293 | [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, | ||
5941 | }; | 6294 | }; |
5942 | 6295 | ||
6296 | static int nl80211_set_cqm_txe(struct genl_info *info, | ||
6297 | u32 rate, u32 pkts, u32 intvl) | ||
6298 | { | ||
6299 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6300 | struct wireless_dev *wdev; | ||
6301 | struct net_device *dev = info->user_ptr[1]; | ||
6302 | |||
6303 | if ((rate < 0 || rate > 100) || | ||
6304 | (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) | ||
6305 | return -EINVAL; | ||
6306 | |||
6307 | wdev = dev->ieee80211_ptr; | ||
6308 | |||
6309 | if (!rdev->ops->set_cqm_txe_config) | ||
6310 | return -EOPNOTSUPP; | ||
6311 | |||
6312 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
6313 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
6314 | return -EOPNOTSUPP; | ||
6315 | |||
6316 | return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, | ||
6317 | rate, pkts, intvl); | ||
6318 | } | ||
6319 | |||
5943 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 6320 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
5944 | s32 threshold, u32 hysteresis) | 6321 | s32 threshold, u32 hysteresis) |
5945 | { | 6322 | { |
@@ -5987,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
5987 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | 6364 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); |
5988 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | 6365 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
5989 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | 6366 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); |
6367 | } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && | ||
6368 | attrs[NL80211_ATTR_CQM_TXE_PKTS] && | ||
6369 | attrs[NL80211_ATTR_CQM_TXE_INTVL]) { | ||
6370 | u32 rate, pkts, intvl; | ||
6371 | rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); | ||
6372 | pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); | ||
6373 | intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); | ||
6374 | err = nl80211_set_cqm_txe(info, rate, pkts, intvl); | ||
5990 | } else | 6375 | } else |
5991 | err = -EINVAL; | 6376 | err = -EINVAL; |
5992 | 6377 | ||
@@ -6032,6 +6417,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6032 | return err; | 6417 | return err; |
6033 | } | 6418 | } |
6034 | 6419 | ||
6420 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
6421 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
6422 | |||
6423 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
6424 | !nl80211_valid_channel_type(info, &channel_type)) | ||
6425 | return -EINVAL; | ||
6426 | |||
6427 | setup.channel = rdev_freq_to_chan(rdev, | ||
6428 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
6429 | channel_type); | ||
6430 | if (!setup.channel) | ||
6431 | return -EINVAL; | ||
6432 | setup.channel_type = channel_type; | ||
6433 | } else { | ||
6434 | /* cfg80211_join_mesh() will sort it out */ | ||
6435 | setup.channel = NULL; | ||
6436 | } | ||
6437 | |||
6035 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 6438 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
6036 | } | 6439 | } |
6037 | 6440 | ||
@@ -6043,6 +6446,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6043 | return cfg80211_leave_mesh(rdev, dev); | 6446 | return cfg80211_leave_mesh(rdev, dev); |
6044 | } | 6447 | } |
6045 | 6448 | ||
6449 | #ifdef CONFIG_PM | ||
6046 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6450 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6047 | { | 6451 | { |
6048 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6452 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6124,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6124 | { | 6528 | { |
6125 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6529 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6126 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | 6530 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; |
6127 | struct cfg80211_wowlan no_triggers = {}; | ||
6128 | struct cfg80211_wowlan new_triggers = {}; | 6531 | struct cfg80211_wowlan new_triggers = {}; |
6532 | struct cfg80211_wowlan *ntrig; | ||
6129 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 6533 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; |
6130 | int err, i; | 6534 | int err, i; |
6131 | bool prev_enabled = rdev->wowlan; | 6535 | bool prev_enabled = rdev->wowlan; |
@@ -6133,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6133 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 6537 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) |
6134 | return -EOPNOTSUPP; | 6538 | return -EOPNOTSUPP; |
6135 | 6539 | ||
6136 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | 6540 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
6137 | goto no_triggers; | 6541 | cfg80211_rdev_free_wowlan(rdev); |
6542 | rdev->wowlan = NULL; | ||
6543 | goto set_wakeup; | ||
6544 | } | ||
6138 | 6545 | ||
6139 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | 6546 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, |
6140 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | 6547 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
@@ -6245,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6245 | } | 6652 | } |
6246 | } | 6653 | } |
6247 | 6654 | ||
6248 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | 6655 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
6249 | struct cfg80211_wowlan *ntrig; | 6656 | if (!ntrig) { |
6250 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | 6657 | err = -ENOMEM; |
6251 | GFP_KERNEL); | 6658 | goto error; |
6252 | if (!ntrig) { | ||
6253 | err = -ENOMEM; | ||
6254 | goto error; | ||
6255 | } | ||
6256 | cfg80211_rdev_free_wowlan(rdev); | ||
6257 | rdev->wowlan = ntrig; | ||
6258 | } else { | ||
6259 | no_triggers: | ||
6260 | cfg80211_rdev_free_wowlan(rdev); | ||
6261 | rdev->wowlan = NULL; | ||
6262 | } | 6659 | } |
6660 | cfg80211_rdev_free_wowlan(rdev); | ||
6661 | rdev->wowlan = ntrig; | ||
6263 | 6662 | ||
6663 | set_wakeup: | ||
6264 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) | 6664 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) |
6265 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); | 6665 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); |
6266 | 6666 | ||
@@ -6271,6 +6671,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6271 | kfree(new_triggers.patterns); | 6671 | kfree(new_triggers.patterns); |
6272 | return err; | 6672 | return err; |
6273 | } | 6673 | } |
6674 | #endif | ||
6274 | 6675 | ||
6275 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6676 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6276 | { | 6677 | { |
@@ -6415,44 +6816,75 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | |||
6415 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | 6816 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 |
6416 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | 6817 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ |
6417 | NL80211_FLAG_CHECK_NETDEV_UP) | 6818 | NL80211_FLAG_CHECK_NETDEV_UP) |
6819 | #define NL80211_FLAG_NEED_WDEV 0x10 | ||
6820 | /* If a netdev is associated, it must be UP */ | ||
6821 | #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ | ||
6822 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
6418 | 6823 | ||
6419 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | 6824 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, |
6420 | struct genl_info *info) | 6825 | struct genl_info *info) |
6421 | { | 6826 | { |
6422 | struct cfg80211_registered_device *rdev; | 6827 | struct cfg80211_registered_device *rdev; |
6828 | struct wireless_dev *wdev; | ||
6423 | struct net_device *dev; | 6829 | struct net_device *dev; |
6424 | int err; | ||
6425 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | 6830 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; |
6426 | 6831 | ||
6427 | if (rtnl) | 6832 | if (rtnl) |
6428 | rtnl_lock(); | 6833 | rtnl_lock(); |
6429 | 6834 | ||
6430 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | 6835 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { |
6431 | rdev = cfg80211_get_dev_from_info(info); | 6836 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); |
6432 | if (IS_ERR(rdev)) { | 6837 | if (IS_ERR(rdev)) { |
6433 | if (rtnl) | 6838 | if (rtnl) |
6434 | rtnl_unlock(); | 6839 | rtnl_unlock(); |
6435 | return PTR_ERR(rdev); | 6840 | return PTR_ERR(rdev); |
6436 | } | 6841 | } |
6437 | info->user_ptr[0] = rdev; | 6842 | info->user_ptr[0] = rdev; |
6438 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 6843 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
6439 | err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, | 6844 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6440 | &rdev, &dev); | 6845 | mutex_lock(&cfg80211_mutex); |
6441 | if (err) { | 6846 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
6847 | info->attrs); | ||
6848 | if (IS_ERR(wdev)) { | ||
6849 | mutex_unlock(&cfg80211_mutex); | ||
6442 | if (rtnl) | 6850 | if (rtnl) |
6443 | rtnl_unlock(); | 6851 | rtnl_unlock(); |
6444 | return err; | 6852 | return PTR_ERR(wdev); |
6445 | } | 6853 | } |
6446 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 6854 | |
6447 | !netif_running(dev)) { | 6855 | dev = wdev->netdev; |
6448 | cfg80211_unlock_rdev(rdev); | 6856 | rdev = wiphy_to_dev(wdev->wiphy); |
6449 | dev_put(dev); | 6857 | |
6450 | if (rtnl) | 6858 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
6451 | rtnl_unlock(); | 6859 | if (!dev) { |
6452 | return -ENETDOWN; | 6860 | mutex_unlock(&cfg80211_mutex); |
6861 | if (rtnl) | ||
6862 | rtnl_unlock(); | ||
6863 | return -EINVAL; | ||
6864 | } | ||
6865 | |||
6866 | info->user_ptr[1] = dev; | ||
6867 | } else { | ||
6868 | info->user_ptr[1] = wdev; | ||
6453 | } | 6869 | } |
6870 | |||
6871 | if (dev) { | ||
6872 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
6873 | !netif_running(dev)) { | ||
6874 | mutex_unlock(&cfg80211_mutex); | ||
6875 | if (rtnl) | ||
6876 | rtnl_unlock(); | ||
6877 | return -ENETDOWN; | ||
6878 | } | ||
6879 | |||
6880 | dev_hold(dev); | ||
6881 | } | ||
6882 | |||
6883 | cfg80211_lock_rdev(rdev); | ||
6884 | |||
6885 | mutex_unlock(&cfg80211_mutex); | ||
6886 | |||
6454 | info->user_ptr[0] = rdev; | 6887 | info->user_ptr[0] = rdev; |
6455 | info->user_ptr[1] = dev; | ||
6456 | } | 6888 | } |
6457 | 6889 | ||
6458 | return 0; | 6890 | return 0; |
@@ -6463,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6463 | { | 6895 | { |
6464 | if (info->user_ptr[0]) | 6896 | if (info->user_ptr[0]) |
6465 | cfg80211_unlock_rdev(info->user_ptr[0]); | 6897 | cfg80211_unlock_rdev(info->user_ptr[0]); |
6466 | if (info->user_ptr[1]) | 6898 | if (info->user_ptr[1]) { |
6467 | dev_put(info->user_ptr[1]); | 6899 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6900 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
6901 | |||
6902 | if (wdev->netdev) | ||
6903 | dev_put(wdev->netdev); | ||
6904 | } else { | ||
6905 | dev_put(info->user_ptr[1]); | ||
6906 | } | ||
6907 | } | ||
6468 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | 6908 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) |
6469 | rtnl_unlock(); | 6909 | rtnl_unlock(); |
6470 | } | 6910 | } |
@@ -6491,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6491 | .dumpit = nl80211_dump_interface, | 6931 | .dumpit = nl80211_dump_interface, |
6492 | .policy = nl80211_policy, | 6932 | .policy = nl80211_policy, |
6493 | /* can be retrieved by unprivileged users */ | 6933 | /* can be retrieved by unprivileged users */ |
6494 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | 6934 | .internal_flags = NL80211_FLAG_NEED_WDEV, |
6495 | }, | 6935 | }, |
6496 | { | 6936 | { |
6497 | .cmd = NL80211_CMD_SET_INTERFACE, | 6937 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -6514,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6514 | .doit = nl80211_del_interface, | 6954 | .doit = nl80211_del_interface, |
6515 | .policy = nl80211_policy, | 6955 | .policy = nl80211_policy, |
6516 | .flags = GENL_ADMIN_PERM, | 6956 | .flags = GENL_ADMIN_PERM, |
6517 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 6957 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6518 | NL80211_FLAG_NEED_RTNL, | 6958 | NL80211_FLAG_NEED_RTNL, |
6519 | }, | 6959 | }, |
6520 | { | 6960 | { |
@@ -6685,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6685 | .doit = nl80211_trigger_scan, | 7125 | .doit = nl80211_trigger_scan, |
6686 | .policy = nl80211_policy, | 7126 | .policy = nl80211_policy, |
6687 | .flags = GENL_ADMIN_PERM, | 7127 | .flags = GENL_ADMIN_PERM, |
6688 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7128 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6689 | NL80211_FLAG_NEED_RTNL, | 7129 | NL80211_FLAG_NEED_RTNL, |
6690 | }, | 7130 | }, |
6691 | { | 7131 | { |
@@ -6826,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6826 | .doit = nl80211_remain_on_channel, | 7266 | .doit = nl80211_remain_on_channel, |
6827 | .policy = nl80211_policy, | 7267 | .policy = nl80211_policy, |
6828 | .flags = GENL_ADMIN_PERM, | 7268 | .flags = GENL_ADMIN_PERM, |
6829 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7269 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6830 | NL80211_FLAG_NEED_RTNL, | 7270 | NL80211_FLAG_NEED_RTNL, |
6831 | }, | 7271 | }, |
6832 | { | 7272 | { |
@@ -6834,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6834 | .doit = nl80211_cancel_remain_on_channel, | 7274 | .doit = nl80211_cancel_remain_on_channel, |
6835 | .policy = nl80211_policy, | 7275 | .policy = nl80211_policy, |
6836 | .flags = GENL_ADMIN_PERM, | 7276 | .flags = GENL_ADMIN_PERM, |
6837 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7277 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6838 | NL80211_FLAG_NEED_RTNL, | 7278 | NL80211_FLAG_NEED_RTNL, |
6839 | }, | 7279 | }, |
6840 | { | 7280 | { |
@@ -6850,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6850 | .doit = nl80211_register_mgmt, | 7290 | .doit = nl80211_register_mgmt, |
6851 | .policy = nl80211_policy, | 7291 | .policy = nl80211_policy, |
6852 | .flags = GENL_ADMIN_PERM, | 7292 | .flags = GENL_ADMIN_PERM, |
6853 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 7293 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6854 | NL80211_FLAG_NEED_RTNL, | 7294 | NL80211_FLAG_NEED_RTNL, |
6855 | }, | 7295 | }, |
6856 | { | 7296 | { |
@@ -6858,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6858 | .doit = nl80211_tx_mgmt, | 7298 | .doit = nl80211_tx_mgmt, |
6859 | .policy = nl80211_policy, | 7299 | .policy = nl80211_policy, |
6860 | .flags = GENL_ADMIN_PERM, | 7300 | .flags = GENL_ADMIN_PERM, |
6861 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7301 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6862 | NL80211_FLAG_NEED_RTNL, | 7302 | NL80211_FLAG_NEED_RTNL, |
6863 | }, | 7303 | }, |
6864 | { | 7304 | { |
@@ -6866,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6866 | .doit = nl80211_tx_mgmt_cancel_wait, | 7306 | .doit = nl80211_tx_mgmt_cancel_wait, |
6867 | .policy = nl80211_policy, | 7307 | .policy = nl80211_policy, |
6868 | .flags = GENL_ADMIN_PERM, | 7308 | .flags = GENL_ADMIN_PERM, |
6869 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7309 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6870 | NL80211_FLAG_NEED_RTNL, | 7310 | NL80211_FLAG_NEED_RTNL, |
6871 | }, | 7311 | }, |
6872 | { | 7312 | { |
@@ -6925,6 +7365,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6925 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7365 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6926 | NL80211_FLAG_NEED_RTNL, | 7366 | NL80211_FLAG_NEED_RTNL, |
6927 | }, | 7367 | }, |
7368 | #ifdef CONFIG_PM | ||
6928 | { | 7369 | { |
6929 | .cmd = NL80211_CMD_GET_WOWLAN, | 7370 | .cmd = NL80211_CMD_GET_WOWLAN, |
6930 | .doit = nl80211_get_wowlan, | 7371 | .doit = nl80211_get_wowlan, |
@@ -6941,6 +7382,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6941 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7382 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
6942 | NL80211_FLAG_NEED_RTNL, | 7383 | NL80211_FLAG_NEED_RTNL, |
6943 | }, | 7384 | }, |
7385 | #endif | ||
6944 | { | 7386 | { |
6945 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7387 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
6946 | .doit = nl80211_set_rekey_data, | 7388 | .doit = nl80211_set_rekey_data, |
@@ -7075,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
7075 | 7517 | ||
7076 | static int nl80211_send_scan_msg(struct sk_buff *msg, | 7518 | static int nl80211_send_scan_msg(struct sk_buff *msg, |
7077 | struct cfg80211_registered_device *rdev, | 7519 | struct cfg80211_registered_device *rdev, |
7078 | struct net_device *netdev, | 7520 | struct wireless_dev *wdev, |
7079 | u32 pid, u32 seq, int flags, | 7521 | u32 pid, u32 seq, int flags, |
7080 | u32 cmd) | 7522 | u32 cmd) |
7081 | { | 7523 | { |
@@ -7086,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
7086 | return -1; | 7528 | return -1; |
7087 | 7529 | ||
7088 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 7530 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7089 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 7531 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
7532 | wdev->netdev->ifindex)) || | ||
7533 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
7090 | goto nla_put_failure; | 7534 | goto nla_put_failure; |
7091 | 7535 | ||
7092 | /* ignore errors and send incomplete event anyway */ | 7536 | /* ignore errors and send incomplete event anyway */ |
@@ -7123,15 +7567,15 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, | |||
7123 | } | 7567 | } |
7124 | 7568 | ||
7125 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 7569 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
7126 | struct net_device *netdev) | 7570 | struct wireless_dev *wdev) |
7127 | { | 7571 | { |
7128 | struct sk_buff *msg; | 7572 | struct sk_buff *msg; |
7129 | 7573 | ||
7130 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7574 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7131 | if (!msg) | 7575 | if (!msg) |
7132 | return; | 7576 | return; |
7133 | 7577 | ||
7134 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7578 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7135 | NL80211_CMD_TRIGGER_SCAN) < 0) { | 7579 | NL80211_CMD_TRIGGER_SCAN) < 0) { |
7136 | nlmsg_free(msg); | 7580 | nlmsg_free(msg); |
7137 | return; | 7581 | return; |
@@ -7142,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
7142 | } | 7586 | } |
7143 | 7587 | ||
7144 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 7588 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
7145 | struct net_device *netdev) | 7589 | struct wireless_dev *wdev) |
7146 | { | 7590 | { |
7147 | struct sk_buff *msg; | 7591 | struct sk_buff *msg; |
7148 | 7592 | ||
@@ -7150,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7150 | if (!msg) | 7594 | if (!msg) |
7151 | return; | 7595 | return; |
7152 | 7596 | ||
7153 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7597 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7154 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | 7598 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { |
7155 | nlmsg_free(msg); | 7599 | nlmsg_free(msg); |
7156 | return; | 7600 | return; |
@@ -7161,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7161 | } | 7605 | } |
7162 | 7606 | ||
7163 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 7607 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
7164 | struct net_device *netdev) | 7608 | struct wireless_dev *wdev) |
7165 | { | 7609 | { |
7166 | struct sk_buff *msg; | 7610 | struct sk_buff *msg; |
7167 | 7611 | ||
@@ -7169,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
7169 | if (!msg) | 7613 | if (!msg) |
7170 | return; | 7614 | return; |
7171 | 7615 | ||
7172 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7616 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7173 | NL80211_CMD_SCAN_ABORTED) < 0) { | 7617 | NL80211_CMD_SCAN_ABORTED) < 0) { |
7174 | nlmsg_free(msg); | 7618 | nlmsg_free(msg); |
7175 | return; | 7619 | return; |
@@ -7203,7 +7647,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
7203 | { | 7647 | { |
7204 | struct sk_buff *msg; | 7648 | struct sk_buff *msg; |
7205 | 7649 | ||
7206 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7650 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7207 | if (!msg) | 7651 | if (!msg) |
7208 | return; | 7652 | return; |
7209 | 7653 | ||
@@ -7419,7 +7863,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
7419 | struct sk_buff *msg; | 7863 | struct sk_buff *msg; |
7420 | void *hdr; | 7864 | void *hdr; |
7421 | 7865 | ||
7422 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7866 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7423 | if (!msg) | 7867 | if (!msg) |
7424 | return; | 7868 | return; |
7425 | 7869 | ||
@@ -7459,7 +7903,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
7459 | struct sk_buff *msg; | 7903 | struct sk_buff *msg; |
7460 | void *hdr; | 7904 | void *hdr; |
7461 | 7905 | ||
7462 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7906 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7463 | if (!msg) | 7907 | if (!msg) |
7464 | return; | 7908 | return; |
7465 | 7909 | ||
@@ -7497,7 +7941,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
7497 | struct sk_buff *msg; | 7941 | struct sk_buff *msg; |
7498 | void *hdr; | 7942 | void *hdr; |
7499 | 7943 | ||
7500 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7944 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7501 | if (!msg) | 7945 | if (!msg) |
7502 | return; | 7946 | return; |
7503 | 7947 | ||
@@ -7692,7 +8136,7 @@ nla_put_failure: | |||
7692 | 8136 | ||
7693 | static void nl80211_send_remain_on_chan_event( | 8137 | static void nl80211_send_remain_on_chan_event( |
7694 | int cmd, struct cfg80211_registered_device *rdev, | 8138 | int cmd, struct cfg80211_registered_device *rdev, |
7695 | struct net_device *netdev, u64 cookie, | 8139 | struct wireless_dev *wdev, u64 cookie, |
7696 | struct ieee80211_channel *chan, | 8140 | struct ieee80211_channel *chan, |
7697 | enum nl80211_channel_type channel_type, | 8141 | enum nl80211_channel_type channel_type, |
7698 | unsigned int duration, gfp_t gfp) | 8142 | unsigned int duration, gfp_t gfp) |
@@ -7711,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event( | |||
7711 | } | 8155 | } |
7712 | 8156 | ||
7713 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8157 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7714 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8158 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8159 | wdev->netdev->ifindex)) || | ||
8160 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
7715 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || | 8161 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || |
7716 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || | 8162 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || |
7717 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) | 8163 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) |
@@ -7733,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event( | |||
7733 | } | 8179 | } |
7734 | 8180 | ||
7735 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 8181 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
7736 | struct net_device *netdev, u64 cookie, | 8182 | struct wireless_dev *wdev, u64 cookie, |
7737 | struct ieee80211_channel *chan, | 8183 | struct ieee80211_channel *chan, |
7738 | enum nl80211_channel_type channel_type, | 8184 | enum nl80211_channel_type channel_type, |
7739 | unsigned int duration, gfp_t gfp) | 8185 | unsigned int duration, gfp_t gfp) |
7740 | { | 8186 | { |
7741 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 8187 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
7742 | rdev, netdev, cookie, chan, | 8188 | rdev, wdev, cookie, chan, |
7743 | channel_type, duration, gfp); | 8189 | channel_type, duration, gfp); |
7744 | } | 8190 | } |
7745 | 8191 | ||
7746 | void nl80211_send_remain_on_channel_cancel( | 8192 | void nl80211_send_remain_on_channel_cancel( |
7747 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | 8193 | struct cfg80211_registered_device *rdev, |
8194 | struct wireless_dev *wdev, | ||
7748 | u64 cookie, struct ieee80211_channel *chan, | 8195 | u64 cookie, struct ieee80211_channel *chan, |
7749 | enum nl80211_channel_type channel_type, gfp_t gfp) | 8196 | enum nl80211_channel_type channel_type, gfp_t gfp) |
7750 | { | 8197 | { |
7751 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 8198 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
7752 | rdev, netdev, cookie, chan, | 8199 | rdev, wdev, cookie, chan, |
7753 | channel_type, 0, gfp); | 8200 | channel_type, 0, gfp); |
7754 | } | 8201 | } |
7755 | 8202 | ||
@@ -7759,7 +8206,7 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
7759 | { | 8206 | { |
7760 | struct sk_buff *msg; | 8207 | struct sk_buff *msg; |
7761 | 8208 | ||
7762 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8209 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7763 | if (!msg) | 8210 | if (!msg) |
7764 | return; | 8211 | return; |
7765 | 8212 | ||
@@ -7780,7 +8227,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7780 | struct sk_buff *msg; | 8227 | struct sk_buff *msg; |
7781 | void *hdr; | 8228 | void *hdr; |
7782 | 8229 | ||
7783 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8230 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7784 | if (!msg) | 8231 | if (!msg) |
7785 | return; | 8232 | return; |
7786 | 8233 | ||
@@ -7863,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, | |||
7863 | } | 8310 | } |
7864 | 8311 | ||
7865 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 8312 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
7866 | struct net_device *netdev, u32 nlpid, | 8313 | struct wireless_dev *wdev, u32 nlpid, |
7867 | int freq, int sig_dbm, | 8314 | int freq, int sig_dbm, |
7868 | const u8 *buf, size_t len, gfp_t gfp) | 8315 | const u8 *buf, size_t len, gfp_t gfp) |
7869 | { | 8316 | { |
8317 | struct net_device *netdev = wdev->netdev; | ||
7870 | struct sk_buff *msg; | 8318 | struct sk_buff *msg; |
7871 | void *hdr; | 8319 | void *hdr; |
7872 | 8320 | ||
@@ -7881,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7881 | } | 8329 | } |
7882 | 8330 | ||
7883 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8331 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7884 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8332 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8333 | netdev->ifindex)) || | ||
7885 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || | 8334 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || |
7886 | (sig_dbm && | 8335 | (sig_dbm && |
7887 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 8336 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
@@ -7899,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7899 | } | 8348 | } |
7900 | 8349 | ||
7901 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 8350 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
7902 | struct net_device *netdev, u64 cookie, | 8351 | struct wireless_dev *wdev, u64 cookie, |
7903 | const u8 *buf, size_t len, bool ack, | 8352 | const u8 *buf, size_t len, bool ack, |
7904 | gfp_t gfp) | 8353 | gfp_t gfp) |
7905 | { | 8354 | { |
8355 | struct net_device *netdev = wdev->netdev; | ||
7906 | struct sk_buff *msg; | 8356 | struct sk_buff *msg; |
7907 | void *hdr; | 8357 | void *hdr; |
7908 | 8358 | ||
@@ -7917,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
7917 | } | 8367 | } |
7918 | 8368 | ||
7919 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8369 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7920 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8370 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8371 | netdev->ifindex)) || | ||
7921 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || | 8372 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || |
7922 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || | 8373 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || |
7923 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) | 8374 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) |
@@ -7943,7 +8394,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
7943 | struct nlattr *pinfoattr; | 8394 | struct nlattr *pinfoattr; |
7944 | void *hdr; | 8395 | void *hdr; |
7945 | 8396 | ||
7946 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8397 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7947 | if (!msg) | 8398 | if (!msg) |
7948 | return; | 8399 | return; |
7949 | 8400 | ||
@@ -7986,7 +8437,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
7986 | struct nlattr *rekey_attr; | 8437 | struct nlattr *rekey_attr; |
7987 | void *hdr; | 8438 | void *hdr; |
7988 | 8439 | ||
7989 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8440 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7990 | if (!msg) | 8441 | if (!msg) |
7991 | return; | 8442 | return; |
7992 | 8443 | ||
@@ -8030,7 +8481,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
8030 | struct nlattr *attr; | 8481 | struct nlattr *attr; |
8031 | void *hdr; | 8482 | void *hdr; |
8032 | 8483 | ||
8033 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8484 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8034 | if (!msg) | 8485 | if (!msg) |
8035 | return; | 8486 | return; |
8036 | 8487 | ||
@@ -8074,7 +8525,7 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8074 | struct sk_buff *msg; | 8525 | struct sk_buff *msg; |
8075 | void *hdr; | 8526 | void *hdr; |
8076 | 8527 | ||
8077 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8528 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8078 | if (!msg) | 8529 | if (!msg) |
8079 | return; | 8530 | return; |
8080 | 8531 | ||
@@ -8101,6 +8552,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8101 | } | 8552 | } |
8102 | 8553 | ||
8103 | void | 8554 | void |
8555 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
8556 | struct net_device *netdev, const u8 *peer, | ||
8557 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
8558 | { | ||
8559 | struct sk_buff *msg; | ||
8560 | struct nlattr *pinfoattr; | ||
8561 | void *hdr; | ||
8562 | |||
8563 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8564 | if (!msg) | ||
8565 | return; | ||
8566 | |||
8567 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
8568 | if (!hdr) { | ||
8569 | nlmsg_free(msg); | ||
8570 | return; | ||
8571 | } | ||
8572 | |||
8573 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
8574 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
8575 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
8576 | goto nla_put_failure; | ||
8577 | |||
8578 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
8579 | if (!pinfoattr) | ||
8580 | goto nla_put_failure; | ||
8581 | |||
8582 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
8583 | goto nla_put_failure; | ||
8584 | |||
8585 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
8586 | goto nla_put_failure; | ||
8587 | |||
8588 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | ||
8589 | goto nla_put_failure; | ||
8590 | |||
8591 | nla_nest_end(msg, pinfoattr); | ||
8592 | |||
8593 | genlmsg_end(msg, hdr); | ||
8594 | |||
8595 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8596 | nl80211_mlme_mcgrp.id, gfp); | ||
8597 | return; | ||
8598 | |||
8599 | nla_put_failure: | ||
8600 | genlmsg_cancel(msg, hdr); | ||
8601 | nlmsg_free(msg); | ||
8602 | } | ||
8603 | |||
8604 | void | ||
8104 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 8605 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
8105 | struct net_device *netdev, const u8 *peer, | 8606 | struct net_device *netdev, const u8 *peer, |
8106 | u32 num_packets, gfp_t gfp) | 8607 | u32 num_packets, gfp_t gfp) |
@@ -8109,7 +8610,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
8109 | struct nlattr *pinfoattr; | 8610 | struct nlattr *pinfoattr; |
8110 | void *hdr; | 8611 | void *hdr; |
8111 | 8612 | ||
8112 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8613 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8113 | if (!msg) | 8614 | if (!msg) |
8114 | return; | 8615 | return; |
8115 | 8616 | ||
@@ -8153,7 +8654,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
8153 | void *hdr; | 8654 | void *hdr; |
8154 | int err; | 8655 | int err; |
8155 | 8656 | ||
8156 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8657 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8157 | if (!msg) | 8658 | if (!msg) |
8158 | return; | 8659 | return; |
8159 | 8660 | ||
@@ -8241,7 +8742,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8241 | rcu_read_lock(); | 8742 | rcu_read_lock(); |
8242 | 8743 | ||
8243 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 8744 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8244 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 8745 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8245 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 8746 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
8246 | if (rdev->ap_beacons_nlpid == notify->pid) | 8747 | if (rdev->ap_beacons_nlpid == notify->pid) |
8247 | rdev->ap_beacons_nlpid = 0; | 8748 | rdev->ap_beacons_nlpid = 0; |