diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-10-08 15:39:28 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-08 15:39:28 -0400 |
commit | e9a68707d736f4f73d7e209885d7b4c5c452b1dc (patch) | |
tree | d9f76964c77c1059483b08436ed060b702b8e25d /net/wireless | |
parent | dd53df265b1ee7a1fbbc76bb62c3bec2383bbd44 (diff) | |
parent | 15a6321d1c0f8db561932cd99e1b9897981da71f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ipw2x00/ipw2200.c
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 54 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/ibss.c | 2 | ||||
-rw-r--r-- | net/wireless/mlme.c | 54 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2000 | ||||
-rw-r--r-- | net/wireless/scan.c | 12 | ||||
-rw-r--r-- | net/wireless/sme.c | 2 | ||||
-rw-r--r-- | net/wireless/util.c | 12 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 38 |
9 files changed, 805 insertions, 1371 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c21ebf9780e..1684ad91763c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -178,26 +178,10 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
178 | char *newname) | 178 | char *newname) |
179 | { | 179 | { |
180 | struct cfg80211_registered_device *rdev2; | 180 | struct cfg80211_registered_device *rdev2; |
181 | int wiphy_idx, taken = -1, result, digits; | 181 | int result; |
182 | 182 | ||
183 | assert_cfg80211_lock(); | 183 | assert_cfg80211_lock(); |
184 | 184 | ||
185 | /* prohibit calling the thing phy%d when %d is not its number */ | ||
186 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | ||
187 | if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { | ||
188 | /* count number of places needed to print wiphy_idx */ | ||
189 | digits = 1; | ||
190 | while (wiphy_idx /= 10) | ||
191 | digits++; | ||
192 | /* | ||
193 | * deny the name if it is phy<idx> where <idx> is printed | ||
194 | * without leading zeroes. taken == strlen(newname) here | ||
195 | */ | ||
196 | if (taken == strlen(PHY_NAME) + digits) | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | |||
201 | /* Ignore nop renames */ | 185 | /* Ignore nop renames */ |
202 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) | 186 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) |
203 | return 0; | 187 | return 0; |
@@ -205,7 +189,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
205 | /* Ensure another device does not already have this name. */ | 189 | /* Ensure another device does not already have this name. */ |
206 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | 190 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) |
207 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) | 191 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) |
208 | return -EINVAL; | 192 | return -EEXIST; |
209 | 193 | ||
210 | result = device_rename(&rdev->wiphy.dev, newname); | 194 | result = device_rename(&rdev->wiphy.dev, newname); |
211 | if (result) | 195 | if (result) |
@@ -320,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work) | |||
320 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 304 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
321 | { | 305 | { |
322 | static int wiphy_counter; | 306 | static int wiphy_counter; |
323 | 307 | int i; | |
324 | struct cfg80211_registered_device *rdev; | 308 | struct cfg80211_registered_device *rdev, *rdev2; |
325 | int alloc_size; | 309 | int alloc_size; |
310 | char nname[IFNAMSIZ + 1]; | ||
311 | bool found = false; | ||
326 | 312 | ||
327 | WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); | 313 | WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); |
328 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); | 314 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); |
@@ -346,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
346 | 332 | ||
347 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { | 333 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { |
348 | wiphy_counter--; | 334 | wiphy_counter--; |
335 | goto too_many_devs; | ||
336 | } | ||
337 | |||
338 | /* 64k wiphy devices is enough for anyone! */ | ||
339 | for (i = 0; i < 0xFFFF; i++) { | ||
340 | found = false; | ||
341 | snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); | ||
342 | nname[sizeof(nname)-1] = 0; | ||
343 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | ||
344 | if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { | ||
345 | found = true; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | if (!found) | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | if (unlikely(found)) { | ||
354 | too_many_devs: | ||
349 | mutex_unlock(&cfg80211_mutex); | 355 | mutex_unlock(&cfg80211_mutex); |
350 | /* ugh, wrapped! */ | 356 | /* ugh, too many devices already! */ |
351 | kfree(rdev); | 357 | kfree(rdev); |
352 | return NULL; | 358 | return NULL; |
353 | } | 359 | } |
354 | 360 | ||
355 | mutex_unlock(&cfg80211_mutex); | ||
356 | |||
357 | /* give it a proper name */ | 361 | /* give it a proper name */ |
358 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 362 | dev_set_name(&rdev->wiphy.dev, "%s", nname); |
363 | |||
364 | mutex_unlock(&cfg80211_mutex); | ||
359 | 365 | ||
360 | mutex_init(&rdev->mtx); | 366 | mutex_init(&rdev->mtx); |
361 | mutex_init(&rdev->devlist_mtx); | 367 | mutex_init(&rdev->devlist_mtx); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5d89310b3587..6583cca0e2ee 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | |||
375 | /* internal helpers */ | 375 | /* internal helpers */ |
376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
377 | struct key_params *params, int key_idx, | 377 | struct key_params *params, int key_idx, |
378 | const u8 *mac_addr); | 378 | bool pairwise, const u8 *mac_addr); |
379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
380 | size_t ie_len, u16 reason, bool from_ap); | 380 | size_t ie_len, u16 reason, bool from_ap); |
381 | void cfg80211_sme_scan_done(struct net_device *dev); | 381 | void cfg80211_sme_scan_done(struct net_device *dev); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8cb6e08373b9..f33fbb79437c 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
160 | */ | 160 | */ |
161 | if (rdev->ops->del_key) | 161 | if (rdev->ops->del_key) |
162 | for (i = 0; i < 6; i++) | 162 | for (i = 0; i < 6; i++) |
163 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 163 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
164 | 164 | ||
165 | if (wdev->current_bss) { | 165 | if (wdev->current_bss) { |
166 | cfg80211_unhold_bss(wdev->current_bss); | 166 | cfg80211_unhold_bss(wdev->current_bss); |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46f371160896..caf11a427507 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -876,21 +876,53 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
876 | 876 | ||
877 | if (ieee80211_is_action(mgmt->frame_control) && | 877 | if (ieee80211_is_action(mgmt->frame_control) && |
878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { |
879 | /* Verify that we are associated with the destination AP */ | 879 | int err = 0; |
880 | |||
880 | wdev_lock(wdev); | 881 | wdev_lock(wdev); |
881 | 882 | ||
882 | if (!wdev->current_bss || | 883 | switch (wdev->iftype) { |
883 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, | 884 | case NL80211_IFTYPE_ADHOC: |
884 | ETH_ALEN) != 0 || | 885 | case NL80211_IFTYPE_STATION: |
885 | ((wdev->iftype == NL80211_IFTYPE_STATION || | 886 | case NL80211_IFTYPE_P2P_CLIENT: |
886 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && | 887 | if (!wdev->current_bss) { |
887 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, | 888 | err = -ENOTCONN; |
888 | ETH_ALEN) != 0)) { | 889 | break; |
889 | wdev_unlock(wdev); | 890 | } |
890 | return -ENOTCONN; | 891 | |
891 | } | 892 | if (memcmp(wdev->current_bss->pub.bssid, |
893 | mgmt->bssid, ETH_ALEN)) { | ||
894 | err = -ENOTCONN; | ||
895 | break; | ||
896 | } | ||
897 | |||
898 | /* | ||
899 | * check for IBSS DA must be done by driver as | ||
900 | * cfg80211 doesn't track the stations | ||
901 | */ | ||
902 | if (wdev->iftype == NL80211_IFTYPE_ADHOC) | ||
903 | break; | ||
892 | 904 | ||
905 | /* for station, check that DA is the AP */ | ||
906 | if (memcmp(wdev->current_bss->pub.bssid, | ||
907 | mgmt->da, ETH_ALEN)) { | ||
908 | err = -ENOTCONN; | ||
909 | break; | ||
910 | } | ||
911 | break; | ||
912 | case NL80211_IFTYPE_AP: | ||
913 | case NL80211_IFTYPE_P2P_GO: | ||
914 | case NL80211_IFTYPE_AP_VLAN: | ||
915 | if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) | ||
916 | err = -EINVAL; | ||
917 | break; | ||
918 | default: | ||
919 | err = -EOPNOTSUPP; | ||
920 | break; | ||
921 | } | ||
893 | wdev_unlock(wdev); | 922 | wdev_unlock(wdev); |
923 | |||
924 | if (err) | ||
925 | return err; | ||
894 | } | 926 | } |
895 | 927 | ||
896 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) | 928 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c84825803ce..882dc921103b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -23,6 +23,11 @@ | |||
23 | #include "nl80211.h" | 23 | #include "nl80211.h" |
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | 25 | ||
26 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
27 | struct genl_info *info); | ||
28 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
29 | struct genl_info *info); | ||
30 | |||
26 | /* the netlink family */ | 31 | /* the netlink family */ |
27 | static struct genl_family nl80211_fam = { | 32 | static struct genl_family nl80211_fam = { |
28 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 33 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { | |||
31 | .version = 1, /* no particular meaning now */ | 36 | .version = 1, /* no particular meaning now */ |
32 | .maxattr = NL80211_ATTR_MAX, | 37 | .maxattr = NL80211_ATTR_MAX, |
33 | .netnsok = true, | 38 | .netnsok = true, |
39 | .pre_doit = nl80211_pre_doit, | ||
40 | .post_doit = nl80211_post_doit, | ||
34 | }; | 41 | }; |
35 | 42 | ||
36 | /* internal helper: get rdev and dev */ | 43 | /* internal helper: get rdev and dev */ |
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
86 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 93 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
87 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 94 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
88 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 95 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
96 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, | ||
89 | 97 | ||
90 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 98 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
91 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 99 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -161,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
161 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | 169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, |
162 | }; | 170 | }; |
163 | 171 | ||
164 | /* policy for the attributes */ | 172 | /* policy for the key attributes */ |
165 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | 173 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { |
166 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 174 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
167 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 175 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
@@ -169,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
169 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 177 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
170 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 178 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
171 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 179 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
180 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | ||
172 | }; | 181 | }; |
173 | 182 | ||
174 | /* ifidx get helper */ | 183 | /* ifidx get helper */ |
@@ -191,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) | |||
191 | return res; | 200 | return res; |
192 | } | 201 | } |
193 | 202 | ||
203 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | ||
204 | struct netlink_callback *cb, | ||
205 | struct cfg80211_registered_device **rdev, | ||
206 | struct net_device **dev) | ||
207 | { | ||
208 | int ifidx = cb->args[0]; | ||
209 | int err; | ||
210 | |||
211 | if (!ifidx) | ||
212 | ifidx = nl80211_get_ifidx(cb); | ||
213 | if (ifidx < 0) | ||
214 | return ifidx; | ||
215 | |||
216 | cb->args[0] = ifidx; | ||
217 | |||
218 | rtnl_lock(); | ||
219 | |||
220 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
221 | if (!*dev) { | ||
222 | err = -ENODEV; | ||
223 | goto out_rtnl; | ||
224 | } | ||
225 | |||
226 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
227 | if (IS_ERR(dev)) { | ||
228 | err = PTR_ERR(dev); | ||
229 | goto out_rtnl; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | out_rtnl: | ||
234 | rtnl_unlock(); | ||
235 | return err; | ||
236 | } | ||
237 | |||
238 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | ||
239 | { | ||
240 | cfg80211_unlock_rdev(rdev); | ||
241 | rtnl_unlock(); | ||
242 | } | ||
243 | |||
194 | /* IE validation */ | 244 | /* IE validation */ |
195 | static bool is_valid_ie_attr(const struct nlattr *attr) | 245 | static bool is_valid_ie_attr(const struct nlattr *attr) |
196 | { | 246 | { |
@@ -258,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
258 | struct key_parse { | 308 | struct key_parse { |
259 | struct key_params p; | 309 | struct key_params p; |
260 | int idx; | 310 | int idx; |
311 | int type; | ||
261 | bool def, defmgmt; | 312 | bool def, defmgmt; |
262 | }; | 313 | }; |
263 | 314 | ||
@@ -288,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
288 | if (tb[NL80211_KEY_CIPHER]) | 339 | if (tb[NL80211_KEY_CIPHER]) |
289 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | 340 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); |
290 | 341 | ||
342 | if (tb[NL80211_KEY_TYPE]) { | ||
343 | k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); | ||
344 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
291 | return 0; | 348 | return 0; |
292 | } | 349 | } |
293 | 350 | ||
@@ -312,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
312 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 369 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
313 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 370 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
314 | 371 | ||
372 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | ||
373 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | ||
374 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
315 | return 0; | 378 | return 0; |
316 | } | 379 | } |
317 | 380 | ||
@@ -321,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
321 | 384 | ||
322 | memset(k, 0, sizeof(*k)); | 385 | memset(k, 0, sizeof(*k)); |
323 | k->idx = -1; | 386 | k->idx = -1; |
387 | k->type = -1; | ||
324 | 388 | ||
325 | if (info->attrs[NL80211_ATTR_KEY]) | 389 | if (info->attrs[NL80211_ATTR_KEY]) |
326 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | 390 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); |
@@ -385,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
385 | } else if (parse.defmgmt) | 449 | } else if (parse.defmgmt) |
386 | goto error; | 450 | goto error; |
387 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 451 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
388 | parse.idx, NULL); | 452 | parse.idx, false, NULL); |
389 | if (err) | 453 | if (err) |
390 | goto error; | 454 | goto error; |
391 | result->params[parse.idx].cipher = parse.p.cipher; | 455 | result->params[parse.idx].cipher = parse.p.cipher; |
@@ -404,9 +468,6 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
404 | { | 468 | { |
405 | ASSERT_WDEV_LOCK(wdev); | 469 | ASSERT_WDEV_LOCK(wdev); |
406 | 470 | ||
407 | if (!netif_running(wdev->netdev)) | ||
408 | return -ENETDOWN; | ||
409 | |||
410 | switch (wdev->iftype) { | 471 | switch (wdev->iftype) { |
411 | case NL80211_IFTYPE_AP: | 472 | case NL80211_IFTYPE_AP: |
412 | case NL80211_IFTYPE_AP_VLAN: | 473 | case NL80211_IFTYPE_AP_VLAN: |
@@ -471,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
471 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 532 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
472 | dev->wiphy.max_scan_ie_len); | 533 | dev->wiphy.max_scan_ie_len); |
473 | 534 | ||
535 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | ||
536 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | ||
537 | |||
474 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 538 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
475 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 539 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
476 | dev->wiphy.cipher_suites); | 540 | dev->wiphy.cipher_suites); |
@@ -603,6 +667,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
603 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 667 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
604 | } | 668 | } |
605 | CMD(set_channel, SET_CHANNEL); | 669 | CMD(set_channel, SET_CHANNEL); |
670 | CMD(set_wds_peer, SET_WDS_PEER); | ||
606 | 671 | ||
607 | #undef CMD | 672 | #undef CMD |
608 | 673 | ||
@@ -703,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
703 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 768 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
704 | { | 769 | { |
705 | struct sk_buff *msg; | 770 | struct sk_buff *msg; |
706 | struct cfg80211_registered_device *dev; | 771 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
707 | |||
708 | dev = cfg80211_get_dev_from_info(info); | ||
709 | if (IS_ERR(dev)) | ||
710 | return PTR_ERR(dev); | ||
711 | 772 | ||
712 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 773 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
713 | if (!msg) | 774 | if (!msg) |
714 | goto out_err; | 775 | return -ENOMEM; |
715 | |||
716 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | ||
717 | goto out_free; | ||
718 | 776 | ||
719 | cfg80211_unlock_rdev(dev); | 777 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { |
778 | nlmsg_free(msg); | ||
779 | return -ENOBUFS; | ||
780 | } | ||
720 | 781 | ||
721 | return genlmsg_reply(msg, info); | 782 | return genlmsg_reply(msg, info); |
722 | |||
723 | out_free: | ||
724 | nlmsg_free(msg); | ||
725 | out_err: | ||
726 | cfg80211_unlock_rdev(dev); | ||
727 | return -ENOBUFS; | ||
728 | } | 783 | } |
729 | 784 | ||
730 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 785 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
@@ -813,24 +868,36 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
813 | 868 | ||
814 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) | 869 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) |
815 | { | 870 | { |
816 | struct cfg80211_registered_device *rdev; | 871 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
817 | struct net_device *netdev; | 872 | struct net_device *netdev = info->user_ptr[1]; |
818 | int result; | ||
819 | 873 | ||
820 | rtnl_lock(); | 874 | return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); |
875 | } | ||
821 | 876 | ||
822 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); | 877 | static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) |
823 | if (result) | 878 | { |
824 | goto unlock; | 879 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
880 | struct net_device *dev = info->user_ptr[1]; | ||
881 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
882 | const u8 *bssid; | ||
825 | 883 | ||
826 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | 884 | if (!info->attrs[NL80211_ATTR_MAC]) |
885 | return -EINVAL; | ||
827 | 886 | ||
828 | unlock: | 887 | if (netif_running(dev)) |
829 | rtnl_unlock(); | 888 | return -EBUSY; |
830 | 889 | ||
831 | return result; | 890 | if (!rdev->ops->set_wds_peer) |
891 | return -EOPNOTSUPP; | ||
892 | |||
893 | if (wdev->iftype != NL80211_IFTYPE_WDS) | ||
894 | return -EOPNOTSUPP; | ||
895 | |||
896 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
897 | return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); | ||
832 | } | 898 | } |
833 | 899 | ||
900 | |||
834 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 901 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
835 | { | 902 | { |
836 | struct cfg80211_registered_device *rdev; | 903 | struct cfg80211_registered_device *rdev; |
@@ -843,8 +910,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
843 | u32 frag_threshold = 0, rts_threshold = 0; | 910 | u32 frag_threshold = 0, rts_threshold = 0; |
844 | u8 coverage_class = 0; | 911 | u8 coverage_class = 0; |
845 | 912 | ||
846 | rtnl_lock(); | ||
847 | |||
848 | /* | 913 | /* |
849 | * Try to find the wiphy and netdev. Normally this | 914 | * Try to find the wiphy and netdev. Normally this |
850 | * function shouldn't need the netdev, but this is | 915 | * function shouldn't need the netdev, but this is |
@@ -871,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
871 | rdev = __cfg80211_rdev_from_info(info); | 936 | rdev = __cfg80211_rdev_from_info(info); |
872 | if (IS_ERR(rdev)) { | 937 | if (IS_ERR(rdev)) { |
873 | mutex_unlock(&cfg80211_mutex); | 938 | mutex_unlock(&cfg80211_mutex); |
874 | result = PTR_ERR(rdev); | 939 | return PTR_ERR(rdev); |
875 | goto unlock; | ||
876 | } | 940 | } |
877 | wdev = NULL; | 941 | wdev = NULL; |
878 | netdev = NULL; | 942 | netdev = NULL; |
@@ -1054,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1054 | mutex_unlock(&rdev->mtx); | 1118 | mutex_unlock(&rdev->mtx); |
1055 | if (netdev) | 1119 | if (netdev) |
1056 | dev_put(netdev); | 1120 | dev_put(netdev); |
1057 | unlock: | ||
1058 | rtnl_unlock(); | ||
1059 | return result; | 1121 | return result; |
1060 | } | 1122 | } |
1061 | 1123 | ||
@@ -1135,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1135 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 1197 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
1136 | { | 1198 | { |
1137 | struct sk_buff *msg; | 1199 | struct sk_buff *msg; |
1138 | struct cfg80211_registered_device *dev; | 1200 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1139 | struct net_device *netdev; | 1201 | struct net_device *netdev = info->user_ptr[1]; |
1140 | int err; | ||
1141 | |||
1142 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); | ||
1143 | if (err) | ||
1144 | return err; | ||
1145 | 1202 | ||
1146 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1203 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1147 | if (!msg) | 1204 | if (!msg) |
1148 | goto out_err; | 1205 | return -ENOMEM; |
1149 | 1206 | ||
1150 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1207 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1151 | dev, netdev) < 0) | 1208 | dev, netdev) < 0) { |
1152 | goto out_free; | 1209 | nlmsg_free(msg); |
1153 | 1210 | return -ENOBUFS; | |
1154 | dev_put(netdev); | 1211 | } |
1155 | cfg80211_unlock_rdev(dev); | ||
1156 | 1212 | ||
1157 | return genlmsg_reply(msg, info); | 1213 | return genlmsg_reply(msg, info); |
1158 | |||
1159 | out_free: | ||
1160 | nlmsg_free(msg); | ||
1161 | out_err: | ||
1162 | dev_put(netdev); | ||
1163 | cfg80211_unlock_rdev(dev); | ||
1164 | return -ENOBUFS; | ||
1165 | } | 1214 | } |
1166 | 1215 | ||
1167 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 1216 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
@@ -1221,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
1221 | 1270 | ||
1222 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 1271 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
1223 | { | 1272 | { |
1224 | struct cfg80211_registered_device *rdev; | 1273 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1225 | struct vif_params params; | 1274 | struct vif_params params; |
1226 | int err; | 1275 | int err; |
1227 | enum nl80211_iftype otype, ntype; | 1276 | enum nl80211_iftype otype, ntype; |
1228 | struct net_device *dev; | 1277 | struct net_device *dev = info->user_ptr[1]; |
1229 | u32 _flags, *flags = NULL; | 1278 | u32 _flags, *flags = NULL; |
1230 | bool change = false; | 1279 | bool change = false; |
1231 | 1280 | ||
1232 | memset(¶ms, 0, sizeof(params)); | 1281 | memset(¶ms, 0, sizeof(params)); |
1233 | 1282 | ||
1234 | rtnl_lock(); | ||
1235 | |||
1236 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1237 | if (err) | ||
1238 | goto unlock_rtnl; | ||
1239 | |||
1240 | otype = ntype = dev->ieee80211_ptr->iftype; | 1283 | otype = ntype = dev->ieee80211_ptr->iftype; |
1241 | 1284 | ||
1242 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1285 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1243 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1286 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1244 | if (otype != ntype) | 1287 | if (otype != ntype) |
1245 | change = true; | 1288 | change = true; |
1246 | if (ntype > NL80211_IFTYPE_MAX) { | 1289 | if (ntype > NL80211_IFTYPE_MAX) |
1247 | err = -EINVAL; | 1290 | return -EINVAL; |
1248 | goto unlock; | ||
1249 | } | ||
1250 | } | 1291 | } |
1251 | 1292 | ||
1252 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1293 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1253 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 1294 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1254 | err = -EINVAL; | 1295 | return -EINVAL; |
1255 | goto unlock; | ||
1256 | } | ||
1257 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1296 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1258 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1297 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1259 | change = true; | 1298 | change = true; |
@@ -1264,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1264 | change = true; | 1303 | change = true; |
1265 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); | 1304 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); |
1266 | if (err) | 1305 | if (err) |
1267 | goto unlock; | 1306 | return err; |
1268 | } else { | 1307 | } else { |
1269 | params.use_4addr = -1; | 1308 | params.use_4addr = -1; |
1270 | } | 1309 | } |
1271 | 1310 | ||
1272 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1311 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
1273 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1312 | if (ntype != NL80211_IFTYPE_MONITOR) |
1274 | err = -EINVAL; | 1313 | return -EINVAL; |
1275 | goto unlock; | ||
1276 | } | ||
1277 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 1314 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
1278 | &_flags); | 1315 | &_flags); |
1279 | if (err) | 1316 | if (err) |
1280 | goto unlock; | 1317 | return err; |
1281 | 1318 | ||
1282 | flags = &_flags; | 1319 | flags = &_flags; |
1283 | change = true; | 1320 | change = true; |
@@ -1291,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1291 | if (!err && params.use_4addr != -1) | 1328 | if (!err && params.use_4addr != -1) |
1292 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 1329 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
1293 | 1330 | ||
1294 | unlock: | ||
1295 | dev_put(dev); | ||
1296 | cfg80211_unlock_rdev(rdev); | ||
1297 | unlock_rtnl: | ||
1298 | rtnl_unlock(); | ||
1299 | return err; | 1331 | return err; |
1300 | } | 1332 | } |
1301 | 1333 | ||
1302 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 1334 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
1303 | { | 1335 | { |
1304 | struct cfg80211_registered_device *rdev; | 1336 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1305 | struct vif_params params; | 1337 | struct vif_params params; |
1306 | int err; | 1338 | int err; |
1307 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1339 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
@@ -1318,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1318 | return -EINVAL; | 1350 | return -EINVAL; |
1319 | } | 1351 | } |
1320 | 1352 | ||
1321 | rtnl_lock(); | ||
1322 | |||
1323 | rdev = cfg80211_get_dev_from_info(info); | ||
1324 | if (IS_ERR(rdev)) { | ||
1325 | err = PTR_ERR(rdev); | ||
1326 | goto unlock_rtnl; | ||
1327 | } | ||
1328 | |||
1329 | if (!rdev->ops->add_virtual_intf || | 1353 | if (!rdev->ops->add_virtual_intf || |
1330 | !(rdev->wiphy.interface_modes & (1 << type))) { | 1354 | !(rdev->wiphy.interface_modes & (1 << type))) |
1331 | err = -EOPNOTSUPP; | 1355 | return -EOPNOTSUPP; |
1332 | goto unlock; | ||
1333 | } | ||
1334 | 1356 | ||
1335 | if (type == NL80211_IFTYPE_MESH_POINT && | 1357 | if (type == NL80211_IFTYPE_MESH_POINT && |
1336 | info->attrs[NL80211_ATTR_MESH_ID]) { | 1358 | info->attrs[NL80211_ATTR_MESH_ID]) { |
@@ -1342,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1342 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1364 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1343 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1365 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
1344 | if (err) | 1366 | if (err) |
1345 | goto unlock; | 1367 | return err; |
1346 | } | 1368 | } |
1347 | 1369 | ||
1348 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1370 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
@@ -1352,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1352 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1374 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1353 | type, err ? NULL : &flags, ¶ms); | 1375 | type, err ? NULL : &flags, ¶ms); |
1354 | 1376 | ||
1355 | unlock: | ||
1356 | cfg80211_unlock_rdev(rdev); | ||
1357 | unlock_rtnl: | ||
1358 | rtnl_unlock(); | ||
1359 | return err; | 1377 | return err; |
1360 | } | 1378 | } |
1361 | 1379 | ||
1362 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1380 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1363 | { | 1381 | { |
1364 | struct cfg80211_registered_device *rdev; | 1382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1365 | int err; | 1383 | struct net_device *dev = info->user_ptr[1]; |
1366 | struct net_device *dev; | ||
1367 | |||
1368 | rtnl_lock(); | ||
1369 | |||
1370 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1371 | if (err) | ||
1372 | goto unlock_rtnl; | ||
1373 | 1384 | ||
1374 | if (!rdev->ops->del_virtual_intf) { | 1385 | if (!rdev->ops->del_virtual_intf) |
1375 | err = -EOPNOTSUPP; | 1386 | return -EOPNOTSUPP; |
1376 | goto out; | ||
1377 | } | ||
1378 | |||
1379 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | ||
1380 | 1387 | ||
1381 | out: | 1388 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1382 | cfg80211_unlock_rdev(rdev); | ||
1383 | dev_put(dev); | ||
1384 | unlock_rtnl: | ||
1385 | rtnl_unlock(); | ||
1386 | return err; | ||
1387 | } | 1389 | } |
1388 | 1390 | ||
1389 | struct get_key_cookie { | 1391 | struct get_key_cookie { |
@@ -1436,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params) | |||
1436 | 1438 | ||
1437 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 1439 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
1438 | { | 1440 | { |
1439 | struct cfg80211_registered_device *rdev; | 1441 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1440 | int err; | 1442 | int err; |
1441 | struct net_device *dev; | 1443 | struct net_device *dev = info->user_ptr[1]; |
1442 | u8 key_idx = 0; | 1444 | u8 key_idx = 0; |
1443 | u8 *mac_addr = NULL; | 1445 | const u8 *mac_addr = NULL; |
1446 | bool pairwise; | ||
1444 | struct get_key_cookie cookie = { | 1447 | struct get_key_cookie cookie = { |
1445 | .error = 0, | 1448 | .error = 0, |
1446 | }; | 1449 | }; |
@@ -1456,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1456 | if (info->attrs[NL80211_ATTR_MAC]) | 1459 | if (info->attrs[NL80211_ATTR_MAC]) |
1457 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1460 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1458 | 1461 | ||
1459 | rtnl_lock(); | 1462 | pairwise = !!mac_addr; |
1460 | 1463 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | |
1461 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1464 | u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); |
1462 | if (err) | 1465 | if (kt >= NUM_NL80211_KEYTYPES) |
1463 | goto unlock_rtnl; | 1466 | return -EINVAL; |
1464 | 1467 | if (kt != NL80211_KEYTYPE_GROUP && | |
1465 | if (!rdev->ops->get_key) { | 1468 | kt != NL80211_KEYTYPE_PAIRWISE) |
1466 | err = -EOPNOTSUPP; | 1469 | return -EINVAL; |
1467 | goto out; | 1470 | pairwise = kt == NL80211_KEYTYPE_PAIRWISE; |
1468 | } | 1471 | } |
1469 | 1472 | ||
1473 | if (!rdev->ops->get_key) | ||
1474 | return -EOPNOTSUPP; | ||
1475 | |||
1470 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1476 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1471 | if (!msg) { | 1477 | if (!msg) |
1472 | err = -ENOMEM; | 1478 | return -ENOMEM; |
1473 | goto out; | ||
1474 | } | ||
1475 | 1479 | ||
1476 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1480 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1477 | NL80211_CMD_NEW_KEY); | 1481 | NL80211_CMD_NEW_KEY); |
1478 | 1482 | if (IS_ERR(hdr)) | |
1479 | if (IS_ERR(hdr)) { | 1483 | return PTR_ERR(hdr); |
1480 | err = PTR_ERR(hdr); | ||
1481 | goto free_msg; | ||
1482 | } | ||
1483 | 1484 | ||
1484 | cookie.msg = msg; | 1485 | cookie.msg = msg; |
1485 | cookie.idx = key_idx; | 1486 | cookie.idx = key_idx; |
@@ -1489,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1489 | if (mac_addr) | 1490 | if (mac_addr) |
1490 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1491 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1491 | 1492 | ||
1492 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, | 1493 | if (pairwise && mac_addr && |
1493 | &cookie, get_key_callback); | 1494 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
1495 | return -ENOENT; | ||
1496 | |||
1497 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, | ||
1498 | mac_addr, &cookie, get_key_callback); | ||
1494 | 1499 | ||
1495 | if (err) | 1500 | if (err) |
1496 | goto free_msg; | 1501 | goto free_msg; |
@@ -1499,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1499 | goto nla_put_failure; | 1504 | goto nla_put_failure; |
1500 | 1505 | ||
1501 | genlmsg_end(msg, hdr); | 1506 | genlmsg_end(msg, hdr); |
1502 | err = genlmsg_reply(msg, info); | 1507 | return genlmsg_reply(msg, info); |
1503 | goto out; | ||
1504 | 1508 | ||
1505 | nla_put_failure: | 1509 | nla_put_failure: |
1506 | err = -ENOBUFS; | 1510 | err = -ENOBUFS; |
1507 | free_msg: | 1511 | free_msg: |
1508 | nlmsg_free(msg); | 1512 | nlmsg_free(msg); |
1509 | out: | ||
1510 | cfg80211_unlock_rdev(rdev); | ||
1511 | dev_put(dev); | ||
1512 | unlock_rtnl: | ||
1513 | rtnl_unlock(); | ||
1514 | |||
1515 | return err; | 1513 | return err; |
1516 | } | 1514 | } |
1517 | 1515 | ||
1518 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1516 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1519 | { | 1517 | { |
1520 | struct cfg80211_registered_device *rdev; | 1518 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1521 | struct key_parse key; | 1519 | struct key_parse key; |
1522 | int err; | 1520 | int err; |
1523 | struct net_device *dev; | 1521 | struct net_device *dev = info->user_ptr[1]; |
1524 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1522 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1525 | u8 key_index); | 1523 | u8 key_index); |
1526 | 1524 | ||
@@ -1535,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1535 | if (!key.def && !key.defmgmt) | 1533 | if (!key.def && !key.defmgmt) |
1536 | return -EINVAL; | 1534 | return -EINVAL; |
1537 | 1535 | ||
1538 | rtnl_lock(); | ||
1539 | |||
1540 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1541 | if (err) | ||
1542 | goto unlock_rtnl; | ||
1543 | |||
1544 | if (key.def) | 1536 | if (key.def) |
1545 | func = rdev->ops->set_default_key; | 1537 | func = rdev->ops->set_default_key; |
1546 | else | 1538 | else |
1547 | func = rdev->ops->set_default_mgmt_key; | 1539 | func = rdev->ops->set_default_mgmt_key; |
1548 | 1540 | ||
1549 | if (!func) { | 1541 | if (!func) |
1550 | err = -EOPNOTSUPP; | 1542 | return -EOPNOTSUPP; |
1551 | goto out; | ||
1552 | } | ||
1553 | 1543 | ||
1554 | wdev_lock(dev->ieee80211_ptr); | 1544 | wdev_lock(dev->ieee80211_ptr); |
1555 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1545 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1566,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1566 | #endif | 1556 | #endif |
1567 | wdev_unlock(dev->ieee80211_ptr); | 1557 | wdev_unlock(dev->ieee80211_ptr); |
1568 | 1558 | ||
1569 | out: | ||
1570 | cfg80211_unlock_rdev(rdev); | ||
1571 | dev_put(dev); | ||
1572 | |||
1573 | unlock_rtnl: | ||
1574 | rtnl_unlock(); | ||
1575 | |||
1576 | return err; | 1559 | return err; |
1577 | } | 1560 | } |
1578 | 1561 | ||
1579 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1562 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
1580 | { | 1563 | { |
1581 | struct cfg80211_registered_device *rdev; | 1564 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1582 | int err; | 1565 | int err; |
1583 | struct net_device *dev; | 1566 | struct net_device *dev = info->user_ptr[1]; |
1584 | struct key_parse key; | 1567 | struct key_parse key; |
1585 | u8 *mac_addr = NULL; | 1568 | const u8 *mac_addr = NULL; |
1586 | 1569 | ||
1587 | err = nl80211_parse_key(info, &key); | 1570 | err = nl80211_parse_key(info, &key); |
1588 | if (err) | 1571 | if (err) |
@@ -1594,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1594 | if (info->attrs[NL80211_ATTR_MAC]) | 1577 | if (info->attrs[NL80211_ATTR_MAC]) |
1595 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1578 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1596 | 1579 | ||
1597 | rtnl_lock(); | 1580 | if (key.type == -1) { |
1581 | if (mac_addr) | ||
1582 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1583 | else | ||
1584 | key.type = NL80211_KEYTYPE_GROUP; | ||
1585 | } | ||
1598 | 1586 | ||
1599 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1587 | /* for now */ |
1600 | if (err) | 1588 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1601 | goto unlock_rtnl; | 1589 | key.type != NL80211_KEYTYPE_GROUP) |
1590 | return -EINVAL; | ||
1602 | 1591 | ||
1603 | if (!rdev->ops->add_key) { | 1592 | if (!rdev->ops->add_key) |
1604 | err = -EOPNOTSUPP; | 1593 | return -EOPNOTSUPP; |
1605 | goto out; | ||
1606 | } | ||
1607 | 1594 | ||
1608 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { | 1595 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, |
1609 | err = -EINVAL; | 1596 | key.type == NL80211_KEYTYPE_PAIRWISE, |
1610 | goto out; | 1597 | mac_addr)) |
1611 | } | 1598 | return -EINVAL; |
1612 | 1599 | ||
1613 | wdev_lock(dev->ieee80211_ptr); | 1600 | wdev_lock(dev->ieee80211_ptr); |
1614 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1601 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1615 | if (!err) | 1602 | if (!err) |
1616 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, | 1603 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, |
1604 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1617 | mac_addr, &key.p); | 1605 | mac_addr, &key.p); |
1618 | wdev_unlock(dev->ieee80211_ptr); | 1606 | wdev_unlock(dev->ieee80211_ptr); |
1619 | 1607 | ||
1620 | out: | ||
1621 | cfg80211_unlock_rdev(rdev); | ||
1622 | dev_put(dev); | ||
1623 | unlock_rtnl: | ||
1624 | rtnl_unlock(); | ||
1625 | |||
1626 | return err; | 1608 | return err; |
1627 | } | 1609 | } |
1628 | 1610 | ||
1629 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 1611 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
1630 | { | 1612 | { |
1631 | struct cfg80211_registered_device *rdev; | 1613 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1632 | int err; | 1614 | int err; |
1633 | struct net_device *dev; | 1615 | struct net_device *dev = info->user_ptr[1]; |
1634 | u8 *mac_addr = NULL; | 1616 | u8 *mac_addr = NULL; |
1635 | struct key_parse key; | 1617 | struct key_parse key; |
1636 | 1618 | ||
@@ -1641,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1641 | if (info->attrs[NL80211_ATTR_MAC]) | 1623 | if (info->attrs[NL80211_ATTR_MAC]) |
1642 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1624 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1643 | 1625 | ||
1644 | rtnl_lock(); | 1626 | if (key.type == -1) { |
1627 | if (mac_addr) | ||
1628 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1629 | else | ||
1630 | key.type = NL80211_KEYTYPE_GROUP; | ||
1631 | } | ||
1645 | 1632 | ||
1646 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1633 | /* for now */ |
1647 | if (err) | 1634 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1648 | goto unlock_rtnl; | 1635 | key.type != NL80211_KEYTYPE_GROUP) |
1636 | return -EINVAL; | ||
1649 | 1637 | ||
1650 | if (!rdev->ops->del_key) { | 1638 | if (!rdev->ops->del_key) |
1651 | err = -EOPNOTSUPP; | 1639 | return -EOPNOTSUPP; |
1652 | goto out; | ||
1653 | } | ||
1654 | 1640 | ||
1655 | wdev_lock(dev->ieee80211_ptr); | 1641 | wdev_lock(dev->ieee80211_ptr); |
1656 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1642 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1643 | |||
1644 | if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && | ||
1645 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
1646 | err = -ENOENT; | ||
1647 | |||
1657 | if (!err) | 1648 | if (!err) |
1658 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); | 1649 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, |
1650 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1651 | mac_addr); | ||
1659 | 1652 | ||
1660 | #ifdef CONFIG_CFG80211_WEXT | 1653 | #ifdef CONFIG_CFG80211_WEXT |
1661 | if (!err) { | 1654 | if (!err) { |
@@ -1667,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1667 | #endif | 1660 | #endif |
1668 | wdev_unlock(dev->ieee80211_ptr); | 1661 | wdev_unlock(dev->ieee80211_ptr); |
1669 | 1662 | ||
1670 | out: | ||
1671 | cfg80211_unlock_rdev(rdev); | ||
1672 | dev_put(dev); | ||
1673 | |||
1674 | unlock_rtnl: | ||
1675 | rtnl_unlock(); | ||
1676 | |||
1677 | return err; | 1663 | return err; |
1678 | } | 1664 | } |
1679 | 1665 | ||
@@ -1681,36 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1681 | { | 1667 | { |
1682 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 1668 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
1683 | struct beacon_parameters *info); | 1669 | struct beacon_parameters *info); |
1684 | struct cfg80211_registered_device *rdev; | 1670 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1685 | int err; | 1671 | struct net_device *dev = info->user_ptr[1]; |
1686 | struct net_device *dev; | ||
1687 | struct beacon_parameters params; | 1672 | struct beacon_parameters params; |
1688 | int haveinfo = 0; | 1673 | int haveinfo = 0; |
1689 | 1674 | ||
1690 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1675 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1691 | return -EINVAL; | 1676 | return -EINVAL; |
1692 | 1677 | ||
1693 | rtnl_lock(); | ||
1694 | |||
1695 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1696 | if (err) | ||
1697 | goto unlock_rtnl; | ||
1698 | |||
1699 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1678 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1700 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 1679 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1701 | err = -EOPNOTSUPP; | 1680 | return -EOPNOTSUPP; |
1702 | goto out; | ||
1703 | } | ||
1704 | 1681 | ||
1705 | switch (info->genlhdr->cmd) { | 1682 | switch (info->genlhdr->cmd) { |
1706 | case NL80211_CMD_NEW_BEACON: | 1683 | case NL80211_CMD_NEW_BEACON: |
1707 | /* these are required for NEW_BEACON */ | 1684 | /* these are required for NEW_BEACON */ |
1708 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 1685 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
1709 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 1686 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
1710 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1687 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1711 | err = -EINVAL; | 1688 | return -EINVAL; |
1712 | goto out; | ||
1713 | } | ||
1714 | 1689 | ||
1715 | call = rdev->ops->add_beacon; | 1690 | call = rdev->ops->add_beacon; |
1716 | break; | 1691 | break; |
@@ -1719,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1719 | break; | 1694 | break; |
1720 | default: | 1695 | default: |
1721 | WARN_ON(1); | 1696 | WARN_ON(1); |
1722 | err = -EOPNOTSUPP; | 1697 | return -EOPNOTSUPP; |
1723 | goto out; | ||
1724 | } | 1698 | } |
1725 | 1699 | ||
1726 | if (!call) { | 1700 | if (!call) |
1727 | err = -EOPNOTSUPP; | 1701 | return -EOPNOTSUPP; |
1728 | goto out; | ||
1729 | } | ||
1730 | 1702 | ||
1731 | memset(¶ms, 0, sizeof(params)); | 1703 | memset(¶ms, 0, sizeof(params)); |
1732 | 1704 | ||
@@ -1756,53 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1756 | haveinfo = 1; | 1728 | haveinfo = 1; |
1757 | } | 1729 | } |
1758 | 1730 | ||
1759 | if (!haveinfo) { | 1731 | if (!haveinfo) |
1760 | err = -EINVAL; | 1732 | return -EINVAL; |
1761 | goto out; | ||
1762 | } | ||
1763 | |||
1764 | err = call(&rdev->wiphy, dev, ¶ms); | ||
1765 | |||
1766 | out: | ||
1767 | cfg80211_unlock_rdev(rdev); | ||
1768 | dev_put(dev); | ||
1769 | unlock_rtnl: | ||
1770 | rtnl_unlock(); | ||
1771 | 1733 | ||
1772 | return err; | 1734 | return call(&rdev->wiphy, dev, ¶ms); |
1773 | } | 1735 | } |
1774 | 1736 | ||
1775 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1737 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1776 | { | 1738 | { |
1777 | struct cfg80211_registered_device *rdev; | 1739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1778 | int err; | 1740 | struct net_device *dev = info->user_ptr[1]; |
1779 | struct net_device *dev; | ||
1780 | 1741 | ||
1781 | rtnl_lock(); | 1742 | if (!rdev->ops->del_beacon) |
1782 | 1743 | return -EOPNOTSUPP; | |
1783 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1784 | if (err) | ||
1785 | goto unlock_rtnl; | ||
1786 | |||
1787 | if (!rdev->ops->del_beacon) { | ||
1788 | err = -EOPNOTSUPP; | ||
1789 | goto out; | ||
1790 | } | ||
1791 | 1744 | ||
1792 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1745 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1793 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 1746 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1794 | err = -EOPNOTSUPP; | 1747 | return -EOPNOTSUPP; |
1795 | goto out; | ||
1796 | } | ||
1797 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); | ||
1798 | |||
1799 | out: | ||
1800 | cfg80211_unlock_rdev(rdev); | ||
1801 | dev_put(dev); | ||
1802 | unlock_rtnl: | ||
1803 | rtnl_unlock(); | ||
1804 | 1748 | ||
1805 | return err; | 1749 | return rdev->ops->del_beacon(&rdev->wiphy, dev); |
1806 | } | 1750 | } |
1807 | 1751 | ||
1808 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1752 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -1923,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1923 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | 1867 | if (sinfo->filled & STATION_INFO_TX_PACKETS) |
1924 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | 1868 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, |
1925 | sinfo->tx_packets); | 1869 | sinfo->tx_packets); |
1870 | if (sinfo->filled & STATION_INFO_TX_RETRIES) | ||
1871 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, | ||
1872 | sinfo->tx_retries); | ||
1873 | if (sinfo->filled & STATION_INFO_TX_FAILED) | ||
1874 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, | ||
1875 | sinfo->tx_failed); | ||
1926 | nla_nest_end(msg, sinfoattr); | 1876 | nla_nest_end(msg, sinfoattr); |
1927 | 1877 | ||
1928 | return genlmsg_end(msg, hdr); | 1878 | return genlmsg_end(msg, hdr); |
@@ -1939,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1939 | struct cfg80211_registered_device *dev; | 1889 | struct cfg80211_registered_device *dev; |
1940 | struct net_device *netdev; | 1890 | struct net_device *netdev; |
1941 | u8 mac_addr[ETH_ALEN]; | 1891 | u8 mac_addr[ETH_ALEN]; |
1942 | int ifidx = cb->args[0]; | ||
1943 | int sta_idx = cb->args[1]; | 1892 | int sta_idx = cb->args[1]; |
1944 | int err; | 1893 | int err; |
1945 | 1894 | ||
1946 | if (!ifidx) | 1895 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
1947 | ifidx = nl80211_get_ifidx(cb); | 1896 | if (err) |
1948 | if (ifidx < 0) | 1897 | return err; |
1949 | return ifidx; | ||
1950 | |||
1951 | rtnl_lock(); | ||
1952 | |||
1953 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1954 | if (!netdev) { | ||
1955 | err = -ENODEV; | ||
1956 | goto out_rtnl; | ||
1957 | } | ||
1958 | |||
1959 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
1960 | if (IS_ERR(dev)) { | ||
1961 | err = PTR_ERR(dev); | ||
1962 | goto out_rtnl; | ||
1963 | } | ||
1964 | 1898 | ||
1965 | if (!dev->ops->dump_station) { | 1899 | if (!dev->ops->dump_station) { |
1966 | err = -EOPNOTSUPP; | 1900 | err = -EOPNOTSUPP; |
@@ -1990,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1990 | cb->args[1] = sta_idx; | 1924 | cb->args[1] = sta_idx; |
1991 | err = skb->len; | 1925 | err = skb->len; |
1992 | out_err: | 1926 | out_err: |
1993 | cfg80211_unlock_rdev(dev); | 1927 | nl80211_finish_netdev_dump(dev); |
1994 | out_rtnl: | ||
1995 | rtnl_unlock(); | ||
1996 | 1928 | ||
1997 | return err; | 1929 | return err; |
1998 | } | 1930 | } |
1999 | 1931 | ||
2000 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1932 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
2001 | { | 1933 | { |
2002 | struct cfg80211_registered_device *rdev; | 1934 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2003 | int err; | 1935 | struct net_device *dev = info->user_ptr[1]; |
2004 | struct net_device *dev; | ||
2005 | struct station_info sinfo; | 1936 | struct station_info sinfo; |
2006 | struct sk_buff *msg; | 1937 | struct sk_buff *msg; |
2007 | u8 *mac_addr = NULL; | 1938 | u8 *mac_addr = NULL; |
1939 | int err; | ||
2008 | 1940 | ||
2009 | memset(&sinfo, 0, sizeof(sinfo)); | 1941 | memset(&sinfo, 0, sizeof(sinfo)); |
2010 | 1942 | ||
@@ -2013,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
2013 | 1945 | ||
2014 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1946 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2015 | 1947 | ||
2016 | rtnl_lock(); | 1948 | if (!rdev->ops->get_station) |
2017 | 1949 | return -EOPNOTSUPP; | |
2018 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2019 | if (err) | ||
2020 | goto out_rtnl; | ||
2021 | |||
2022 | if (!rdev->ops->get_station) { | ||
2023 | err = -EOPNOTSUPP; | ||
2024 | goto out; | ||
2025 | } | ||
2026 | 1950 | ||
2027 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); | 1951 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); |
2028 | if (err) | 1952 | if (err) |
2029 | goto out; | 1953 | return err; |
2030 | 1954 | ||
2031 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1955 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2032 | if (!msg) | 1956 | if (!msg) |
2033 | goto out; | 1957 | return -ENOMEM; |
2034 | 1958 | ||
2035 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1959 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
2036 | dev, mac_addr, &sinfo) < 0) | 1960 | dev, mac_addr, &sinfo) < 0) { |
2037 | goto out_free; | 1961 | nlmsg_free(msg); |
2038 | 1962 | return -ENOBUFS; | |
2039 | err = genlmsg_reply(msg, info); | 1963 | } |
2040 | goto out; | ||
2041 | |||
2042 | out_free: | ||
2043 | nlmsg_free(msg); | ||
2044 | out: | ||
2045 | cfg80211_unlock_rdev(rdev); | ||
2046 | dev_put(dev); | ||
2047 | out_rtnl: | ||
2048 | rtnl_unlock(); | ||
2049 | 1964 | ||
2050 | return err; | 1965 | return genlmsg_reply(msg, info); |
2051 | } | 1966 | } |
2052 | 1967 | ||
2053 | /* | 1968 | /* |
@@ -2077,9 +1992,9 @@ static int get_vlan(struct genl_info *info, | |||
2077 | 1992 | ||
2078 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1993 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
2079 | { | 1994 | { |
2080 | struct cfg80211_registered_device *rdev; | 1995 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2081 | int err; | 1996 | int err; |
2082 | struct net_device *dev; | 1997 | struct net_device *dev = info->user_ptr[1]; |
2083 | struct station_parameters params; | 1998 | struct station_parameters params; |
2084 | u8 *mac_addr = NULL; | 1999 | u8 *mac_addr = NULL; |
2085 | 2000 | ||
@@ -2117,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2117 | params.plink_action = | 2032 | params.plink_action = |
2118 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2033 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2119 | 2034 | ||
2120 | rtnl_lock(); | ||
2121 | |||
2122 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2123 | if (err) | ||
2124 | goto out_rtnl; | ||
2125 | |||
2126 | err = get_vlan(info, rdev, ¶ms.vlan); | 2035 | err = get_vlan(info, rdev, ¶ms.vlan); |
2127 | if (err) | 2036 | if (err) |
2128 | goto out; | 2037 | goto out; |
@@ -2184,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2184 | out: | 2093 | out: |
2185 | if (params.vlan) | 2094 | if (params.vlan) |
2186 | dev_put(params.vlan); | 2095 | dev_put(params.vlan); |
2187 | cfg80211_unlock_rdev(rdev); | ||
2188 | dev_put(dev); | ||
2189 | out_rtnl: | ||
2190 | rtnl_unlock(); | ||
2191 | 2096 | ||
2192 | return err; | 2097 | return err; |
2193 | } | 2098 | } |
2194 | 2099 | ||
2195 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 2100 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
2196 | { | 2101 | { |
2197 | struct cfg80211_registered_device *rdev; | 2102 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2198 | int err; | 2103 | int err; |
2199 | struct net_device *dev; | 2104 | struct net_device *dev = info->user_ptr[1]; |
2200 | struct station_parameters params; | 2105 | struct station_parameters params; |
2201 | u8 *mac_addr = NULL; | 2106 | u8 *mac_addr = NULL; |
2202 | 2107 | ||
@@ -2233,18 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2233 | if (parse_station_flags(info, ¶ms)) | 2138 | if (parse_station_flags(info, ¶ms)) |
2234 | return -EINVAL; | 2139 | return -EINVAL; |
2235 | 2140 | ||
2236 | rtnl_lock(); | ||
2237 | |||
2238 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2239 | if (err) | ||
2240 | goto out_rtnl; | ||
2241 | |||
2242 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2141 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2243 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2142 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2244 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2143 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2245 | err = -EINVAL; | 2144 | return -EINVAL; |
2246 | goto out; | ||
2247 | } | ||
2248 | 2145 | ||
2249 | err = get_vlan(info, rdev, ¶ms.vlan); | 2146 | err = get_vlan(info, rdev, ¶ms.vlan); |
2250 | if (err) | 2147 | if (err) |
@@ -2258,62 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2258 | goto out; | 2155 | goto out; |
2259 | } | 2156 | } |
2260 | 2157 | ||
2261 | if (!netif_running(dev)) { | ||
2262 | err = -ENETDOWN; | ||
2263 | goto out; | ||
2264 | } | ||
2265 | |||
2266 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2158 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2267 | 2159 | ||
2268 | out: | 2160 | out: |
2269 | if (params.vlan) | 2161 | if (params.vlan) |
2270 | dev_put(params.vlan); | 2162 | dev_put(params.vlan); |
2271 | cfg80211_unlock_rdev(rdev); | ||
2272 | dev_put(dev); | ||
2273 | out_rtnl: | ||
2274 | rtnl_unlock(); | ||
2275 | |||
2276 | return err; | 2163 | return err; |
2277 | } | 2164 | } |
2278 | 2165 | ||
2279 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 2166 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
2280 | { | 2167 | { |
2281 | struct cfg80211_registered_device *rdev; | 2168 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2282 | int err; | 2169 | struct net_device *dev = info->user_ptr[1]; |
2283 | struct net_device *dev; | ||
2284 | u8 *mac_addr = NULL; | 2170 | u8 *mac_addr = NULL; |
2285 | 2171 | ||
2286 | if (info->attrs[NL80211_ATTR_MAC]) | 2172 | if (info->attrs[NL80211_ATTR_MAC]) |
2287 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2173 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2288 | 2174 | ||
2289 | rtnl_lock(); | ||
2290 | |||
2291 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2292 | if (err) | ||
2293 | goto out_rtnl; | ||
2294 | |||
2295 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2175 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2296 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2176 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2297 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 2177 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2298 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2178 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2299 | err = -EINVAL; | 2179 | return -EINVAL; |
2300 | goto out; | ||
2301 | } | ||
2302 | |||
2303 | if (!rdev->ops->del_station) { | ||
2304 | err = -EOPNOTSUPP; | ||
2305 | goto out; | ||
2306 | } | ||
2307 | |||
2308 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); | ||
2309 | 2180 | ||
2310 | out: | 2181 | if (!rdev->ops->del_station) |
2311 | cfg80211_unlock_rdev(rdev); | 2182 | return -EOPNOTSUPP; |
2312 | dev_put(dev); | ||
2313 | out_rtnl: | ||
2314 | rtnl_unlock(); | ||
2315 | 2183 | ||
2316 | return err; | 2184 | return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); |
2317 | } | 2185 | } |
2318 | 2186 | ||
2319 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 2187 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -2376,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2376 | struct net_device *netdev; | 2244 | struct net_device *netdev; |
2377 | u8 dst[ETH_ALEN]; | 2245 | u8 dst[ETH_ALEN]; |
2378 | u8 next_hop[ETH_ALEN]; | 2246 | u8 next_hop[ETH_ALEN]; |
2379 | int ifidx = cb->args[0]; | ||
2380 | int path_idx = cb->args[1]; | 2247 | int path_idx = cb->args[1]; |
2381 | int err; | 2248 | int err; |
2382 | 2249 | ||
2383 | if (!ifidx) | 2250 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
2384 | ifidx = nl80211_get_ifidx(cb); | 2251 | if (err) |
2385 | if (ifidx < 0) | 2252 | return err; |
2386 | return ifidx; | ||
2387 | |||
2388 | rtnl_lock(); | ||
2389 | |||
2390 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
2391 | if (!netdev) { | ||
2392 | err = -ENODEV; | ||
2393 | goto out_rtnl; | ||
2394 | } | ||
2395 | |||
2396 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
2397 | if (IS_ERR(dev)) { | ||
2398 | err = PTR_ERR(dev); | ||
2399 | goto out_rtnl; | ||
2400 | } | ||
2401 | 2253 | ||
2402 | if (!dev->ops->dump_mpath) { | 2254 | if (!dev->ops->dump_mpath) { |
2403 | err = -EOPNOTSUPP; | 2255 | err = -EOPNOTSUPP; |
@@ -2431,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2431 | cb->args[1] = path_idx; | 2283 | cb->args[1] = path_idx; |
2432 | err = skb->len; | 2284 | err = skb->len; |
2433 | out_err: | 2285 | out_err: |
2434 | cfg80211_unlock_rdev(dev); | 2286 | nl80211_finish_netdev_dump(dev); |
2435 | out_rtnl: | ||
2436 | rtnl_unlock(); | ||
2437 | |||
2438 | return err; | 2287 | return err; |
2439 | } | 2288 | } |
2440 | 2289 | ||
2441 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 2290 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
2442 | { | 2291 | { |
2443 | struct cfg80211_registered_device *rdev; | 2292 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2444 | int err; | 2293 | int err; |
2445 | struct net_device *dev; | 2294 | struct net_device *dev = info->user_ptr[1]; |
2446 | struct mpath_info pinfo; | 2295 | struct mpath_info pinfo; |
2447 | struct sk_buff *msg; | 2296 | struct sk_buff *msg; |
2448 | u8 *dst = NULL; | 2297 | u8 *dst = NULL; |
@@ -2455,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2455 | 2304 | ||
2456 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2305 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2457 | 2306 | ||
2458 | rtnl_lock(); | 2307 | if (!rdev->ops->get_mpath) |
2459 | 2308 | return -EOPNOTSUPP; | |
2460 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2461 | if (err) | ||
2462 | goto out_rtnl; | ||
2463 | |||
2464 | if (!rdev->ops->get_mpath) { | ||
2465 | err = -EOPNOTSUPP; | ||
2466 | goto out; | ||
2467 | } | ||
2468 | 2309 | ||
2469 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2310 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2470 | err = -EOPNOTSUPP; | 2311 | return -EOPNOTSUPP; |
2471 | goto out; | ||
2472 | } | ||
2473 | 2312 | ||
2474 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); | 2313 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); |
2475 | if (err) | 2314 | if (err) |
2476 | goto out; | 2315 | return err; |
2477 | 2316 | ||
2478 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2317 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2479 | if (!msg) | 2318 | if (!msg) |
2480 | goto out; | 2319 | return -ENOMEM; |
2481 | 2320 | ||
2482 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 2321 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
2483 | dev, dst, next_hop, &pinfo) < 0) | 2322 | dev, dst, next_hop, &pinfo) < 0) { |
2484 | goto out_free; | 2323 | nlmsg_free(msg); |
2485 | 2324 | return -ENOBUFS; | |
2486 | err = genlmsg_reply(msg, info); | 2325 | } |
2487 | goto out; | ||
2488 | |||
2489 | out_free: | ||
2490 | nlmsg_free(msg); | ||
2491 | out: | ||
2492 | cfg80211_unlock_rdev(rdev); | ||
2493 | dev_put(dev); | ||
2494 | out_rtnl: | ||
2495 | rtnl_unlock(); | ||
2496 | 2326 | ||
2497 | return err; | 2327 | return genlmsg_reply(msg, info); |
2498 | } | 2328 | } |
2499 | 2329 | ||
2500 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 2330 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
2501 | { | 2331 | { |
2502 | struct cfg80211_registered_device *rdev; | 2332 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2503 | int err; | 2333 | struct net_device *dev = info->user_ptr[1]; |
2504 | struct net_device *dev; | ||
2505 | u8 *dst = NULL; | 2334 | u8 *dst = NULL; |
2506 | u8 *next_hop = NULL; | 2335 | u8 *next_hop = NULL; |
2507 | 2336 | ||
@@ -2514,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2514 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2343 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2515 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2344 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2516 | 2345 | ||
2517 | rtnl_lock(); | 2346 | if (!rdev->ops->change_mpath) |
2518 | 2347 | return -EOPNOTSUPP; | |
2519 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2520 | if (err) | ||
2521 | goto out_rtnl; | ||
2522 | |||
2523 | if (!rdev->ops->change_mpath) { | ||
2524 | err = -EOPNOTSUPP; | ||
2525 | goto out; | ||
2526 | } | ||
2527 | |||
2528 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2529 | err = -EOPNOTSUPP; | ||
2530 | goto out; | ||
2531 | } | ||
2532 | |||
2533 | if (!netif_running(dev)) { | ||
2534 | err = -ENETDOWN; | ||
2535 | goto out; | ||
2536 | } | ||
2537 | |||
2538 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2539 | 2348 | ||
2540 | out: | 2349 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2541 | cfg80211_unlock_rdev(rdev); | 2350 | return -EOPNOTSUPP; |
2542 | dev_put(dev); | ||
2543 | out_rtnl: | ||
2544 | rtnl_unlock(); | ||
2545 | 2351 | ||
2546 | return err; | 2352 | return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); |
2547 | } | 2353 | } |
2354 | |||
2548 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 2355 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
2549 | { | 2356 | { |
2550 | struct cfg80211_registered_device *rdev; | 2357 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2551 | int err; | 2358 | struct net_device *dev = info->user_ptr[1]; |
2552 | struct net_device *dev; | ||
2553 | u8 *dst = NULL; | 2359 | u8 *dst = NULL; |
2554 | u8 *next_hop = NULL; | 2360 | u8 *next_hop = NULL; |
2555 | 2361 | ||
@@ -2562,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2562 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2368 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2563 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2369 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2564 | 2370 | ||
2565 | rtnl_lock(); | 2371 | if (!rdev->ops->add_mpath) |
2566 | 2372 | return -EOPNOTSUPP; | |
2567 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2568 | if (err) | ||
2569 | goto out_rtnl; | ||
2570 | |||
2571 | if (!rdev->ops->add_mpath) { | ||
2572 | err = -EOPNOTSUPP; | ||
2573 | goto out; | ||
2574 | } | ||
2575 | |||
2576 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2577 | err = -EOPNOTSUPP; | ||
2578 | goto out; | ||
2579 | } | ||
2580 | |||
2581 | if (!netif_running(dev)) { | ||
2582 | err = -ENETDOWN; | ||
2583 | goto out; | ||
2584 | } | ||
2585 | |||
2586 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2587 | 2373 | ||
2588 | out: | 2374 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2589 | cfg80211_unlock_rdev(rdev); | 2375 | return -EOPNOTSUPP; |
2590 | dev_put(dev); | ||
2591 | out_rtnl: | ||
2592 | rtnl_unlock(); | ||
2593 | 2376 | ||
2594 | return err; | 2377 | return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); |
2595 | } | 2378 | } |
2596 | 2379 | ||
2597 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 2380 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
2598 | { | 2381 | { |
2599 | struct cfg80211_registered_device *rdev; | 2382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2600 | int err; | 2383 | struct net_device *dev = info->user_ptr[1]; |
2601 | struct net_device *dev; | ||
2602 | u8 *dst = NULL; | 2384 | u8 *dst = NULL; |
2603 | 2385 | ||
2604 | if (info->attrs[NL80211_ATTR_MAC]) | 2386 | if (info->attrs[NL80211_ATTR_MAC]) |
2605 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2387 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2606 | 2388 | ||
2607 | rtnl_lock(); | 2389 | if (!rdev->ops->del_mpath) |
2608 | 2390 | return -EOPNOTSUPP; | |
2609 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2610 | if (err) | ||
2611 | goto out_rtnl; | ||
2612 | |||
2613 | if (!rdev->ops->del_mpath) { | ||
2614 | err = -EOPNOTSUPP; | ||
2615 | goto out; | ||
2616 | } | ||
2617 | |||
2618 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); | ||
2619 | |||
2620 | out: | ||
2621 | cfg80211_unlock_rdev(rdev); | ||
2622 | dev_put(dev); | ||
2623 | out_rtnl: | ||
2624 | rtnl_unlock(); | ||
2625 | 2391 | ||
2626 | return err; | 2392 | return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); |
2627 | } | 2393 | } |
2628 | 2394 | ||
2629 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 2395 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
2630 | { | 2396 | { |
2631 | struct cfg80211_registered_device *rdev; | 2397 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2632 | int err; | 2398 | struct net_device *dev = info->user_ptr[1]; |
2633 | struct net_device *dev; | ||
2634 | struct bss_parameters params; | 2399 | struct bss_parameters params; |
2635 | 2400 | ||
2636 | memset(¶ms, 0, sizeof(params)); | 2401 | memset(¶ms, 0, sizeof(params)); |
@@ -2658,32 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2658 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2423 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2659 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2424 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2660 | 2425 | ||
2661 | rtnl_lock(); | 2426 | if (!rdev->ops->change_bss) |
2662 | 2427 | return -EOPNOTSUPP; | |
2663 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2664 | if (err) | ||
2665 | goto out_rtnl; | ||
2666 | |||
2667 | if (!rdev->ops->change_bss) { | ||
2668 | err = -EOPNOTSUPP; | ||
2669 | goto out; | ||
2670 | } | ||
2671 | 2428 | ||
2672 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2429 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2673 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2430 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2674 | err = -EOPNOTSUPP; | 2431 | return -EOPNOTSUPP; |
2675 | goto out; | ||
2676 | } | ||
2677 | |||
2678 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); | ||
2679 | |||
2680 | out: | ||
2681 | cfg80211_unlock_rdev(rdev); | ||
2682 | dev_put(dev); | ||
2683 | out_rtnl: | ||
2684 | rtnl_unlock(); | ||
2685 | 2432 | ||
2686 | return err; | 2433 | return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); |
2687 | } | 2434 | } |
2688 | 2435 | ||
2689 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 2436 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
@@ -2762,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2762 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2509 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2763 | struct genl_info *info) | 2510 | struct genl_info *info) |
2764 | { | 2511 | { |
2765 | struct cfg80211_registered_device *rdev; | 2512 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2766 | struct mesh_config cur_params; | 2513 | struct mesh_config cur_params; |
2767 | int err; | 2514 | int err; |
2768 | struct net_device *dev; | 2515 | struct net_device *dev = info->user_ptr[1]; |
2769 | void *hdr; | 2516 | void *hdr; |
2770 | struct nlattr *pinfoattr; | 2517 | struct nlattr *pinfoattr; |
2771 | struct sk_buff *msg; | 2518 | struct sk_buff *msg; |
2772 | 2519 | ||
2773 | rtnl_lock(); | 2520 | if (!rdev->ops->get_mesh_params) |
2774 | 2521 | return -EOPNOTSUPP; | |
2775 | /* Look up our device */ | ||
2776 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2777 | if (err) | ||
2778 | goto out_rtnl; | ||
2779 | |||
2780 | if (!rdev->ops->get_mesh_params) { | ||
2781 | err = -EOPNOTSUPP; | ||
2782 | goto out; | ||
2783 | } | ||
2784 | 2522 | ||
2785 | /* Get the mesh params */ | 2523 | /* Get the mesh params */ |
2786 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2524 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); |
2787 | if (err) | 2525 | if (err) |
2788 | goto out; | 2526 | return err; |
2789 | 2527 | ||
2790 | /* Draw up a netlink message to send back */ | 2528 | /* Draw up a netlink message to send back */ |
2791 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2529 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2792 | if (!msg) { | 2530 | if (!msg) |
2793 | err = -ENOBUFS; | 2531 | return -ENOMEM; |
2794 | goto out; | ||
2795 | } | ||
2796 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2532 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2797 | NL80211_CMD_GET_MESH_PARAMS); | 2533 | NL80211_CMD_GET_MESH_PARAMS); |
2798 | if (!hdr) | 2534 | if (!hdr) |
@@ -2831,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2831 | cur_params.dot11MeshHWMPRootMode); | 2567 | cur_params.dot11MeshHWMPRootMode); |
2832 | nla_nest_end(msg, pinfoattr); | 2568 | nla_nest_end(msg, pinfoattr); |
2833 | genlmsg_end(msg, hdr); | 2569 | genlmsg_end(msg, hdr); |
2834 | err = genlmsg_reply(msg, info); | 2570 | return genlmsg_reply(msg, info); |
2835 | goto out; | ||
2836 | 2571 | ||
2837 | nla_put_failure: | 2572 | nla_put_failure: |
2838 | genlmsg_cancel(msg, hdr); | 2573 | genlmsg_cancel(msg, hdr); |
2839 | nlmsg_free(msg); | 2574 | nlmsg_free(msg); |
2840 | err = -EMSGSIZE; | 2575 | return -ENOBUFS; |
2841 | out: | ||
2842 | /* Cleanup */ | ||
2843 | cfg80211_unlock_rdev(rdev); | ||
2844 | dev_put(dev); | ||
2845 | out_rtnl: | ||
2846 | rtnl_unlock(); | ||
2847 | |||
2848 | return err; | ||
2849 | } | 2576 | } |
2850 | 2577 | ||
2851 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 2578 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
@@ -2875,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2875 | 2602 | ||
2876 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2603 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2877 | { | 2604 | { |
2878 | int err; | ||
2879 | u32 mask; | 2605 | u32 mask; |
2880 | struct cfg80211_registered_device *rdev; | 2606 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2881 | struct net_device *dev; | 2607 | struct net_device *dev = info->user_ptr[1]; |
2882 | struct mesh_config cfg; | 2608 | struct mesh_config cfg; |
2883 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2609 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2884 | struct nlattr *parent_attr; | 2610 | struct nlattr *parent_attr; |
@@ -2890,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2890 | parent_attr, nl80211_meshconf_params_policy)) | 2616 | parent_attr, nl80211_meshconf_params_policy)) |
2891 | return -EINVAL; | 2617 | return -EINVAL; |
2892 | 2618 | ||
2893 | rtnl_lock(); | 2619 | if (!rdev->ops->set_mesh_params) |
2894 | 2620 | return -EOPNOTSUPP; | |
2895 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2896 | if (err) | ||
2897 | goto out_rtnl; | ||
2898 | |||
2899 | if (!rdev->ops->set_mesh_params) { | ||
2900 | err = -EOPNOTSUPP; | ||
2901 | goto out; | ||
2902 | } | ||
2903 | 2621 | ||
2904 | /* This makes sure that there aren't more than 32 mesh config | 2622 | /* This makes sure that there aren't more than 32 mesh config |
2905 | * parameters (otherwise our bitfield scheme would not work.) */ | 2623 | * parameters (otherwise our bitfield scheme would not work.) */ |
@@ -2945,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2945 | nla_get_u8); | 2663 | nla_get_u8); |
2946 | 2664 | ||
2947 | /* Apply changes */ | 2665 | /* Apply changes */ |
2948 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2666 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
2949 | |||
2950 | out: | ||
2951 | /* cleanup */ | ||
2952 | cfg80211_unlock_rdev(rdev); | ||
2953 | dev_put(dev); | ||
2954 | out_rtnl: | ||
2955 | rtnl_unlock(); | ||
2956 | |||
2957 | return err; | ||
2958 | } | 2667 | } |
2959 | 2668 | ||
2960 | #undef FILL_IN_MESH_PARAM_IF_SET | 2669 | #undef FILL_IN_MESH_PARAM_IF_SET |
@@ -3137,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3137 | 2846 | ||
3138 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2847 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3139 | { | 2848 | { |
3140 | struct cfg80211_registered_device *rdev; | 2849 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3141 | struct net_device *dev; | 2850 | struct net_device *dev = info->user_ptr[1]; |
3142 | struct cfg80211_scan_request *request; | 2851 | struct cfg80211_scan_request *request; |
3143 | struct cfg80211_ssid *ssid; | 2852 | struct cfg80211_ssid *ssid; |
3144 | struct ieee80211_channel *channel; | 2853 | struct ieee80211_channel *channel; |
@@ -3151,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3151 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 2860 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3152 | return -EINVAL; | 2861 | return -EINVAL; |
3153 | 2862 | ||
3154 | rtnl_lock(); | ||
3155 | |||
3156 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3157 | if (err) | ||
3158 | goto out_rtnl; | ||
3159 | |||
3160 | wiphy = &rdev->wiphy; | 2863 | wiphy = &rdev->wiphy; |
3161 | 2864 | ||
3162 | if (!rdev->ops->scan) { | 2865 | if (!rdev->ops->scan) |
3163 | err = -EOPNOTSUPP; | 2866 | return -EOPNOTSUPP; |
3164 | goto out; | ||
3165 | } | ||
3166 | |||
3167 | if (!netif_running(dev)) { | ||
3168 | err = -ENETDOWN; | ||
3169 | goto out; | ||
3170 | } | ||
3171 | 2867 | ||
3172 | if (rdev->scan_req) { | 2868 | if (rdev->scan_req) |
3173 | err = -EBUSY; | 2869 | return -EBUSY; |
3174 | goto out; | ||
3175 | } | ||
3176 | 2870 | ||
3177 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2871 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3178 | n_channels = validate_scan_freqs( | 2872 | n_channels = validate_scan_freqs( |
3179 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 2873 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
3180 | if (!n_channels) { | 2874 | if (!n_channels) |
3181 | err = -EINVAL; | 2875 | return -EINVAL; |
3182 | goto out; | ||
3183 | } | ||
3184 | } else { | 2876 | } else { |
3185 | n_channels = 0; | 2877 | n_channels = 0; |
3186 | 2878 | ||
@@ -3193,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3193 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 2885 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
3194 | n_ssids++; | 2886 | n_ssids++; |
3195 | 2887 | ||
3196 | if (n_ssids > wiphy->max_scan_ssids) { | 2888 | if (n_ssids > wiphy->max_scan_ssids) |
3197 | err = -EINVAL; | 2889 | return -EINVAL; |
3198 | goto out; | ||
3199 | } | ||
3200 | 2890 | ||
3201 | if (info->attrs[NL80211_ATTR_IE]) | 2891 | if (info->attrs[NL80211_ATTR_IE]) |
3202 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2892 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3203 | else | 2893 | else |
3204 | ie_len = 0; | 2894 | ie_len = 0; |
3205 | 2895 | ||
3206 | if (ie_len > wiphy->max_scan_ie_len) { | 2896 | if (ie_len > wiphy->max_scan_ie_len) |
3207 | err = -EINVAL; | 2897 | return -EINVAL; |
3208 | goto out; | ||
3209 | } | ||
3210 | 2898 | ||
3211 | request = kzalloc(sizeof(*request) | 2899 | request = kzalloc(sizeof(*request) |
3212 | + sizeof(*ssid) * n_ssids | 2900 | + sizeof(*ssid) * n_ssids |
3213 | + sizeof(channel) * n_channels | 2901 | + sizeof(channel) * n_channels |
3214 | + ie_len, GFP_KERNEL); | 2902 | + ie_len, GFP_KERNEL); |
3215 | if (!request) { | 2903 | if (!request) |
3216 | err = -ENOMEM; | 2904 | return -ENOMEM; |
3217 | goto out; | ||
3218 | } | ||
3219 | 2905 | ||
3220 | if (n_ssids) | 2906 | if (n_ssids) |
3221 | request->ssids = (void *)&request->channels[n_channels]; | 2907 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -3303,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3303 | if (!err) { | 2989 | if (!err) { |
3304 | nl80211_send_scan_start(rdev, dev); | 2990 | nl80211_send_scan_start(rdev, dev); |
3305 | dev_hold(dev); | 2991 | dev_hold(dev); |
3306 | } | 2992 | } else { |
3307 | |||
3308 | out_free: | 2993 | out_free: |
3309 | if (err) { | ||
3310 | rdev->scan_req = NULL; | 2994 | rdev->scan_req = NULL; |
3311 | kfree(request); | 2995 | kfree(request); |
3312 | } | 2996 | } |
3313 | out: | ||
3314 | cfg80211_unlock_rdev(rdev); | ||
3315 | dev_put(dev); | ||
3316 | out_rtnl: | ||
3317 | rtnl_unlock(); | ||
3318 | 2997 | ||
3319 | return err; | 2998 | return err; |
3320 | } | 2999 | } |
@@ -3411,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3411 | struct net_device *dev; | 3090 | struct net_device *dev; |
3412 | struct cfg80211_internal_bss *scan; | 3091 | struct cfg80211_internal_bss *scan; |
3413 | struct wireless_dev *wdev; | 3092 | struct wireless_dev *wdev; |
3414 | int ifidx = cb->args[0]; | ||
3415 | int start = cb->args[1], idx = 0; | 3093 | int start = cb->args[1], idx = 0; |
3416 | int err; | 3094 | int err; |
3417 | 3095 | ||
3418 | if (!ifidx) | 3096 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); |
3419 | ifidx = nl80211_get_ifidx(cb); | 3097 | if (err) |
3420 | if (ifidx < 0) | 3098 | return err; |
3421 | return ifidx; | ||
3422 | cb->args[0] = ifidx; | ||
3423 | |||
3424 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3425 | if (!dev) | ||
3426 | return -ENODEV; | ||
3427 | |||
3428 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3429 | if (IS_ERR(rdev)) { | ||
3430 | err = PTR_ERR(rdev); | ||
3431 | goto out_put_netdev; | ||
3432 | } | ||
3433 | 3099 | ||
3434 | wdev = dev->ieee80211_ptr; | 3100 | wdev = dev->ieee80211_ptr; |
3435 | 3101 | ||
@@ -3445,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3445 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3111 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3446 | rdev, wdev, scan) < 0) { | 3112 | rdev, wdev, scan) < 0) { |
3447 | idx--; | 3113 | idx--; |
3448 | goto out; | 3114 | break; |
3449 | } | 3115 | } |
3450 | } | 3116 | } |
3451 | 3117 | ||
3452 | out: | ||
3453 | spin_unlock_bh(&rdev->bss_lock); | 3118 | spin_unlock_bh(&rdev->bss_lock); |
3454 | wdev_unlock(wdev); | 3119 | wdev_unlock(wdev); |
3455 | 3120 | ||
3456 | cb->args[1] = idx; | 3121 | cb->args[1] = idx; |
3457 | err = skb->len; | 3122 | nl80211_finish_netdev_dump(rdev); |
3458 | cfg80211_unlock_rdev(rdev); | ||
3459 | out_put_netdev: | ||
3460 | dev_put(dev); | ||
3461 | 3123 | ||
3462 | return err; | 3124 | return skb->len; |
3463 | } | 3125 | } |
3464 | 3126 | ||
3465 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | 3127 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -3489,6 +3151,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3489 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | 3151 | if (survey->filled & SURVEY_INFO_NOISE_DBM) |
3490 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | 3152 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, |
3491 | survey->noise); | 3153 | survey->noise); |
3154 | if (survey->filled & SURVEY_INFO_IN_USE) | ||
3155 | NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); | ||
3492 | 3156 | ||
3493 | nla_nest_end(msg, infoattr); | 3157 | nla_nest_end(msg, infoattr); |
3494 | 3158 | ||
@@ -3505,29 +3169,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3505 | struct survey_info survey; | 3169 | struct survey_info survey; |
3506 | struct cfg80211_registered_device *dev; | 3170 | struct cfg80211_registered_device *dev; |
3507 | struct net_device *netdev; | 3171 | struct net_device *netdev; |
3508 | int ifidx = cb->args[0]; | ||
3509 | int survey_idx = cb->args[1]; | 3172 | int survey_idx = cb->args[1]; |
3510 | int res; | 3173 | int res; |
3511 | 3174 | ||
3512 | if (!ifidx) | 3175 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
3513 | ifidx = nl80211_get_ifidx(cb); | 3176 | if (res) |
3514 | if (ifidx < 0) | 3177 | return res; |
3515 | return ifidx; | ||
3516 | cb->args[0] = ifidx; | ||
3517 | |||
3518 | rtnl_lock(); | ||
3519 | |||
3520 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3521 | if (!netdev) { | ||
3522 | res = -ENODEV; | ||
3523 | goto out_rtnl; | ||
3524 | } | ||
3525 | |||
3526 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3527 | if (IS_ERR(dev)) { | ||
3528 | res = PTR_ERR(dev); | ||
3529 | goto out_rtnl; | ||
3530 | } | ||
3531 | 3178 | ||
3532 | if (!dev->ops->dump_survey) { | 3179 | if (!dev->ops->dump_survey) { |
3533 | res = -EOPNOTSUPP; | 3180 | res = -EOPNOTSUPP; |
@@ -3555,10 +3202,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3555 | cb->args[1] = survey_idx; | 3202 | cb->args[1] = survey_idx; |
3556 | res = skb->len; | 3203 | res = skb->len; |
3557 | out_err: | 3204 | out_err: |
3558 | cfg80211_unlock_rdev(dev); | 3205 | nl80211_finish_netdev_dump(dev); |
3559 | out_rtnl: | ||
3560 | rtnl_unlock(); | ||
3561 | |||
3562 | return res; | 3206 | return res; |
3563 | } | 3207 | } |
3564 | 3208 | ||
@@ -3591,8 +3235,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) | |||
3591 | 3235 | ||
3592 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3236 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3593 | { | 3237 | { |
3594 | struct cfg80211_registered_device *rdev; | 3238 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3595 | struct net_device *dev; | 3239 | struct net_device *dev = info->user_ptr[1]; |
3596 | struct ieee80211_channel *chan; | 3240 | struct ieee80211_channel *chan; |
3597 | const u8 *bssid, *ssid, *ie = NULL; | 3241 | const u8 *bssid, *ssid, *ie = NULL; |
3598 | int err, ssid_len, ie_len = 0; | 3242 | int err, ssid_len, ie_len = 0; |
@@ -3620,6 +3264,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3620 | return err; | 3264 | return err; |
3621 | 3265 | ||
3622 | if (key.idx >= 0) { | 3266 | if (key.idx >= 0) { |
3267 | if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) | ||
3268 | return -EINVAL; | ||
3623 | if (!key.p.key || !key.p.key_len) | 3269 | if (!key.p.key || !key.p.key_len) |
3624 | return -EINVAL; | 3270 | return -EINVAL; |
3625 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || | 3271 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || |
@@ -3634,12 +3280,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3634 | key.p.key = NULL; | 3280 | key.p.key = NULL; |
3635 | } | 3281 | } |
3636 | 3282 | ||
3637 | rtnl_lock(); | ||
3638 | |||
3639 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3640 | if (err) | ||
3641 | goto unlock_rtnl; | ||
3642 | |||
3643 | if (key.idx >= 0) { | 3283 | if (key.idx >= 0) { |
3644 | int i; | 3284 | int i; |
3645 | bool ok = false; | 3285 | bool ok = false; |
@@ -3649,35 +3289,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3649 | break; | 3289 | break; |
3650 | } | 3290 | } |
3651 | } | 3291 | } |
3652 | if (!ok) { | 3292 | if (!ok) |
3653 | err = -EINVAL; | 3293 | return -EINVAL; |
3654 | goto out; | ||
3655 | } | ||
3656 | } | 3294 | } |
3657 | 3295 | ||
3658 | if (!rdev->ops->auth) { | 3296 | if (!rdev->ops->auth) |
3659 | err = -EOPNOTSUPP; | 3297 | return -EOPNOTSUPP; |
3660 | goto out; | ||
3661 | } | ||
3662 | 3298 | ||
3663 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3299 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3664 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3300 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3665 | err = -EOPNOTSUPP; | 3301 | return -EOPNOTSUPP; |
3666 | goto out; | ||
3667 | } | ||
3668 | |||
3669 | if (!netif_running(dev)) { | ||
3670 | err = -ENETDOWN; | ||
3671 | goto out; | ||
3672 | } | ||
3673 | 3302 | ||
3674 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3303 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3675 | chan = ieee80211_get_channel(&rdev->wiphy, | 3304 | chan = ieee80211_get_channel(&rdev->wiphy, |
3676 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3305 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3677 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3306 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3678 | err = -EINVAL; | 3307 | return -EINVAL; |
3679 | goto out; | ||
3680 | } | ||
3681 | 3308 | ||
3682 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3309 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3683 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3310 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3688,24 +3315,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3688 | } | 3315 | } |
3689 | 3316 | ||
3690 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3317 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3691 | if (!nl80211_valid_auth_type(auth_type)) { | 3318 | if (!nl80211_valid_auth_type(auth_type)) |
3692 | err = -EINVAL; | 3319 | return -EINVAL; |
3693 | goto out; | ||
3694 | } | ||
3695 | 3320 | ||
3696 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3321 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3697 | 3322 | ||
3698 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3323 | return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3699 | ssid, ssid_len, ie, ie_len, | 3324 | ssid, ssid_len, ie, ie_len, |
3700 | key.p.key, key.p.key_len, key.idx, | 3325 | key.p.key, key.p.key_len, key.idx, |
3701 | local_state_change); | 3326 | local_state_change); |
3702 | |||
3703 | out: | ||
3704 | cfg80211_unlock_rdev(rdev); | ||
3705 | dev_put(dev); | ||
3706 | unlock_rtnl: | ||
3707 | rtnl_unlock(); | ||
3708 | return err; | ||
3709 | } | 3327 | } |
3710 | 3328 | ||
3711 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | 3329 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, |
@@ -3789,8 +3407,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | |||
3789 | 3407 | ||
3790 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3408 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3791 | { | 3409 | { |
3792 | struct cfg80211_registered_device *rdev; | 3410 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3793 | struct net_device *dev; | 3411 | struct net_device *dev = info->user_ptr[1]; |
3794 | struct cfg80211_crypto_settings crypto; | 3412 | struct cfg80211_crypto_settings crypto; |
3795 | struct ieee80211_channel *chan; | 3413 | struct ieee80211_channel *chan; |
3796 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3414 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
@@ -3805,36 +3423,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3805 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3423 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3806 | return -EINVAL; | 3424 | return -EINVAL; |
3807 | 3425 | ||
3808 | rtnl_lock(); | 3426 | if (!rdev->ops->assoc) |
3809 | 3427 | return -EOPNOTSUPP; | |
3810 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3811 | if (err) | ||
3812 | goto unlock_rtnl; | ||
3813 | |||
3814 | if (!rdev->ops->assoc) { | ||
3815 | err = -EOPNOTSUPP; | ||
3816 | goto out; | ||
3817 | } | ||
3818 | 3428 | ||
3819 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3429 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3820 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3430 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3821 | err = -EOPNOTSUPP; | 3431 | return -EOPNOTSUPP; |
3822 | goto out; | ||
3823 | } | ||
3824 | |||
3825 | if (!netif_running(dev)) { | ||
3826 | err = -ENETDOWN; | ||
3827 | goto out; | ||
3828 | } | ||
3829 | 3432 | ||
3830 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3433 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3831 | 3434 | ||
3832 | chan = ieee80211_get_channel(&rdev->wiphy, | 3435 | chan = ieee80211_get_channel(&rdev->wiphy, |
3833 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3436 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3834 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3437 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3835 | err = -EINVAL; | 3438 | return -EINVAL; |
3836 | goto out; | ||
3837 | } | ||
3838 | 3439 | ||
3839 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3440 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3840 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3441 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3849,10 +3450,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3849 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3450 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3850 | if (mfp == NL80211_MFP_REQUIRED) | 3451 | if (mfp == NL80211_MFP_REQUIRED) |
3851 | use_mfp = true; | 3452 | use_mfp = true; |
3852 | else if (mfp != NL80211_MFP_NO) { | 3453 | else if (mfp != NL80211_MFP_NO) |
3853 | err = -EINVAL; | 3454 | return -EINVAL; |
3854 | goto out; | ||
3855 | } | ||
3856 | } | 3455 | } |
3857 | 3456 | ||
3858 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 3457 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
@@ -3864,20 +3463,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3864 | ssid, ssid_len, ie, ie_len, use_mfp, | 3463 | ssid, ssid_len, ie, ie_len, use_mfp, |
3865 | &crypto); | 3464 | &crypto); |
3866 | 3465 | ||
3867 | out: | ||
3868 | cfg80211_unlock_rdev(rdev); | ||
3869 | dev_put(dev); | ||
3870 | unlock_rtnl: | ||
3871 | rtnl_unlock(); | ||
3872 | return err; | 3466 | return err; |
3873 | } | 3467 | } |
3874 | 3468 | ||
3875 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) |
3876 | { | 3470 | { |
3877 | struct cfg80211_registered_device *rdev; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3878 | struct net_device *dev; | 3472 | struct net_device *dev = info->user_ptr[1]; |
3879 | const u8 *ie = NULL, *bssid; | 3473 | const u8 *ie = NULL, *bssid; |
3880 | int err, ie_len = 0; | 3474 | int ie_len = 0; |
3881 | u16 reason_code; | 3475 | u16 reason_code; |
3882 | bool local_state_change; | 3476 | bool local_state_change; |
3883 | 3477 | ||
@@ -3890,35 +3484,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3890 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3484 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3891 | return -EINVAL; | 3485 | return -EINVAL; |
3892 | 3486 | ||
3893 | rtnl_lock(); | 3487 | if (!rdev->ops->deauth) |
3894 | 3488 | return -EOPNOTSUPP; | |
3895 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3896 | if (err) | ||
3897 | goto unlock_rtnl; | ||
3898 | |||
3899 | if (!rdev->ops->deauth) { | ||
3900 | err = -EOPNOTSUPP; | ||
3901 | goto out; | ||
3902 | } | ||
3903 | 3489 | ||
3904 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3490 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3905 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3491 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3906 | err = -EOPNOTSUPP; | 3492 | return -EOPNOTSUPP; |
3907 | goto out; | ||
3908 | } | ||
3909 | |||
3910 | if (!netif_running(dev)) { | ||
3911 | err = -ENETDOWN; | ||
3912 | goto out; | ||
3913 | } | ||
3914 | 3493 | ||
3915 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3494 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3916 | 3495 | ||
3917 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3496 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3918 | if (reason_code == 0) { | 3497 | if (reason_code == 0) { |
3919 | /* Reason Code 0 is reserved */ | 3498 | /* Reason Code 0 is reserved */ |
3920 | err = -EINVAL; | 3499 | return -EINVAL; |
3921 | goto out; | ||
3922 | } | 3500 | } |
3923 | 3501 | ||
3924 | if (info->attrs[NL80211_ATTR_IE]) { | 3502 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3928,23 +3506,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3928 | 3506 | ||
3929 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3507 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3930 | 3508 | ||
3931 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | 3509 | return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, |
3932 | local_state_change); | 3510 | local_state_change); |
3933 | |||
3934 | out: | ||
3935 | cfg80211_unlock_rdev(rdev); | ||
3936 | dev_put(dev); | ||
3937 | unlock_rtnl: | ||
3938 | rtnl_unlock(); | ||
3939 | return err; | ||
3940 | } | 3511 | } |
3941 | 3512 | ||
3942 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 3513 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
3943 | { | 3514 | { |
3944 | struct cfg80211_registered_device *rdev; | 3515 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3945 | struct net_device *dev; | 3516 | struct net_device *dev = info->user_ptr[1]; |
3946 | const u8 *ie = NULL, *bssid; | 3517 | const u8 *ie = NULL, *bssid; |
3947 | int err, ie_len = 0; | 3518 | int ie_len = 0; |
3948 | u16 reason_code; | 3519 | u16 reason_code; |
3949 | bool local_state_change; | 3520 | bool local_state_change; |
3950 | 3521 | ||
@@ -3957,35 +3528,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3957 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3528 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3958 | return -EINVAL; | 3529 | return -EINVAL; |
3959 | 3530 | ||
3960 | rtnl_lock(); | 3531 | if (!rdev->ops->disassoc) |
3961 | 3532 | return -EOPNOTSUPP; | |
3962 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3963 | if (err) | ||
3964 | goto unlock_rtnl; | ||
3965 | |||
3966 | if (!rdev->ops->disassoc) { | ||
3967 | err = -EOPNOTSUPP; | ||
3968 | goto out; | ||
3969 | } | ||
3970 | 3533 | ||
3971 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3534 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3972 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3535 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3973 | err = -EOPNOTSUPP; | 3536 | return -EOPNOTSUPP; |
3974 | goto out; | ||
3975 | } | ||
3976 | |||
3977 | if (!netif_running(dev)) { | ||
3978 | err = -ENETDOWN; | ||
3979 | goto out; | ||
3980 | } | ||
3981 | 3537 | ||
3982 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3538 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3983 | 3539 | ||
3984 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3540 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3985 | if (reason_code == 0) { | 3541 | if (reason_code == 0) { |
3986 | /* Reason Code 0 is reserved */ | 3542 | /* Reason Code 0 is reserved */ |
3987 | err = -EINVAL; | 3543 | return -EINVAL; |
3988 | goto out; | ||
3989 | } | 3544 | } |
3990 | 3545 | ||
3991 | if (info->attrs[NL80211_ATTR_IE]) { | 3546 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3995,21 +3550,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3995 | 3550 | ||
3996 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3551 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3997 | 3552 | ||
3998 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | 3553 | return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, |
3999 | local_state_change); | 3554 | local_state_change); |
4000 | |||
4001 | out: | ||
4002 | cfg80211_unlock_rdev(rdev); | ||
4003 | dev_put(dev); | ||
4004 | unlock_rtnl: | ||
4005 | rtnl_unlock(); | ||
4006 | return err; | ||
4007 | } | 3555 | } |
4008 | 3556 | ||
4009 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3557 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
4010 | { | 3558 | { |
4011 | struct cfg80211_registered_device *rdev; | 3559 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4012 | struct net_device *dev; | 3560 | struct net_device *dev = info->user_ptr[1]; |
4013 | struct cfg80211_ibss_params ibss; | 3561 | struct cfg80211_ibss_params ibss; |
4014 | struct wiphy *wiphy; | 3562 | struct wiphy *wiphy; |
4015 | struct cfg80211_cached_keys *connkeys = NULL; | 3563 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4034,26 +3582,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4034 | return -EINVAL; | 3582 | return -EINVAL; |
4035 | } | 3583 | } |
4036 | 3584 | ||
4037 | rtnl_lock(); | 3585 | if (!rdev->ops->join_ibss) |
4038 | 3586 | return -EOPNOTSUPP; | |
4039 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4040 | if (err) | ||
4041 | goto unlock_rtnl; | ||
4042 | |||
4043 | if (!rdev->ops->join_ibss) { | ||
4044 | err = -EOPNOTSUPP; | ||
4045 | goto out; | ||
4046 | } | ||
4047 | |||
4048 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4049 | err = -EOPNOTSUPP; | ||
4050 | goto out; | ||
4051 | } | ||
4052 | 3587 | ||
4053 | if (!netif_running(dev)) { | 3588 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
4054 | err = -ENETDOWN; | 3589 | return -EOPNOTSUPP; |
4055 | goto out; | ||
4056 | } | ||
4057 | 3590 | ||
4058 | wiphy = &rdev->wiphy; | 3591 | wiphy = &rdev->wiphy; |
4059 | 3592 | ||
@@ -4071,24 +3604,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4071 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3604 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4072 | if (!ibss.channel || | 3605 | if (!ibss.channel || |
4073 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | 3606 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || |
4074 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | 3607 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) |
4075 | err = -EINVAL; | 3608 | return -EINVAL; |
4076 | goto out; | ||
4077 | } | ||
4078 | 3609 | ||
4079 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 3610 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
4080 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 3611 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
4081 | 3612 | ||
4082 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | ||
4083 | connkeys = nl80211_parse_connkeys(rdev, | ||
4084 | info->attrs[NL80211_ATTR_KEYS]); | ||
4085 | if (IS_ERR(connkeys)) { | ||
4086 | err = PTR_ERR(connkeys); | ||
4087 | connkeys = NULL; | ||
4088 | goto out; | ||
4089 | } | ||
4090 | } | ||
4091 | |||
4092 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 3613 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
4093 | u8 *rates = | 3614 | u8 *rates = |
4094 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 3615 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
@@ -4098,10 +3619,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4098 | wiphy->bands[ibss.channel->band]; | 3619 | wiphy->bands[ibss.channel->band]; |
4099 | int i, j; | 3620 | int i, j; |
4100 | 3621 | ||
4101 | if (n_rates == 0) { | 3622 | if (n_rates == 0) |
4102 | err = -EINVAL; | 3623 | return -EINVAL; |
4103 | goto out; | ||
4104 | } | ||
4105 | 3624 | ||
4106 | for (i = 0; i < n_rates; i++) { | 3625 | for (i = 0; i < n_rates; i++) { |
4107 | int rate = (rates[i] & 0x7f) * 5; | 3626 | int rate = (rates[i] & 0x7f) * 5; |
@@ -4114,60 +3633,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4114 | break; | 3633 | break; |
4115 | } | 3634 | } |
4116 | } | 3635 | } |
4117 | if (!found) { | 3636 | if (!found) |
4118 | err = -EINVAL; | 3637 | return -EINVAL; |
4119 | goto out; | ||
4120 | } | ||
4121 | } | 3638 | } |
4122 | } | 3639 | } |
4123 | 3640 | ||
4124 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 3641 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3642 | connkeys = nl80211_parse_connkeys(rdev, | ||
3643 | info->attrs[NL80211_ATTR_KEYS]); | ||
3644 | if (IS_ERR(connkeys)) | ||
3645 | return PTR_ERR(connkeys); | ||
3646 | } | ||
4125 | 3647 | ||
4126 | out: | 3648 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
4127 | cfg80211_unlock_rdev(rdev); | ||
4128 | dev_put(dev); | ||
4129 | unlock_rtnl: | ||
4130 | if (err) | 3649 | if (err) |
4131 | kfree(connkeys); | 3650 | kfree(connkeys); |
4132 | rtnl_unlock(); | ||
4133 | return err; | 3651 | return err; |
4134 | } | 3652 | } |
4135 | 3653 | ||
4136 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | 3654 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) |
4137 | { | 3655 | { |
4138 | struct cfg80211_registered_device *rdev; | 3656 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4139 | struct net_device *dev; | 3657 | struct net_device *dev = info->user_ptr[1]; |
4140 | int err; | ||
4141 | 3658 | ||
4142 | rtnl_lock(); | 3659 | if (!rdev->ops->leave_ibss) |
4143 | 3660 | return -EOPNOTSUPP; | |
4144 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4145 | if (err) | ||
4146 | goto unlock_rtnl; | ||
4147 | |||
4148 | if (!rdev->ops->leave_ibss) { | ||
4149 | err = -EOPNOTSUPP; | ||
4150 | goto out; | ||
4151 | } | ||
4152 | |||
4153 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4154 | err = -EOPNOTSUPP; | ||
4155 | goto out; | ||
4156 | } | ||
4157 | |||
4158 | if (!netif_running(dev)) { | ||
4159 | err = -ENETDOWN; | ||
4160 | goto out; | ||
4161 | } | ||
4162 | 3661 | ||
4163 | err = cfg80211_leave_ibss(rdev, dev, false); | 3662 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3663 | return -EOPNOTSUPP; | ||
4164 | 3664 | ||
4165 | out: | 3665 | return cfg80211_leave_ibss(rdev, dev, false); |
4166 | cfg80211_unlock_rdev(rdev); | ||
4167 | dev_put(dev); | ||
4168 | unlock_rtnl: | ||
4169 | rtnl_unlock(); | ||
4170 | return err; | ||
4171 | } | 3666 | } |
4172 | 3667 | ||
4173 | #ifdef CONFIG_NL80211_TESTMODE | 3668 | #ifdef CONFIG_NL80211_TESTMODE |
@@ -4177,20 +3672,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { | |||
4177 | 3672 | ||
4178 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 3673 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
4179 | { | 3674 | { |
4180 | struct cfg80211_registered_device *rdev; | 3675 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4181 | int err; | 3676 | int err; |
4182 | 3677 | ||
4183 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 3678 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
4184 | return -EINVAL; | 3679 | return -EINVAL; |
4185 | 3680 | ||
4186 | rtnl_lock(); | ||
4187 | |||
4188 | rdev = cfg80211_get_dev_from_info(info); | ||
4189 | if (IS_ERR(rdev)) { | ||
4190 | err = PTR_ERR(rdev); | ||
4191 | goto unlock_rtnl; | ||
4192 | } | ||
4193 | |||
4194 | err = -EOPNOTSUPP; | 3681 | err = -EOPNOTSUPP; |
4195 | if (rdev->ops->testmode_cmd) { | 3682 | if (rdev->ops->testmode_cmd) { |
4196 | rdev->testmode_info = info; | 3683 | rdev->testmode_info = info; |
@@ -4200,10 +3687,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4200 | rdev->testmode_info = NULL; | 3687 | rdev->testmode_info = NULL; |
4201 | } | 3688 | } |
4202 | 3689 | ||
4203 | cfg80211_unlock_rdev(rdev); | ||
4204 | |||
4205 | unlock_rtnl: | ||
4206 | rtnl_unlock(); | ||
4207 | return err; | 3690 | return err; |
4208 | } | 3691 | } |
4209 | 3692 | ||
@@ -4294,8 +3777,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); | |||
4294 | 3777 | ||
4295 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 3778 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
4296 | { | 3779 | { |
4297 | struct cfg80211_registered_device *rdev; | 3780 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4298 | struct net_device *dev; | 3781 | struct net_device *dev = info->user_ptr[1]; |
4299 | struct cfg80211_connect_params connect; | 3782 | struct cfg80211_connect_params connect; |
4300 | struct wiphy *wiphy; | 3783 | struct wiphy *wiphy; |
4301 | struct cfg80211_cached_keys *connkeys = NULL; | 3784 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4324,22 +3807,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4324 | NL80211_MAX_NR_CIPHER_SUITES); | 3807 | NL80211_MAX_NR_CIPHER_SUITES); |
4325 | if (err) | 3808 | if (err) |
4326 | return err; | 3809 | return err; |
4327 | rtnl_lock(); | ||
4328 | |||
4329 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4330 | if (err) | ||
4331 | goto unlock_rtnl; | ||
4332 | 3810 | ||
4333 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3811 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4334 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3812 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4335 | err = -EOPNOTSUPP; | 3813 | return -EOPNOTSUPP; |
4336 | goto out; | ||
4337 | } | ||
4338 | |||
4339 | if (!netif_running(dev)) { | ||
4340 | err = -ENETDOWN; | ||
4341 | goto out; | ||
4342 | } | ||
4343 | 3814 | ||
4344 | wiphy = &rdev->wiphy; | 3815 | wiphy = &rdev->wiphy; |
4345 | 3816 | ||
@@ -4358,39 +3829,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4358 | ieee80211_get_channel(wiphy, | 3829 | ieee80211_get_channel(wiphy, |
4359 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3830 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4360 | if (!connect.channel || | 3831 | if (!connect.channel || |
4361 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | 3832 | connect.channel->flags & IEEE80211_CHAN_DISABLED) |
4362 | err = -EINVAL; | 3833 | return -EINVAL; |
4363 | goto out; | ||
4364 | } | ||
4365 | } | 3834 | } |
4366 | 3835 | ||
4367 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3836 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
4368 | connkeys = nl80211_parse_connkeys(rdev, | 3837 | connkeys = nl80211_parse_connkeys(rdev, |
4369 | info->attrs[NL80211_ATTR_KEYS]); | 3838 | info->attrs[NL80211_ATTR_KEYS]); |
4370 | if (IS_ERR(connkeys)) { | 3839 | if (IS_ERR(connkeys)) |
4371 | err = PTR_ERR(connkeys); | 3840 | return PTR_ERR(connkeys); |
4372 | connkeys = NULL; | ||
4373 | goto out; | ||
4374 | } | ||
4375 | } | 3841 | } |
4376 | 3842 | ||
4377 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 3843 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4378 | |||
4379 | out: | ||
4380 | cfg80211_unlock_rdev(rdev); | ||
4381 | dev_put(dev); | ||
4382 | unlock_rtnl: | ||
4383 | if (err) | 3844 | if (err) |
4384 | kfree(connkeys); | 3845 | kfree(connkeys); |
4385 | rtnl_unlock(); | ||
4386 | return err; | 3846 | return err; |
4387 | } | 3847 | } |
4388 | 3848 | ||
4389 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | 3849 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) |
4390 | { | 3850 | { |
4391 | struct cfg80211_registered_device *rdev; | 3851 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4392 | struct net_device *dev; | 3852 | struct net_device *dev = info->user_ptr[1]; |
4393 | int err; | ||
4394 | u16 reason; | 3853 | u16 reason; |
4395 | 3854 | ||
4396 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3855 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
@@ -4401,36 +3860,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4401 | if (reason == 0) | 3860 | if (reason == 0) |
4402 | return -EINVAL; | 3861 | return -EINVAL; |
4403 | 3862 | ||
4404 | rtnl_lock(); | ||
4405 | |||
4406 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4407 | if (err) | ||
4408 | goto unlock_rtnl; | ||
4409 | |||
4410 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3863 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4411 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3864 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4412 | err = -EOPNOTSUPP; | 3865 | return -EOPNOTSUPP; |
4413 | goto out; | ||
4414 | } | ||
4415 | |||
4416 | if (!netif_running(dev)) { | ||
4417 | err = -ENETDOWN; | ||
4418 | goto out; | ||
4419 | } | ||
4420 | |||
4421 | err = cfg80211_disconnect(rdev, dev, reason, true); | ||
4422 | 3866 | ||
4423 | out: | 3867 | return cfg80211_disconnect(rdev, dev, reason, true); |
4424 | cfg80211_unlock_rdev(rdev); | ||
4425 | dev_put(dev); | ||
4426 | unlock_rtnl: | ||
4427 | rtnl_unlock(); | ||
4428 | return err; | ||
4429 | } | 3868 | } |
4430 | 3869 | ||
4431 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 3870 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
4432 | { | 3871 | { |
4433 | struct cfg80211_registered_device *rdev; | 3872 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4434 | struct net *net; | 3873 | struct net *net; |
4435 | int err; | 3874 | int err; |
4436 | u32 pid; | 3875 | u32 pid; |
@@ -4440,43 +3879,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | |||
4440 | 3879 | ||
4441 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | 3880 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); |
4442 | 3881 | ||
4443 | rtnl_lock(); | ||
4444 | |||
4445 | rdev = cfg80211_get_dev_from_info(info); | ||
4446 | if (IS_ERR(rdev)) { | ||
4447 | err = PTR_ERR(rdev); | ||
4448 | goto out_rtnl; | ||
4449 | } | ||
4450 | |||
4451 | net = get_net_ns_by_pid(pid); | 3882 | net = get_net_ns_by_pid(pid); |
4452 | if (IS_ERR(net)) { | 3883 | if (IS_ERR(net)) |
4453 | err = PTR_ERR(net); | 3884 | return PTR_ERR(net); |
4454 | goto out; | ||
4455 | } | ||
4456 | 3885 | ||
4457 | err = 0; | 3886 | err = 0; |
4458 | 3887 | ||
4459 | /* check if anything to do */ | 3888 | /* check if anything to do */ |
4460 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 3889 | if (!net_eq(wiphy_net(&rdev->wiphy), net)) |
4461 | goto out_put_net; | 3890 | err = cfg80211_switch_netns(rdev, net); |
4462 | 3891 | ||
4463 | err = cfg80211_switch_netns(rdev, net); | ||
4464 | out_put_net: | ||
4465 | put_net(net); | 3892 | put_net(net); |
4466 | out: | ||
4467 | cfg80211_unlock_rdev(rdev); | ||
4468 | out_rtnl: | ||
4469 | rtnl_unlock(); | ||
4470 | return err; | 3893 | return err; |
4471 | } | 3894 | } |
4472 | 3895 | ||
4473 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | 3896 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) |
4474 | { | 3897 | { |
4475 | struct cfg80211_registered_device *rdev; | 3898 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4476 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | 3899 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, |
4477 | struct cfg80211_pmksa *pmksa) = NULL; | 3900 | struct cfg80211_pmksa *pmksa) = NULL; |
4478 | int err; | 3901 | struct net_device *dev = info->user_ptr[1]; |
4479 | struct net_device *dev; | ||
4480 | struct cfg80211_pmksa pmksa; | 3902 | struct cfg80211_pmksa pmksa; |
4481 | 3903 | ||
4482 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | 3904 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
@@ -4487,20 +3909,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4487 | if (!info->attrs[NL80211_ATTR_PMKID]) | 3909 | if (!info->attrs[NL80211_ATTR_PMKID]) |
4488 | return -EINVAL; | 3910 | return -EINVAL; |
4489 | 3911 | ||
4490 | rtnl_lock(); | ||
4491 | |||
4492 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4493 | if (err) | ||
4494 | goto out_rtnl; | ||
4495 | |||
4496 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | 3912 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
4497 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3913 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4498 | 3914 | ||
4499 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3915 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4500 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3916 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4501 | err = -EOPNOTSUPP; | 3917 | return -EOPNOTSUPP; |
4502 | goto out; | ||
4503 | } | ||
4504 | 3918 | ||
4505 | switch (info->genlhdr->cmd) { | 3919 | switch (info->genlhdr->cmd) { |
4506 | case NL80211_CMD_SET_PMKSA: | 3920 | case NL80211_CMD_SET_PMKSA: |
@@ -4514,62 +3928,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4514 | break; | 3928 | break; |
4515 | } | 3929 | } |
4516 | 3930 | ||
4517 | if (!rdev_ops) { | 3931 | if (!rdev_ops) |
4518 | err = -EOPNOTSUPP; | 3932 | return -EOPNOTSUPP; |
4519 | goto out; | ||
4520 | } | ||
4521 | |||
4522 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | ||
4523 | |||
4524 | out: | ||
4525 | cfg80211_unlock_rdev(rdev); | ||
4526 | dev_put(dev); | ||
4527 | out_rtnl: | ||
4528 | rtnl_unlock(); | ||
4529 | 3933 | ||
4530 | return err; | 3934 | return rdev_ops(&rdev->wiphy, dev, &pmksa); |
4531 | } | 3935 | } |
4532 | 3936 | ||
4533 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | 3937 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) |
4534 | { | 3938 | { |
4535 | struct cfg80211_registered_device *rdev; | 3939 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4536 | int err; | 3940 | struct net_device *dev = info->user_ptr[1]; |
4537 | struct net_device *dev; | ||
4538 | |||
4539 | rtnl_lock(); | ||
4540 | |||
4541 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4542 | if (err) | ||
4543 | goto out_rtnl; | ||
4544 | 3941 | ||
4545 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3942 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4546 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3943 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4547 | err = -EOPNOTSUPP; | 3944 | return -EOPNOTSUPP; |
4548 | goto out; | ||
4549 | } | ||
4550 | |||
4551 | if (!rdev->ops->flush_pmksa) { | ||
4552 | err = -EOPNOTSUPP; | ||
4553 | goto out; | ||
4554 | } | ||
4555 | |||
4556 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4557 | |||
4558 | out: | ||
4559 | cfg80211_unlock_rdev(rdev); | ||
4560 | dev_put(dev); | ||
4561 | out_rtnl: | ||
4562 | rtnl_unlock(); | ||
4563 | 3945 | ||
4564 | return err; | 3946 | if (!rdev->ops->flush_pmksa) |
3947 | return -EOPNOTSUPP; | ||
4565 | 3948 | ||
3949 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4566 | } | 3950 | } |
4567 | 3951 | ||
4568 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 3952 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4569 | struct genl_info *info) | 3953 | struct genl_info *info) |
4570 | { | 3954 | { |
4571 | struct cfg80211_registered_device *rdev; | 3955 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4572 | struct net_device *dev; | 3956 | struct net_device *dev = info->user_ptr[1]; |
4573 | struct ieee80211_channel *chan; | 3957 | struct ieee80211_channel *chan; |
4574 | struct sk_buff *msg; | 3958 | struct sk_buff *msg; |
4575 | void *hdr; | 3959 | void *hdr; |
@@ -4591,21 +3975,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4591 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 3975 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) |
4592 | return -EINVAL; | 3976 | return -EINVAL; |
4593 | 3977 | ||
4594 | rtnl_lock(); | 3978 | if (!rdev->ops->remain_on_channel) |
4595 | 3979 | return -EOPNOTSUPP; | |
4596 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4597 | if (err) | ||
4598 | goto unlock_rtnl; | ||
4599 | |||
4600 | if (!rdev->ops->remain_on_channel) { | ||
4601 | err = -EOPNOTSUPP; | ||
4602 | goto out; | ||
4603 | } | ||
4604 | |||
4605 | if (!netif_running(dev)) { | ||
4606 | err = -ENETDOWN; | ||
4607 | goto out; | ||
4608 | } | ||
4609 | 3980 | ||
4610 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 3981 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4611 | channel_type = nla_get_u32( | 3982 | channel_type = nla_get_u32( |
@@ -4613,24 +3984,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4613 | if (channel_type != NL80211_CHAN_NO_HT && | 3984 | if (channel_type != NL80211_CHAN_NO_HT && |
4614 | channel_type != NL80211_CHAN_HT20 && | 3985 | channel_type != NL80211_CHAN_HT20 && |
4615 | channel_type != NL80211_CHAN_HT40PLUS && | 3986 | channel_type != NL80211_CHAN_HT40PLUS && |
4616 | channel_type != NL80211_CHAN_HT40MINUS) { | 3987 | channel_type != NL80211_CHAN_HT40MINUS) |
4617 | err = -EINVAL; | 3988 | return -EINVAL; |
4618 | goto out; | ||
4619 | } | ||
4620 | } | 3989 | } |
4621 | 3990 | ||
4622 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 3991 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4623 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 3992 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4624 | if (chan == NULL) { | 3993 | if (chan == NULL) |
4625 | err = -EINVAL; | 3994 | return -EINVAL; |
4626 | goto out; | ||
4627 | } | ||
4628 | 3995 | ||
4629 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 3996 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4630 | if (!msg) { | 3997 | if (!msg) |
4631 | err = -ENOMEM; | 3998 | return -ENOMEM; |
4632 | goto out; | ||
4633 | } | ||
4634 | 3999 | ||
4635 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4000 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4636 | NL80211_CMD_REMAIN_ON_CHANNEL); | 4001 | NL80211_CMD_REMAIN_ON_CHANNEL); |
@@ -4649,58 +4014,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4649 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4014 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4650 | 4015 | ||
4651 | genlmsg_end(msg, hdr); | 4016 | genlmsg_end(msg, hdr); |
4652 | err = genlmsg_reply(msg, info); | 4017 | |
4653 | goto out; | 4018 | return genlmsg_reply(msg, info); |
4654 | 4019 | ||
4655 | nla_put_failure: | 4020 | nla_put_failure: |
4656 | err = -ENOBUFS; | 4021 | err = -ENOBUFS; |
4657 | free_msg: | 4022 | free_msg: |
4658 | nlmsg_free(msg); | 4023 | nlmsg_free(msg); |
4659 | out: | ||
4660 | cfg80211_unlock_rdev(rdev); | ||
4661 | dev_put(dev); | ||
4662 | unlock_rtnl: | ||
4663 | rtnl_unlock(); | ||
4664 | return err; | 4024 | return err; |
4665 | } | 4025 | } |
4666 | 4026 | ||
4667 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | 4027 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, |
4668 | struct genl_info *info) | 4028 | struct genl_info *info) |
4669 | { | 4029 | { |
4670 | struct cfg80211_registered_device *rdev; | 4030 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4671 | struct net_device *dev; | 4031 | struct net_device *dev = info->user_ptr[1]; |
4672 | u64 cookie; | 4032 | u64 cookie; |
4673 | int err; | ||
4674 | 4033 | ||
4675 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 4034 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
4676 | return -EINVAL; | 4035 | return -EINVAL; |
4677 | 4036 | ||
4678 | rtnl_lock(); | 4037 | if (!rdev->ops->cancel_remain_on_channel) |
4679 | 4038 | return -EOPNOTSUPP; | |
4680 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4681 | if (err) | ||
4682 | goto unlock_rtnl; | ||
4683 | |||
4684 | if (!rdev->ops->cancel_remain_on_channel) { | ||
4685 | err = -EOPNOTSUPP; | ||
4686 | goto out; | ||
4687 | } | ||
4688 | |||
4689 | if (!netif_running(dev)) { | ||
4690 | err = -ENETDOWN; | ||
4691 | goto out; | ||
4692 | } | ||
4693 | 4039 | ||
4694 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 4040 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
4695 | 4041 | ||
4696 | err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 4042 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); |
4697 | |||
4698 | out: | ||
4699 | cfg80211_unlock_rdev(rdev); | ||
4700 | dev_put(dev); | ||
4701 | unlock_rtnl: | ||
4702 | rtnl_unlock(); | ||
4703 | return err; | ||
4704 | } | 4043 | } |
4705 | 4044 | ||
4706 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 4045 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -4736,26 +4075,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4736 | struct genl_info *info) | 4075 | struct genl_info *info) |
4737 | { | 4076 | { |
4738 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | 4077 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; |
4739 | struct cfg80211_registered_device *rdev; | 4078 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4740 | struct cfg80211_bitrate_mask mask; | 4079 | struct cfg80211_bitrate_mask mask; |
4741 | int err, rem, i; | 4080 | int rem, i; |
4742 | struct net_device *dev; | 4081 | struct net_device *dev = info->user_ptr[1]; |
4743 | struct nlattr *tx_rates; | 4082 | struct nlattr *tx_rates; |
4744 | struct ieee80211_supported_band *sband; | 4083 | struct ieee80211_supported_band *sband; |
4745 | 4084 | ||
4746 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | 4085 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) |
4747 | return -EINVAL; | 4086 | return -EINVAL; |
4748 | 4087 | ||
4749 | rtnl_lock(); | 4088 | if (!rdev->ops->set_bitrate_mask) |
4750 | 4089 | return -EOPNOTSUPP; | |
4751 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4752 | if (err) | ||
4753 | goto unlock_rtnl; | ||
4754 | |||
4755 | if (!rdev->ops->set_bitrate_mask) { | ||
4756 | err = -EOPNOTSUPP; | ||
4757 | goto unlock; | ||
4758 | } | ||
4759 | 4090 | ||
4760 | memset(&mask, 0, sizeof(mask)); | 4091 | memset(&mask, 0, sizeof(mask)); |
4761 | /* Default to all rates enabled */ | 4092 | /* Default to all rates enabled */ |
@@ -4772,15 +4103,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4772 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 4103 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) |
4773 | { | 4104 | { |
4774 | enum ieee80211_band band = nla_type(tx_rates); | 4105 | enum ieee80211_band band = nla_type(tx_rates); |
4775 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | 4106 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
4776 | err = -EINVAL; | 4107 | return -EINVAL; |
4777 | goto unlock; | ||
4778 | } | ||
4779 | sband = rdev->wiphy.bands[band]; | 4108 | sband = rdev->wiphy.bands[band]; |
4780 | if (sband == NULL) { | 4109 | if (sband == NULL) |
4781 | err = -EINVAL; | 4110 | return -EINVAL; |
4782 | goto unlock; | ||
4783 | } | ||
4784 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 4111 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
4785 | nla_len(tx_rates), nl80211_txattr_policy); | 4112 | nla_len(tx_rates), nl80211_txattr_policy); |
4786 | if (tb[NL80211_TXRATE_LEGACY]) { | 4113 | if (tb[NL80211_TXRATE_LEGACY]) { |
@@ -4788,29 +4115,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4788 | sband, | 4115 | sband, |
4789 | nla_data(tb[NL80211_TXRATE_LEGACY]), | 4116 | nla_data(tb[NL80211_TXRATE_LEGACY]), |
4790 | nla_len(tb[NL80211_TXRATE_LEGACY])); | 4117 | nla_len(tb[NL80211_TXRATE_LEGACY])); |
4791 | if (mask.control[band].legacy == 0) { | 4118 | if (mask.control[band].legacy == 0) |
4792 | err = -EINVAL; | 4119 | return -EINVAL; |
4793 | goto unlock; | ||
4794 | } | ||
4795 | } | 4120 | } |
4796 | } | 4121 | } |
4797 | 4122 | ||
4798 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | 4123 | return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); |
4799 | |||
4800 | unlock: | ||
4801 | dev_put(dev); | ||
4802 | cfg80211_unlock_rdev(rdev); | ||
4803 | unlock_rtnl: | ||
4804 | rtnl_unlock(); | ||
4805 | return err; | ||
4806 | } | 4124 | } |
4807 | 4125 | ||
4808 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | 4126 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
4809 | { | 4127 | { |
4810 | struct cfg80211_registered_device *rdev; | 4128 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4811 | struct net_device *dev; | 4129 | struct net_device *dev = info->user_ptr[1]; |
4812 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 4130 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
4813 | int err; | ||
4814 | 4131 | ||
4815 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4132 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
4816 | return -EINVAL; | 4133 | return -EINVAL; |
@@ -4818,41 +4135,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4818 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 4135 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
4819 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 4136 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
4820 | 4137 | ||
4821 | rtnl_lock(); | ||
4822 | |||
4823 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4824 | if (err) | ||
4825 | goto unlock_rtnl; | ||
4826 | |||
4827 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4138 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4828 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 4139 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4829 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4140 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4830 | err = -EOPNOTSUPP; | 4141 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4831 | goto out; | 4142 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4832 | } | 4143 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4144 | return -EOPNOTSUPP; | ||
4833 | 4145 | ||
4834 | /* not much point in registering if we can't reply */ | 4146 | /* not much point in registering if we can't reply */ |
4835 | if (!rdev->ops->mgmt_tx) { | 4147 | if (!rdev->ops->mgmt_tx) |
4836 | err = -EOPNOTSUPP; | 4148 | return -EOPNOTSUPP; |
4837 | goto out; | ||
4838 | } | ||
4839 | 4149 | ||
4840 | err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 4150 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
4841 | frame_type, | 4151 | frame_type, |
4842 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4152 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
4843 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4153 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
4844 | out: | ||
4845 | cfg80211_unlock_rdev(rdev); | ||
4846 | dev_put(dev); | ||
4847 | unlock_rtnl: | ||
4848 | rtnl_unlock(); | ||
4849 | return err; | ||
4850 | } | 4154 | } |
4851 | 4155 | ||
4852 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | 4156 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
4853 | { | 4157 | { |
4854 | struct cfg80211_registered_device *rdev; | 4158 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4855 | struct net_device *dev; | 4159 | struct net_device *dev = info->user_ptr[1]; |
4856 | struct ieee80211_channel *chan; | 4160 | struct ieee80211_channel *chan; |
4857 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4161 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
4858 | bool channel_type_valid = false; | 4162 | bool channel_type_valid = false; |
@@ -4866,28 +4170,16 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4866 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 4170 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
4867 | return -EINVAL; | 4171 | return -EINVAL; |
4868 | 4172 | ||
4869 | rtnl_lock(); | 4173 | if (!rdev->ops->mgmt_tx) |
4870 | 4174 | return -EOPNOTSUPP; | |
4871 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4872 | if (err) | ||
4873 | goto unlock_rtnl; | ||
4874 | |||
4875 | if (!rdev->ops->mgmt_tx) { | ||
4876 | err = -EOPNOTSUPP; | ||
4877 | goto out; | ||
4878 | } | ||
4879 | 4175 | ||
4880 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4176 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4881 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 4177 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4882 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4178 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4883 | err = -EOPNOTSUPP; | 4179 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4884 | goto out; | 4180 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4885 | } | 4181 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4886 | 4182 | return -EOPNOTSUPP; | |
4887 | if (!netif_running(dev)) { | ||
4888 | err = -ENETDOWN; | ||
4889 | goto out; | ||
4890 | } | ||
4891 | 4183 | ||
4892 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 4184 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4893 | channel_type = nla_get_u32( | 4185 | channel_type = nla_get_u32( |
@@ -4895,25 +4187,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4895 | if (channel_type != NL80211_CHAN_NO_HT && | 4187 | if (channel_type != NL80211_CHAN_NO_HT && |
4896 | channel_type != NL80211_CHAN_HT20 && | 4188 | channel_type != NL80211_CHAN_HT20 && |
4897 | channel_type != NL80211_CHAN_HT40PLUS && | 4189 | channel_type != NL80211_CHAN_HT40PLUS && |
4898 | channel_type != NL80211_CHAN_HT40MINUS) { | 4190 | channel_type != NL80211_CHAN_HT40MINUS) |
4899 | err = -EINVAL; | 4191 | return -EINVAL; |
4900 | goto out; | ||
4901 | } | ||
4902 | channel_type_valid = true; | 4192 | channel_type_valid = true; |
4903 | } | 4193 | } |
4904 | 4194 | ||
4905 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4195 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4906 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4196 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4907 | if (chan == NULL) { | 4197 | if (chan == NULL) |
4908 | err = -EINVAL; | 4198 | return -EINVAL; |
4909 | goto out; | ||
4910 | } | ||
4911 | 4199 | ||
4912 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4200 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4913 | if (!msg) { | 4201 | if (!msg) |
4914 | err = -ENOMEM; | 4202 | return -ENOMEM; |
4915 | goto out; | ||
4916 | } | ||
4917 | 4203 | ||
4918 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4204 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4919 | NL80211_CMD_FRAME); | 4205 | NL80211_CMD_FRAME); |
@@ -4933,110 +4219,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4933 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4219 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4934 | 4220 | ||
4935 | genlmsg_end(msg, hdr); | 4221 | genlmsg_end(msg, hdr); |
4936 | err = genlmsg_reply(msg, info); | 4222 | return genlmsg_reply(msg, info); |
4937 | goto out; | ||
4938 | 4223 | ||
4939 | nla_put_failure: | 4224 | nla_put_failure: |
4940 | err = -ENOBUFS; | 4225 | err = -ENOBUFS; |
4941 | free_msg: | 4226 | free_msg: |
4942 | nlmsg_free(msg); | 4227 | nlmsg_free(msg); |
4943 | out: | ||
4944 | cfg80211_unlock_rdev(rdev); | ||
4945 | dev_put(dev); | ||
4946 | unlock_rtnl: | ||
4947 | rtnl_unlock(); | ||
4948 | return err; | 4228 | return err; |
4949 | } | 4229 | } |
4950 | 4230 | ||
4951 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 4231 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
4952 | { | 4232 | { |
4953 | struct cfg80211_registered_device *rdev; | 4233 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4954 | struct wireless_dev *wdev; | 4234 | struct wireless_dev *wdev; |
4955 | struct net_device *dev; | 4235 | struct net_device *dev = info->user_ptr[1]; |
4956 | u8 ps_state; | 4236 | u8 ps_state; |
4957 | bool state; | 4237 | bool state; |
4958 | int err; | 4238 | int err; |
4959 | 4239 | ||
4960 | if (!info->attrs[NL80211_ATTR_PS_STATE]) { | 4240 | if (!info->attrs[NL80211_ATTR_PS_STATE]) |
4961 | err = -EINVAL; | 4241 | return -EINVAL; |
4962 | goto out; | ||
4963 | } | ||
4964 | 4242 | ||
4965 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); | 4243 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); |
4966 | 4244 | ||
4967 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { | 4245 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) |
4968 | err = -EINVAL; | 4246 | return -EINVAL; |
4969 | goto out; | ||
4970 | } | ||
4971 | |||
4972 | rtnl_lock(); | ||
4973 | |||
4974 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4975 | if (err) | ||
4976 | goto unlock_rtnl; | ||
4977 | 4247 | ||
4978 | wdev = dev->ieee80211_ptr; | 4248 | wdev = dev->ieee80211_ptr; |
4979 | 4249 | ||
4980 | if (!rdev->ops->set_power_mgmt) { | 4250 | if (!rdev->ops->set_power_mgmt) |
4981 | err = -EOPNOTSUPP; | 4251 | return -EOPNOTSUPP; |
4982 | goto unlock_rdev; | ||
4983 | } | ||
4984 | 4252 | ||
4985 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; | 4253 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; |
4986 | 4254 | ||
4987 | if (state == wdev->ps) | 4255 | if (state == wdev->ps) |
4988 | goto unlock_rdev; | 4256 | return 0; |
4989 | |||
4990 | wdev->ps = state; | ||
4991 | |||
4992 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, | ||
4993 | wdev->ps_timeout)) | ||
4994 | /* assume this means it's off */ | ||
4995 | wdev->ps = false; | ||
4996 | |||
4997 | unlock_rdev: | ||
4998 | cfg80211_unlock_rdev(rdev); | ||
4999 | dev_put(dev); | ||
5000 | unlock_rtnl: | ||
5001 | rtnl_unlock(); | ||
5002 | 4257 | ||
5003 | out: | 4258 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, |
4259 | wdev->ps_timeout); | ||
4260 | if (!err) | ||
4261 | wdev->ps = state; | ||
5004 | return err; | 4262 | return err; |
5005 | } | 4263 | } |
5006 | 4264 | ||
5007 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | 4265 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) |
5008 | { | 4266 | { |
5009 | struct cfg80211_registered_device *rdev; | 4267 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5010 | enum nl80211_ps_state ps_state; | 4268 | enum nl80211_ps_state ps_state; |
5011 | struct wireless_dev *wdev; | 4269 | struct wireless_dev *wdev; |
5012 | struct net_device *dev; | 4270 | struct net_device *dev = info->user_ptr[1]; |
5013 | struct sk_buff *msg; | 4271 | struct sk_buff *msg; |
5014 | void *hdr; | 4272 | void *hdr; |
5015 | int err; | 4273 | int err; |
5016 | 4274 | ||
5017 | rtnl_lock(); | ||
5018 | |||
5019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
5020 | if (err) | ||
5021 | goto unlock_rtnl; | ||
5022 | |||
5023 | wdev = dev->ieee80211_ptr; | 4275 | wdev = dev->ieee80211_ptr; |
5024 | 4276 | ||
5025 | if (!rdev->ops->set_power_mgmt) { | 4277 | if (!rdev->ops->set_power_mgmt) |
5026 | err = -EOPNOTSUPP; | 4278 | return -EOPNOTSUPP; |
5027 | goto out; | ||
5028 | } | ||
5029 | 4279 | ||
5030 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4280 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
5031 | if (!msg) { | 4281 | if (!msg) |
5032 | err = -ENOMEM; | 4282 | return -ENOMEM; |
5033 | goto out; | ||
5034 | } | ||
5035 | 4283 | ||
5036 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4284 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
5037 | NL80211_CMD_GET_POWER_SAVE); | 4285 | NL80211_CMD_GET_POWER_SAVE); |
5038 | if (!hdr) { | 4286 | if (!hdr) { |
5039 | err = -ENOMEM; | 4287 | err = -ENOBUFS; |
5040 | goto free_msg; | 4288 | goto free_msg; |
5041 | } | 4289 | } |
5042 | 4290 | ||
@@ -5048,22 +4296,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
5048 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); | 4296 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); |
5049 | 4297 | ||
5050 | genlmsg_end(msg, hdr); | 4298 | genlmsg_end(msg, hdr); |
5051 | err = genlmsg_reply(msg, info); | 4299 | return genlmsg_reply(msg, info); |
5052 | goto out; | ||
5053 | 4300 | ||
5054 | nla_put_failure: | 4301 | nla_put_failure: |
5055 | err = -ENOBUFS; | 4302 | err = -ENOBUFS; |
5056 | 4303 | free_msg: | |
5057 | free_msg: | ||
5058 | nlmsg_free(msg); | 4304 | nlmsg_free(msg); |
5059 | |||
5060 | out: | ||
5061 | cfg80211_unlock_rdev(rdev); | ||
5062 | dev_put(dev); | ||
5063 | |||
5064 | unlock_rtnl: | ||
5065 | rtnl_unlock(); | ||
5066 | |||
5067 | return err; | 4305 | return err; |
5068 | } | 4306 | } |
5069 | 4307 | ||
@@ -5077,42 +4315,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
5077 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 4315 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
5078 | s32 threshold, u32 hysteresis) | 4316 | s32 threshold, u32 hysteresis) |
5079 | { | 4317 | { |
5080 | struct cfg80211_registered_device *rdev; | 4318 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5081 | struct wireless_dev *wdev; | 4319 | struct wireless_dev *wdev; |
5082 | struct net_device *dev; | 4320 | struct net_device *dev = info->user_ptr[1]; |
5083 | int err; | ||
5084 | 4321 | ||
5085 | if (threshold > 0) | 4322 | if (threshold > 0) |
5086 | return -EINVAL; | 4323 | return -EINVAL; |
5087 | 4324 | ||
5088 | rtnl_lock(); | ||
5089 | |||
5090 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
5091 | if (err) | ||
5092 | goto unlock_rdev; | ||
5093 | |||
5094 | wdev = dev->ieee80211_ptr; | 4325 | wdev = dev->ieee80211_ptr; |
5095 | 4326 | ||
5096 | if (!rdev->ops->set_cqm_rssi_config) { | 4327 | if (!rdev->ops->set_cqm_rssi_config) |
5097 | err = -EOPNOTSUPP; | 4328 | return -EOPNOTSUPP; |
5098 | goto unlock_rdev; | ||
5099 | } | ||
5100 | 4329 | ||
5101 | if (wdev->iftype != NL80211_IFTYPE_STATION && | 4330 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
5102 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4331 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) |
5103 | err = -EOPNOTSUPP; | 4332 | return -EOPNOTSUPP; |
5104 | goto unlock_rdev; | ||
5105 | } | ||
5106 | |||
5107 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
5108 | threshold, hysteresis); | ||
5109 | |||
5110 | unlock_rdev: | ||
5111 | cfg80211_unlock_rdev(rdev); | ||
5112 | dev_put(dev); | ||
5113 | rtnl_unlock(); | ||
5114 | 4333 | ||
5115 | return err; | 4334 | return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, |
4335 | threshold, hysteresis); | ||
5116 | } | 4336 | } |
5117 | 4337 | ||
5118 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | 4338 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) |
@@ -5146,6 +4366,65 @@ out: | |||
5146 | return err; | 4366 | return err; |
5147 | } | 4367 | } |
5148 | 4368 | ||
4369 | #define NL80211_FLAG_NEED_WIPHY 0x01 | ||
4370 | #define NL80211_FLAG_NEED_NETDEV 0x02 | ||
4371 | #define NL80211_FLAG_NEED_RTNL 0x04 | ||
4372 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | ||
4373 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | ||
4374 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
4375 | |||
4376 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4377 | struct genl_info *info) | ||
4378 | { | ||
4379 | struct cfg80211_registered_device *rdev; | ||
4380 | struct net_device *dev; | ||
4381 | int err; | ||
4382 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | ||
4383 | |||
4384 | if (rtnl) | ||
4385 | rtnl_lock(); | ||
4386 | |||
4387 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | ||
4388 | rdev = cfg80211_get_dev_from_info(info); | ||
4389 | if (IS_ERR(rdev)) { | ||
4390 | if (rtnl) | ||
4391 | rtnl_unlock(); | ||
4392 | return PTR_ERR(rdev); | ||
4393 | } | ||
4394 | info->user_ptr[0] = rdev; | ||
4395 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | ||
4396 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4397 | if (err) { | ||
4398 | if (rtnl) | ||
4399 | rtnl_unlock(); | ||
4400 | return err; | ||
4401 | } | ||
4402 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
4403 | !netif_running(dev)) { | ||
4404 | cfg80211_unlock_rdev(rdev); | ||
4405 | dev_put(dev); | ||
4406 | if (rtnl) | ||
4407 | rtnl_unlock(); | ||
4408 | return -ENETDOWN; | ||
4409 | } | ||
4410 | info->user_ptr[0] = rdev; | ||
4411 | info->user_ptr[1] = dev; | ||
4412 | } | ||
4413 | |||
4414 | return 0; | ||
4415 | } | ||
4416 | |||
4417 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4418 | struct genl_info *info) | ||
4419 | { | ||
4420 | if (info->user_ptr[0]) | ||
4421 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
4422 | if (info->user_ptr[1]) | ||
4423 | dev_put(info->user_ptr[1]); | ||
4424 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | ||
4425 | rtnl_unlock(); | ||
4426 | } | ||
4427 | |||
5149 | static struct genl_ops nl80211_ops[] = { | 4428 | static struct genl_ops nl80211_ops[] = { |
5150 | { | 4429 | { |
5151 | .cmd = NL80211_CMD_GET_WIPHY, | 4430 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5153,12 +4432,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5153 | .dumpit = nl80211_dump_wiphy, | 4432 | .dumpit = nl80211_dump_wiphy, |
5154 | .policy = nl80211_policy, | 4433 | .policy = nl80211_policy, |
5155 | /* can be retrieved by unprivileged users */ | 4434 | /* can be retrieved by unprivileged users */ |
4435 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | ||
5156 | }, | 4436 | }, |
5157 | { | 4437 | { |
5158 | .cmd = NL80211_CMD_SET_WIPHY, | 4438 | .cmd = NL80211_CMD_SET_WIPHY, |
5159 | .doit = nl80211_set_wiphy, | 4439 | .doit = nl80211_set_wiphy, |
5160 | .policy = nl80211_policy, | 4440 | .policy = nl80211_policy, |
5161 | .flags = GENL_ADMIN_PERM, | 4441 | .flags = GENL_ADMIN_PERM, |
4442 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
5162 | }, | 4443 | }, |
5163 | { | 4444 | { |
5164 | .cmd = NL80211_CMD_GET_INTERFACE, | 4445 | .cmd = NL80211_CMD_GET_INTERFACE, |
@@ -5166,90 +4447,119 @@ static struct genl_ops nl80211_ops[] = { | |||
5166 | .dumpit = nl80211_dump_interface, | 4447 | .dumpit = nl80211_dump_interface, |
5167 | .policy = nl80211_policy, | 4448 | .policy = nl80211_policy, |
5168 | /* can be retrieved by unprivileged users */ | 4449 | /* can be retrieved by unprivileged users */ |
4450 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | ||
5169 | }, | 4451 | }, |
5170 | { | 4452 | { |
5171 | .cmd = NL80211_CMD_SET_INTERFACE, | 4453 | .cmd = NL80211_CMD_SET_INTERFACE, |
5172 | .doit = nl80211_set_interface, | 4454 | .doit = nl80211_set_interface, |
5173 | .policy = nl80211_policy, | 4455 | .policy = nl80211_policy, |
5174 | .flags = GENL_ADMIN_PERM, | 4456 | .flags = GENL_ADMIN_PERM, |
4457 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4458 | NL80211_FLAG_NEED_RTNL, | ||
5175 | }, | 4459 | }, |
5176 | { | 4460 | { |
5177 | .cmd = NL80211_CMD_NEW_INTERFACE, | 4461 | .cmd = NL80211_CMD_NEW_INTERFACE, |
5178 | .doit = nl80211_new_interface, | 4462 | .doit = nl80211_new_interface, |
5179 | .policy = nl80211_policy, | 4463 | .policy = nl80211_policy, |
5180 | .flags = GENL_ADMIN_PERM, | 4464 | .flags = GENL_ADMIN_PERM, |
4465 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4466 | NL80211_FLAG_NEED_RTNL, | ||
5181 | }, | 4467 | }, |
5182 | { | 4468 | { |
5183 | .cmd = NL80211_CMD_DEL_INTERFACE, | 4469 | .cmd = NL80211_CMD_DEL_INTERFACE, |
5184 | .doit = nl80211_del_interface, | 4470 | .doit = nl80211_del_interface, |
5185 | .policy = nl80211_policy, | 4471 | .policy = nl80211_policy, |
5186 | .flags = GENL_ADMIN_PERM, | 4472 | .flags = GENL_ADMIN_PERM, |
4473 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4474 | NL80211_FLAG_NEED_RTNL, | ||
5187 | }, | 4475 | }, |
5188 | { | 4476 | { |
5189 | .cmd = NL80211_CMD_GET_KEY, | 4477 | .cmd = NL80211_CMD_GET_KEY, |
5190 | .doit = nl80211_get_key, | 4478 | .doit = nl80211_get_key, |
5191 | .policy = nl80211_policy, | 4479 | .policy = nl80211_policy, |
5192 | .flags = GENL_ADMIN_PERM, | 4480 | .flags = GENL_ADMIN_PERM, |
4481 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4482 | NL80211_FLAG_NEED_RTNL, | ||
5193 | }, | 4483 | }, |
5194 | { | 4484 | { |
5195 | .cmd = NL80211_CMD_SET_KEY, | 4485 | .cmd = NL80211_CMD_SET_KEY, |
5196 | .doit = nl80211_set_key, | 4486 | .doit = nl80211_set_key, |
5197 | .policy = nl80211_policy, | 4487 | .policy = nl80211_policy, |
5198 | .flags = GENL_ADMIN_PERM, | 4488 | .flags = GENL_ADMIN_PERM, |
4489 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4490 | NL80211_FLAG_NEED_RTNL, | ||
5199 | }, | 4491 | }, |
5200 | { | 4492 | { |
5201 | .cmd = NL80211_CMD_NEW_KEY, | 4493 | .cmd = NL80211_CMD_NEW_KEY, |
5202 | .doit = nl80211_new_key, | 4494 | .doit = nl80211_new_key, |
5203 | .policy = nl80211_policy, | 4495 | .policy = nl80211_policy, |
5204 | .flags = GENL_ADMIN_PERM, | 4496 | .flags = GENL_ADMIN_PERM, |
4497 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4498 | NL80211_FLAG_NEED_RTNL, | ||
5205 | }, | 4499 | }, |
5206 | { | 4500 | { |
5207 | .cmd = NL80211_CMD_DEL_KEY, | 4501 | .cmd = NL80211_CMD_DEL_KEY, |
5208 | .doit = nl80211_del_key, | 4502 | .doit = nl80211_del_key, |
5209 | .policy = nl80211_policy, | 4503 | .policy = nl80211_policy, |
5210 | .flags = GENL_ADMIN_PERM, | 4504 | .flags = GENL_ADMIN_PERM, |
4505 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4506 | NL80211_FLAG_NEED_RTNL, | ||
5211 | }, | 4507 | }, |
5212 | { | 4508 | { |
5213 | .cmd = NL80211_CMD_SET_BEACON, | 4509 | .cmd = NL80211_CMD_SET_BEACON, |
5214 | .policy = nl80211_policy, | 4510 | .policy = nl80211_policy, |
5215 | .flags = GENL_ADMIN_PERM, | 4511 | .flags = GENL_ADMIN_PERM, |
5216 | .doit = nl80211_addset_beacon, | 4512 | .doit = nl80211_addset_beacon, |
4513 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4514 | NL80211_FLAG_NEED_RTNL, | ||
5217 | }, | 4515 | }, |
5218 | { | 4516 | { |
5219 | .cmd = NL80211_CMD_NEW_BEACON, | 4517 | .cmd = NL80211_CMD_NEW_BEACON, |
5220 | .policy = nl80211_policy, | 4518 | .policy = nl80211_policy, |
5221 | .flags = GENL_ADMIN_PERM, | 4519 | .flags = GENL_ADMIN_PERM, |
5222 | .doit = nl80211_addset_beacon, | 4520 | .doit = nl80211_addset_beacon, |
4521 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4522 | NL80211_FLAG_NEED_RTNL, | ||
5223 | }, | 4523 | }, |
5224 | { | 4524 | { |
5225 | .cmd = NL80211_CMD_DEL_BEACON, | 4525 | .cmd = NL80211_CMD_DEL_BEACON, |
5226 | .policy = nl80211_policy, | 4526 | .policy = nl80211_policy, |
5227 | .flags = GENL_ADMIN_PERM, | 4527 | .flags = GENL_ADMIN_PERM, |
5228 | .doit = nl80211_del_beacon, | 4528 | .doit = nl80211_del_beacon, |
4529 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4530 | NL80211_FLAG_NEED_RTNL, | ||
5229 | }, | 4531 | }, |
5230 | { | 4532 | { |
5231 | .cmd = NL80211_CMD_GET_STATION, | 4533 | .cmd = NL80211_CMD_GET_STATION, |
5232 | .doit = nl80211_get_station, | 4534 | .doit = nl80211_get_station, |
5233 | .dumpit = nl80211_dump_station, | 4535 | .dumpit = nl80211_dump_station, |
5234 | .policy = nl80211_policy, | 4536 | .policy = nl80211_policy, |
4537 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4538 | NL80211_FLAG_NEED_RTNL, | ||
5235 | }, | 4539 | }, |
5236 | { | 4540 | { |
5237 | .cmd = NL80211_CMD_SET_STATION, | 4541 | .cmd = NL80211_CMD_SET_STATION, |
5238 | .doit = nl80211_set_station, | 4542 | .doit = nl80211_set_station, |
5239 | .policy = nl80211_policy, | 4543 | .policy = nl80211_policy, |
5240 | .flags = GENL_ADMIN_PERM, | 4544 | .flags = GENL_ADMIN_PERM, |
4545 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4546 | NL80211_FLAG_NEED_RTNL, | ||
5241 | }, | 4547 | }, |
5242 | { | 4548 | { |
5243 | .cmd = NL80211_CMD_NEW_STATION, | 4549 | .cmd = NL80211_CMD_NEW_STATION, |
5244 | .doit = nl80211_new_station, | 4550 | .doit = nl80211_new_station, |
5245 | .policy = nl80211_policy, | 4551 | .policy = nl80211_policy, |
5246 | .flags = GENL_ADMIN_PERM, | 4552 | .flags = GENL_ADMIN_PERM, |
4553 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4554 | NL80211_FLAG_NEED_RTNL, | ||
5247 | }, | 4555 | }, |
5248 | { | 4556 | { |
5249 | .cmd = NL80211_CMD_DEL_STATION, | 4557 | .cmd = NL80211_CMD_DEL_STATION, |
5250 | .doit = nl80211_del_station, | 4558 | .doit = nl80211_del_station, |
5251 | .policy = nl80211_policy, | 4559 | .policy = nl80211_policy, |
5252 | .flags = GENL_ADMIN_PERM, | 4560 | .flags = GENL_ADMIN_PERM, |
4561 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4562 | NL80211_FLAG_NEED_RTNL, | ||
5253 | }, | 4563 | }, |
5254 | { | 4564 | { |
5255 | .cmd = NL80211_CMD_GET_MPATH, | 4565 | .cmd = NL80211_CMD_GET_MPATH, |
@@ -5257,30 +4567,40 @@ static struct genl_ops nl80211_ops[] = { | |||
5257 | .dumpit = nl80211_dump_mpath, | 4567 | .dumpit = nl80211_dump_mpath, |
5258 | .policy = nl80211_policy, | 4568 | .policy = nl80211_policy, |
5259 | .flags = GENL_ADMIN_PERM, | 4569 | .flags = GENL_ADMIN_PERM, |
4570 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4571 | NL80211_FLAG_NEED_RTNL, | ||
5260 | }, | 4572 | }, |
5261 | { | 4573 | { |
5262 | .cmd = NL80211_CMD_SET_MPATH, | 4574 | .cmd = NL80211_CMD_SET_MPATH, |
5263 | .doit = nl80211_set_mpath, | 4575 | .doit = nl80211_set_mpath, |
5264 | .policy = nl80211_policy, | 4576 | .policy = nl80211_policy, |
5265 | .flags = GENL_ADMIN_PERM, | 4577 | .flags = GENL_ADMIN_PERM, |
4578 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4579 | NL80211_FLAG_NEED_RTNL, | ||
5266 | }, | 4580 | }, |
5267 | { | 4581 | { |
5268 | .cmd = NL80211_CMD_NEW_MPATH, | 4582 | .cmd = NL80211_CMD_NEW_MPATH, |
5269 | .doit = nl80211_new_mpath, | 4583 | .doit = nl80211_new_mpath, |
5270 | .policy = nl80211_policy, | 4584 | .policy = nl80211_policy, |
5271 | .flags = GENL_ADMIN_PERM, | 4585 | .flags = GENL_ADMIN_PERM, |
4586 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4587 | NL80211_FLAG_NEED_RTNL, | ||
5272 | }, | 4588 | }, |
5273 | { | 4589 | { |
5274 | .cmd = NL80211_CMD_DEL_MPATH, | 4590 | .cmd = NL80211_CMD_DEL_MPATH, |
5275 | .doit = nl80211_del_mpath, | 4591 | .doit = nl80211_del_mpath, |
5276 | .policy = nl80211_policy, | 4592 | .policy = nl80211_policy, |
5277 | .flags = GENL_ADMIN_PERM, | 4593 | .flags = GENL_ADMIN_PERM, |
4594 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4595 | NL80211_FLAG_NEED_RTNL, | ||
5278 | }, | 4596 | }, |
5279 | { | 4597 | { |
5280 | .cmd = NL80211_CMD_SET_BSS, | 4598 | .cmd = NL80211_CMD_SET_BSS, |
5281 | .doit = nl80211_set_bss, | 4599 | .doit = nl80211_set_bss, |
5282 | .policy = nl80211_policy, | 4600 | .policy = nl80211_policy, |
5283 | .flags = GENL_ADMIN_PERM, | 4601 | .flags = GENL_ADMIN_PERM, |
4602 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4603 | NL80211_FLAG_NEED_RTNL, | ||
5284 | }, | 4604 | }, |
5285 | { | 4605 | { |
5286 | .cmd = NL80211_CMD_GET_REG, | 4606 | .cmd = NL80211_CMD_GET_REG, |
@@ -5305,18 +4625,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5305 | .doit = nl80211_get_mesh_params, | 4625 | .doit = nl80211_get_mesh_params, |
5306 | .policy = nl80211_policy, | 4626 | .policy = nl80211_policy, |
5307 | /* can be retrieved by unprivileged users */ | 4627 | /* can be retrieved by unprivileged users */ |
4628 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4629 | NL80211_FLAG_NEED_RTNL, | ||
5308 | }, | 4630 | }, |
5309 | { | 4631 | { |
5310 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4632 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
5311 | .doit = nl80211_set_mesh_params, | 4633 | .doit = nl80211_set_mesh_params, |
5312 | .policy = nl80211_policy, | 4634 | .policy = nl80211_policy, |
5313 | .flags = GENL_ADMIN_PERM, | 4635 | .flags = GENL_ADMIN_PERM, |
4636 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4637 | NL80211_FLAG_NEED_RTNL, | ||
5314 | }, | 4638 | }, |
5315 | { | 4639 | { |
5316 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 4640 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
5317 | .doit = nl80211_trigger_scan, | 4641 | .doit = nl80211_trigger_scan, |
5318 | .policy = nl80211_policy, | 4642 | .policy = nl80211_policy, |
5319 | .flags = GENL_ADMIN_PERM, | 4643 | .flags = GENL_ADMIN_PERM, |
4644 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4645 | NL80211_FLAG_NEED_RTNL, | ||
5320 | }, | 4646 | }, |
5321 | { | 4647 | { |
5322 | .cmd = NL80211_CMD_GET_SCAN, | 4648 | .cmd = NL80211_CMD_GET_SCAN, |
@@ -5328,36 +4654,48 @@ static struct genl_ops nl80211_ops[] = { | |||
5328 | .doit = nl80211_authenticate, | 4654 | .doit = nl80211_authenticate, |
5329 | .policy = nl80211_policy, | 4655 | .policy = nl80211_policy, |
5330 | .flags = GENL_ADMIN_PERM, | 4656 | .flags = GENL_ADMIN_PERM, |
4657 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4658 | NL80211_FLAG_NEED_RTNL, | ||
5331 | }, | 4659 | }, |
5332 | { | 4660 | { |
5333 | .cmd = NL80211_CMD_ASSOCIATE, | 4661 | .cmd = NL80211_CMD_ASSOCIATE, |
5334 | .doit = nl80211_associate, | 4662 | .doit = nl80211_associate, |
5335 | .policy = nl80211_policy, | 4663 | .policy = nl80211_policy, |
5336 | .flags = GENL_ADMIN_PERM, | 4664 | .flags = GENL_ADMIN_PERM, |
4665 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4666 | NL80211_FLAG_NEED_RTNL, | ||
5337 | }, | 4667 | }, |
5338 | { | 4668 | { |
5339 | .cmd = NL80211_CMD_DEAUTHENTICATE, | 4669 | .cmd = NL80211_CMD_DEAUTHENTICATE, |
5340 | .doit = nl80211_deauthenticate, | 4670 | .doit = nl80211_deauthenticate, |
5341 | .policy = nl80211_policy, | 4671 | .policy = nl80211_policy, |
5342 | .flags = GENL_ADMIN_PERM, | 4672 | .flags = GENL_ADMIN_PERM, |
4673 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4674 | NL80211_FLAG_NEED_RTNL, | ||
5343 | }, | 4675 | }, |
5344 | { | 4676 | { |
5345 | .cmd = NL80211_CMD_DISASSOCIATE, | 4677 | .cmd = NL80211_CMD_DISASSOCIATE, |
5346 | .doit = nl80211_disassociate, | 4678 | .doit = nl80211_disassociate, |
5347 | .policy = nl80211_policy, | 4679 | .policy = nl80211_policy, |
5348 | .flags = GENL_ADMIN_PERM, | 4680 | .flags = GENL_ADMIN_PERM, |
4681 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4682 | NL80211_FLAG_NEED_RTNL, | ||
5349 | }, | 4683 | }, |
5350 | { | 4684 | { |
5351 | .cmd = NL80211_CMD_JOIN_IBSS, | 4685 | .cmd = NL80211_CMD_JOIN_IBSS, |
5352 | .doit = nl80211_join_ibss, | 4686 | .doit = nl80211_join_ibss, |
5353 | .policy = nl80211_policy, | 4687 | .policy = nl80211_policy, |
5354 | .flags = GENL_ADMIN_PERM, | 4688 | .flags = GENL_ADMIN_PERM, |
4689 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4690 | NL80211_FLAG_NEED_RTNL, | ||
5355 | }, | 4691 | }, |
5356 | { | 4692 | { |
5357 | .cmd = NL80211_CMD_LEAVE_IBSS, | 4693 | .cmd = NL80211_CMD_LEAVE_IBSS, |
5358 | .doit = nl80211_leave_ibss, | 4694 | .doit = nl80211_leave_ibss, |
5359 | .policy = nl80211_policy, | 4695 | .policy = nl80211_policy, |
5360 | .flags = GENL_ADMIN_PERM, | 4696 | .flags = GENL_ADMIN_PERM, |
4697 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4698 | NL80211_FLAG_NEED_RTNL, | ||
5361 | }, | 4699 | }, |
5362 | #ifdef CONFIG_NL80211_TESTMODE | 4700 | #ifdef CONFIG_NL80211_TESTMODE |
5363 | { | 4701 | { |
@@ -5365,6 +4703,8 @@ static struct genl_ops nl80211_ops[] = { | |||
5365 | .doit = nl80211_testmode_do, | 4703 | .doit = nl80211_testmode_do, |
5366 | .policy = nl80211_policy, | 4704 | .policy = nl80211_policy, |
5367 | .flags = GENL_ADMIN_PERM, | 4705 | .flags = GENL_ADMIN_PERM, |
4706 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4707 | NL80211_FLAG_NEED_RTNL, | ||
5368 | }, | 4708 | }, |
5369 | #endif | 4709 | #endif |
5370 | { | 4710 | { |
@@ -5372,18 +4712,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5372 | .doit = nl80211_connect, | 4712 | .doit = nl80211_connect, |
5373 | .policy = nl80211_policy, | 4713 | .policy = nl80211_policy, |
5374 | .flags = GENL_ADMIN_PERM, | 4714 | .flags = GENL_ADMIN_PERM, |
4715 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4716 | NL80211_FLAG_NEED_RTNL, | ||
5375 | }, | 4717 | }, |
5376 | { | 4718 | { |
5377 | .cmd = NL80211_CMD_DISCONNECT, | 4719 | .cmd = NL80211_CMD_DISCONNECT, |
5378 | .doit = nl80211_disconnect, | 4720 | .doit = nl80211_disconnect, |
5379 | .policy = nl80211_policy, | 4721 | .policy = nl80211_policy, |
5380 | .flags = GENL_ADMIN_PERM, | 4722 | .flags = GENL_ADMIN_PERM, |
4723 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4724 | NL80211_FLAG_NEED_RTNL, | ||
5381 | }, | 4725 | }, |
5382 | { | 4726 | { |
5383 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | 4727 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, |
5384 | .doit = nl80211_wiphy_netns, | 4728 | .doit = nl80211_wiphy_netns, |
5385 | .policy = nl80211_policy, | 4729 | .policy = nl80211_policy, |
5386 | .flags = GENL_ADMIN_PERM, | 4730 | .flags = GENL_ADMIN_PERM, |
4731 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4732 | NL80211_FLAG_NEED_RTNL, | ||
5387 | }, | 4733 | }, |
5388 | { | 4734 | { |
5389 | .cmd = NL80211_CMD_GET_SURVEY, | 4735 | .cmd = NL80211_CMD_GET_SURVEY, |
@@ -5395,72 +4741,104 @@ static struct genl_ops nl80211_ops[] = { | |||
5395 | .doit = nl80211_setdel_pmksa, | 4741 | .doit = nl80211_setdel_pmksa, |
5396 | .policy = nl80211_policy, | 4742 | .policy = nl80211_policy, |
5397 | .flags = GENL_ADMIN_PERM, | 4743 | .flags = GENL_ADMIN_PERM, |
4744 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4745 | NL80211_FLAG_NEED_RTNL, | ||
5398 | }, | 4746 | }, |
5399 | { | 4747 | { |
5400 | .cmd = NL80211_CMD_DEL_PMKSA, | 4748 | .cmd = NL80211_CMD_DEL_PMKSA, |
5401 | .doit = nl80211_setdel_pmksa, | 4749 | .doit = nl80211_setdel_pmksa, |
5402 | .policy = nl80211_policy, | 4750 | .policy = nl80211_policy, |
5403 | .flags = GENL_ADMIN_PERM, | 4751 | .flags = GENL_ADMIN_PERM, |
4752 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4753 | NL80211_FLAG_NEED_RTNL, | ||
5404 | }, | 4754 | }, |
5405 | { | 4755 | { |
5406 | .cmd = NL80211_CMD_FLUSH_PMKSA, | 4756 | .cmd = NL80211_CMD_FLUSH_PMKSA, |
5407 | .doit = nl80211_flush_pmksa, | 4757 | .doit = nl80211_flush_pmksa, |
5408 | .policy = nl80211_policy, | 4758 | .policy = nl80211_policy, |
5409 | .flags = GENL_ADMIN_PERM, | 4759 | .flags = GENL_ADMIN_PERM, |
4760 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4761 | NL80211_FLAG_NEED_RTNL, | ||
5410 | }, | 4762 | }, |
5411 | { | 4763 | { |
5412 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | 4764 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, |
5413 | .doit = nl80211_remain_on_channel, | 4765 | .doit = nl80211_remain_on_channel, |
5414 | .policy = nl80211_policy, | 4766 | .policy = nl80211_policy, |
5415 | .flags = GENL_ADMIN_PERM, | 4767 | .flags = GENL_ADMIN_PERM, |
4768 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4769 | NL80211_FLAG_NEED_RTNL, | ||
5416 | }, | 4770 | }, |
5417 | { | 4771 | { |
5418 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 4772 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
5419 | .doit = nl80211_cancel_remain_on_channel, | 4773 | .doit = nl80211_cancel_remain_on_channel, |
5420 | .policy = nl80211_policy, | 4774 | .policy = nl80211_policy, |
5421 | .flags = GENL_ADMIN_PERM, | 4775 | .flags = GENL_ADMIN_PERM, |
4776 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4777 | NL80211_FLAG_NEED_RTNL, | ||
5422 | }, | 4778 | }, |
5423 | { | 4779 | { |
5424 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | 4780 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, |
5425 | .doit = nl80211_set_tx_bitrate_mask, | 4781 | .doit = nl80211_set_tx_bitrate_mask, |
5426 | .policy = nl80211_policy, | 4782 | .policy = nl80211_policy, |
5427 | .flags = GENL_ADMIN_PERM, | 4783 | .flags = GENL_ADMIN_PERM, |
4784 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4785 | NL80211_FLAG_NEED_RTNL, | ||
5428 | }, | 4786 | }, |
5429 | { | 4787 | { |
5430 | .cmd = NL80211_CMD_REGISTER_FRAME, | 4788 | .cmd = NL80211_CMD_REGISTER_FRAME, |
5431 | .doit = nl80211_register_mgmt, | 4789 | .doit = nl80211_register_mgmt, |
5432 | .policy = nl80211_policy, | 4790 | .policy = nl80211_policy, |
5433 | .flags = GENL_ADMIN_PERM, | 4791 | .flags = GENL_ADMIN_PERM, |
4792 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4793 | NL80211_FLAG_NEED_RTNL, | ||
5434 | }, | 4794 | }, |
5435 | { | 4795 | { |
5436 | .cmd = NL80211_CMD_FRAME, | 4796 | .cmd = NL80211_CMD_FRAME, |
5437 | .doit = nl80211_tx_mgmt, | 4797 | .doit = nl80211_tx_mgmt, |
5438 | .policy = nl80211_policy, | 4798 | .policy = nl80211_policy, |
5439 | .flags = GENL_ADMIN_PERM, | 4799 | .flags = GENL_ADMIN_PERM, |
4800 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4801 | NL80211_FLAG_NEED_RTNL, | ||
5440 | }, | 4802 | }, |
5441 | { | 4803 | { |
5442 | .cmd = NL80211_CMD_SET_POWER_SAVE, | 4804 | .cmd = NL80211_CMD_SET_POWER_SAVE, |
5443 | .doit = nl80211_set_power_save, | 4805 | .doit = nl80211_set_power_save, |
5444 | .policy = nl80211_policy, | 4806 | .policy = nl80211_policy, |
5445 | .flags = GENL_ADMIN_PERM, | 4807 | .flags = GENL_ADMIN_PERM, |
4808 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4809 | NL80211_FLAG_NEED_RTNL, | ||
5446 | }, | 4810 | }, |
5447 | { | 4811 | { |
5448 | .cmd = NL80211_CMD_GET_POWER_SAVE, | 4812 | .cmd = NL80211_CMD_GET_POWER_SAVE, |
5449 | .doit = nl80211_get_power_save, | 4813 | .doit = nl80211_get_power_save, |
5450 | .policy = nl80211_policy, | 4814 | .policy = nl80211_policy, |
5451 | /* can be retrieved by unprivileged users */ | 4815 | /* can be retrieved by unprivileged users */ |
4816 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4817 | NL80211_FLAG_NEED_RTNL, | ||
5452 | }, | 4818 | }, |
5453 | { | 4819 | { |
5454 | .cmd = NL80211_CMD_SET_CQM, | 4820 | .cmd = NL80211_CMD_SET_CQM, |
5455 | .doit = nl80211_set_cqm, | 4821 | .doit = nl80211_set_cqm, |
5456 | .policy = nl80211_policy, | 4822 | .policy = nl80211_policy, |
5457 | .flags = GENL_ADMIN_PERM, | 4823 | .flags = GENL_ADMIN_PERM, |
4824 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4825 | NL80211_FLAG_NEED_RTNL, | ||
5458 | }, | 4826 | }, |
5459 | { | 4827 | { |
5460 | .cmd = NL80211_CMD_SET_CHANNEL, | 4828 | .cmd = NL80211_CMD_SET_CHANNEL, |
5461 | .doit = nl80211_set_channel, | 4829 | .doit = nl80211_set_channel, |
5462 | .policy = nl80211_policy, | 4830 | .policy = nl80211_policy, |
5463 | .flags = GENL_ADMIN_PERM, | 4831 | .flags = GENL_ADMIN_PERM, |
4832 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4833 | NL80211_FLAG_NEED_RTNL, | ||
4834 | }, | ||
4835 | { | ||
4836 | .cmd = NL80211_CMD_SET_WDS_PEER, | ||
4837 | .doit = nl80211_set_wds_peer, | ||
4838 | .policy = nl80211_policy, | ||
4839 | .flags = GENL_ADMIN_PERM, | ||
4840 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4841 | NL80211_FLAG_NEED_RTNL, | ||
5464 | }, | 4842 | }, |
5465 | }; | 4843 | }; |
5466 | 4844 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c7180141..503ebb86ba18 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
651 | 651 | ||
652 | spin_lock_bh(&dev->bss_lock); | 652 | spin_lock_bh(&dev->bss_lock); |
653 | if (!list_empty(&bss->list)) { | ||
654 | list_del_init(&bss->list); | ||
655 | dev->bss_generation++; | ||
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
653 | 657 | ||
654 | list_del(&bss->list); | 658 | kref_put(&bss->ref, bss_release); |
655 | dev->bss_generation++; | 659 | } |
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
657 | |||
658 | spin_unlock_bh(&dev->bss_lock); | 660 | spin_unlock_bh(&dev->bss_lock); |
659 | |||
660 | kref_put(&bss->ref, bss_release); | ||
661 | } | 661 | } |
662 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 662 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
663 | 663 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f161b9844542..e17b0bee6bdc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
698 | */ | 698 | */ |
699 | if (rdev->ops->del_key) | 699 | if (rdev->ops->del_key) |
700 | for (i = 0; i < 6; i++) | 700 | for (i = 0; i < 6; i++) |
701 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 701 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
702 | 702 | ||
703 | #ifdef CONFIG_CFG80211_WEXT | 703 | #ifdef CONFIG_CFG80211_WEXT |
704 | memset(&wrqu, 0, sizeof(wrqu)); | 704 | memset(&wrqu, 0, sizeof(wrqu)); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index fb5448f7d55a..76120aeda57d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
144 | 144 | ||
145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
146 | struct key_params *params, int key_idx, | 146 | struct key_params *params, int key_idx, |
147 | const u8 *mac_addr) | 147 | bool pairwise, const u8 *mac_addr) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | 150 | ||
151 | if (key_idx > 5) | 151 | if (key_idx > 5) |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | 153 | ||
154 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | if (pairwise && !mac_addr) | ||
158 | return -EINVAL; | ||
159 | |||
154 | /* | 160 | /* |
155 | * Disallow pairwise keys with non-zero index unless it's WEP | 161 | * Disallow pairwise keys with non-zero index unless it's WEP |
156 | * (because current deployments use pairwise WEP keys with | 162 | * (because current deployments use pairwise WEP keys with |
157 | * non-zero indizes but 802.11i clearly specifies to use zero) | 163 | * non-zero indizes but 802.11i clearly specifies to use zero) |
158 | */ | 164 | */ |
159 | if (mac_addr && key_idx && | 165 | if (pairwise && key_idx && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 166 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && |
161 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 167 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
162 | return -EINVAL; | 168 | return -EINVAL; |
@@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
677 | for (i = 0; i < 6; i++) { | 683 | for (i = 0; i < 6; i++) { |
678 | if (!wdev->connect_keys->params[i].cipher) | 684 | if (!wdev->connect_keys->params[i].cipher) |
679 | continue; | 685 | continue; |
680 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
681 | &wdev->connect_keys->params[i])) { | 687 | &wdev->connect_keys->params[i])) { |
682 | printk(KERN_ERR "%s: failed to set key %d\n", | 688 | printk(KERN_ERR "%s: failed to set key %d\n", |
683 | dev->name, i); | 689 | dev->name, i); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f811..6002265289c6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
433 | 433 | ||
434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
435 | struct net_device *dev, const u8 *addr, | 435 | struct net_device *dev, bool pairwise, |
436 | bool remove, bool tx_key, int idx, | 436 | const u8 *addr, bool remove, bool tx_key, |
437 | struct key_params *params) | 437 | int idx, struct key_params *params) |
438 | { | 438 | { |
439 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
440 | int err, i; | 440 | int err, i; |
441 | bool rejoin = false; | 441 | bool rejoin = false; |
442 | 442 | ||
443 | if (pairwise && !addr) | ||
444 | return -EINVAL; | ||
445 | |||
443 | if (!wdev->wext.keys) { | 446 | if (!wdev->wext.keys) { |
444 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 447 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
445 | GFP_KERNEL); | 448 | GFP_KERNEL); |
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
478 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 481 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
479 | rejoin = true; | 482 | rejoin = true; |
480 | } | 483 | } |
481 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 484 | |
485 | if (!pairwise && addr && | ||
486 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
487 | err = -ENOENT; | ||
488 | else | ||
489 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, | ||
490 | pairwise, addr); | ||
482 | } | 491 | } |
483 | wdev->wext.connect.privacy = false; | 492 | wdev->wext.connect.privacy = false; |
484 | /* | 493 | /* |
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
507 | if (addr) | 516 | if (addr) |
508 | tx_key = false; | 517 | tx_key = false; |
509 | 518 | ||
510 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | 519 | if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) |
511 | return -EINVAL; | 520 | return -EINVAL; |
512 | 521 | ||
513 | err = 0; | 522 | err = 0; |
514 | if (wdev->current_bss) | 523 | if (wdev->current_bss) |
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 524 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, |
525 | pairwise, addr, params); | ||
516 | if (err) | 526 | if (err) |
517 | return err; | 527 | return err; |
518 | 528 | ||
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
563 | } | 573 | } |
564 | 574 | ||
565 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 575 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
566 | struct net_device *dev, const u8 *addr, | 576 | struct net_device *dev, bool pairwise, |
567 | bool remove, bool tx_key, int idx, | 577 | const u8 *addr, bool remove, bool tx_key, |
568 | struct key_params *params) | 578 | int idx, struct key_params *params) |
569 | { | 579 | { |
570 | int err; | 580 | int err; |
571 | 581 | ||
572 | /* devlist mutex needed for possible IBSS re-join */ | 582 | /* devlist mutex needed for possible IBSS re-join */ |
573 | mutex_lock(&rdev->devlist_mtx); | 583 | mutex_lock(&rdev->devlist_mtx); |
574 | wdev_lock(dev->ieee80211_ptr); | 584 | wdev_lock(dev->ieee80211_ptr); |
575 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
576 | tx_key, idx, params); | 586 | remove, tx_key, idx, params); |
577 | wdev_unlock(dev->ieee80211_ptr); | 587 | wdev_unlock(dev->ieee80211_ptr); |
578 | mutex_unlock(&rdev->devlist_mtx); | 588 | mutex_unlock(&rdev->devlist_mtx); |
579 | 589 | ||
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
635 | else if (!remove) | 645 | else if (!remove) |
636 | return -EINVAL; | 646 | return -EINVAL; |
637 | 647 | ||
638 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | 648 | return cfg80211_set_encryption(rdev, dev, false, NULL, remove, |
639 | wdev->wext.default_key == -1, | 649 | wdev->wext.default_key == -1, |
640 | idx, ¶ms); | 650 | idx, ¶ms); |
641 | } | 651 | } |
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
725 | } | 735 | } |
726 | 736 | ||
727 | return cfg80211_set_encryption( | 737 | return cfg80211_set_encryption( |
728 | rdev, dev, addr, remove, | 738 | rdev, dev, |
739 | !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), | ||
740 | addr, remove, | ||
729 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 741 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
730 | idx, ¶ms); | 742 | idx, ¶ms); |
731 | } | 743 | } |