diff options
author | David S. Miller <davem@davemloft.net> | 2009-12-30 16:51:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-30 16:51:29 -0500 |
commit | 3a999e6eb5d277cd6a321dcda3fc43c3d9e4e4b8 (patch) | |
tree | b0ad8d03710ee556e97515ba1c949233859391ce /net/wireless | |
parent | 6cd9b49d7328c4656bfc17fcb47fb814955d40d2 (diff) | |
parent | 891dc5e73783eeabd2a704a9425e2a199b39c9f9 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/Kconfig | 15 | ||||
-rw-r--r-- | net/wireless/chan.c | 41 | ||||
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/mlme.c | 50 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 245 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 15 | ||||
-rw-r--r-- | net/wireless/reg.c | 89 | ||||
-rw-r--r-- | net/wireless/scan.c | 13 |
8 files changed, 342 insertions, 129 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 8419971f07c5..d0ee29063e5d 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -94,21 +94,6 @@ config CFG80211_DEBUGFS | |||
94 | 94 | ||
95 | If unsure, say N. | 95 | If unsure, say N. |
96 | 96 | ||
97 | config WIRELESS_OLD_REGULATORY | ||
98 | bool "Old wireless static regulatory definitions" | ||
99 | default n | ||
100 | depends on CFG80211 | ||
101 | ---help--- | ||
102 | This option enables the old static regulatory information | ||
103 | and uses it within the new framework. This option is available | ||
104 | for historical reasons and it is advised to leave it off. | ||
105 | |||
106 | For details see: | ||
107 | |||
108 | http://wireless.kernel.org/en/developers/Regulatory | ||
109 | |||
110 | Say N and if you say Y, please tell us why. The default is N. | ||
111 | |||
112 | config CFG80211_INTERNAL_REGDB | 97 | config CFG80211_INTERNAL_REGDB |
113 | bool "use statically compiled regulatory rules database" if EMBEDDED | 98 | bool "use statically compiled regulatory rules database" if EMBEDDED |
114 | default n | 99 | default n |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index a46ac6c9b365..bf1737fc9a7e 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -41,44 +41,57 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev, | |||
41 | return result; | 41 | return result; |
42 | } | 42 | } |
43 | 43 | ||
44 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | 44 | struct ieee80211_channel * |
45 | struct wireless_dev *for_wdev, | 45 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
46 | int freq, enum nl80211_channel_type channel_type) | 46 | int freq, enum nl80211_channel_type channel_type) |
47 | { | 47 | { |
48 | struct ieee80211_channel *chan; | 48 | struct ieee80211_channel *chan; |
49 | struct ieee80211_sta_ht_cap *ht_cap; | 49 | struct ieee80211_sta_ht_cap *ht_cap; |
50 | int result; | ||
51 | |||
52 | if (rdev_fixed_channel(rdev, for_wdev)) | ||
53 | return -EBUSY; | ||
54 | |||
55 | if (!rdev->ops->set_channel) | ||
56 | return -EOPNOTSUPP; | ||
57 | 50 | ||
58 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | 51 | chan = ieee80211_get_channel(&rdev->wiphy, freq); |
59 | 52 | ||
60 | /* Primary channel not allowed */ | 53 | /* Primary channel not allowed */ |
61 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 54 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
62 | return -EINVAL; | 55 | return NULL; |
63 | 56 | ||
64 | if (channel_type == NL80211_CHAN_HT40MINUS && | 57 | if (channel_type == NL80211_CHAN_HT40MINUS && |
65 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | 58 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) |
66 | return -EINVAL; | 59 | return NULL; |
67 | else if (channel_type == NL80211_CHAN_HT40PLUS && | 60 | else if (channel_type == NL80211_CHAN_HT40PLUS && |
68 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | 61 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) |
69 | return -EINVAL; | 62 | return NULL; |
70 | 63 | ||
71 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | 64 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; |
72 | 65 | ||
73 | if (channel_type != NL80211_CHAN_NO_HT) { | 66 | if (channel_type != NL80211_CHAN_NO_HT) { |
74 | if (!ht_cap->ht_supported) | 67 | if (!ht_cap->ht_supported) |
75 | return -EINVAL; | 68 | return NULL; |
76 | 69 | ||
77 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 70 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || |
78 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | 71 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) |
79 | return -EINVAL; | 72 | return NULL; |
80 | } | 73 | } |
81 | 74 | ||
75 | return chan; | ||
76 | } | ||
77 | |||
78 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
79 | struct wireless_dev *for_wdev, | ||
80 | int freq, enum nl80211_channel_type channel_type) | ||
81 | { | ||
82 | struct ieee80211_channel *chan; | ||
83 | int result; | ||
84 | |||
85 | if (rdev_fixed_channel(rdev, for_wdev)) | ||
86 | return -EBUSY; | ||
87 | |||
88 | if (!rdev->ops->set_channel) | ||
89 | return -EOPNOTSUPP; | ||
90 | |||
91 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | ||
92 | if (!chan) | ||
93 | return -EINVAL; | ||
94 | |||
82 | result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); | 95 | result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); |
83 | if (result) | 96 | if (result) |
84 | return result; | 97 | return result; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 35b712127143..30ec95f05b52 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -374,6 +374,9 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | |||
374 | struct ieee80211_channel * | 374 | struct ieee80211_channel * |
375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | 375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, |
376 | struct wireless_dev *for_wdev); | 376 | struct wireless_dev *for_wdev); |
377 | struct ieee80211_channel * | ||
378 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | ||
379 | int freq, enum nl80211_channel_type channel_type); | ||
377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | 380 | int rdev_set_freq(struct cfg80211_registered_device *rdev, |
378 | struct wireless_dev *for_wdev, | 381 | struct wireless_dev *for_wdev, |
379 | int freq, enum nl80211_channel_type channel_type); | 382 | int freq, enum nl80211_channel_type channel_type); |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index acaeaa784d68..94d151f6f73e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -93,7 +93,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | WARN_ON(!bss); | 96 | /* |
97 | * We might be coming here because the driver reported | ||
98 | * a successful association at the same time as the | ||
99 | * user requested a deauth. In that case, we will have | ||
100 | * removed the BSS from the auth_bsses list due to the | ||
101 | * deauth request when the assoc response makes it. If | ||
102 | * the two code paths acquire the lock the other way | ||
103 | * around, that's just the standard situation of a | ||
104 | * deauth being requested while connected. | ||
105 | */ | ||
106 | if (!bss) | ||
107 | goto out; | ||
97 | } else if (wdev->conn) { | 108 | } else if (wdev->conn) { |
98 | cfg80211_sme_failed_assoc(wdev); | 109 | cfg80211_sme_failed_assoc(wdev); |
99 | /* | 110 | /* |
@@ -680,3 +691,40 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
680 | } | 691 | } |
681 | } | 692 | } |
682 | } | 693 | } |
694 | |||
695 | void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, | ||
696 | struct ieee80211_channel *chan, | ||
697 | enum nl80211_channel_type channel_type, | ||
698 | unsigned int duration, gfp_t gfp) | ||
699 | { | ||
700 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
701 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
702 | |||
703 | nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, | ||
704 | duration, gfp); | ||
705 | } | ||
706 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
707 | |||
708 | void cfg80211_remain_on_channel_expired(struct net_device *dev, | ||
709 | u64 cookie, | ||
710 | struct ieee80211_channel *chan, | ||
711 | enum nl80211_channel_type channel_type, | ||
712 | gfp_t gfp) | ||
713 | { | ||
714 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
715 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
716 | |||
717 | nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, | ||
718 | channel_type, gfp); | ||
719 | } | ||
720 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
721 | |||
722 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | ||
723 | struct station_info *sinfo, gfp_t gfp) | ||
724 | { | ||
725 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
726 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
727 | |||
728 | nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); | ||
729 | } | ||
730 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7cb0d647fc34..e3bee3cecdfa 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | 141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, |
142 | [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, | 142 | [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, |
143 | .len = WLAN_PMKID_LEN }, | 143 | .len = WLAN_PMKID_LEN }, |
144 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, | ||
145 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, | ||
144 | }; | 146 | }; |
145 | 147 | ||
146 | /* policy for the attributes */ | 148 | /* policy for the attributes */ |
@@ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
569 | CMD(set_pmksa, SET_PMKSA); | 571 | CMD(set_pmksa, SET_PMKSA); |
570 | CMD(del_pmksa, DEL_PMKSA); | 572 | CMD(del_pmksa, DEL_PMKSA); |
571 | CMD(flush_pmksa, FLUSH_PMKSA); | 573 | CMD(flush_pmksa, FLUSH_PMKSA); |
574 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
572 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 575 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
573 | i++; | 576 | i++; |
574 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 577 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -1639,7 +1642,7 @@ static int parse_station_flags(struct genl_info *info, | |||
1639 | 1642 | ||
1640 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 1643 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
1641 | int flags, struct net_device *dev, | 1644 | int flags, struct net_device *dev, |
1642 | u8 *mac_addr, struct station_info *sinfo) | 1645 | const u8 *mac_addr, struct station_info *sinfo) |
1643 | { | 1646 | { |
1644 | void *hdr; | 1647 | void *hdr; |
1645 | struct nlattr *sinfoattr, *txrate; | 1648 | struct nlattr *sinfoattr, *txrate; |
@@ -2550,12 +2553,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2550 | 2553 | ||
2551 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 2554 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
2552 | 2555 | ||
2553 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
2554 | /* We ignore world regdom requests with the old regdom setup */ | ||
2555 | if (is_world_regdom(data)) | ||
2556 | return -EINVAL; | ||
2557 | #endif | ||
2558 | |||
2559 | r = regulatory_hint_user(data); | 2556 | r = regulatory_hint_user(data); |
2560 | 2557 | ||
2561 | return r; | 2558 | return r; |
@@ -4289,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4289 | 4286 | ||
4290 | } | 4287 | } |
4291 | 4288 | ||
4289 | static int nl80211_remain_on_channel(struct sk_buff *skb, | ||
4290 | struct genl_info *info) | ||
4291 | { | ||
4292 | struct cfg80211_registered_device *rdev; | ||
4293 | struct net_device *dev; | ||
4294 | struct ieee80211_channel *chan; | ||
4295 | struct sk_buff *msg; | ||
4296 | void *hdr; | ||
4297 | u64 cookie; | ||
4298 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
4299 | u32 freq, duration; | ||
4300 | int err; | ||
4301 | |||
4302 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||
4303 | !info->attrs[NL80211_ATTR_DURATION]) | ||
4304 | return -EINVAL; | ||
4305 | |||
4306 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | ||
4307 | |||
4308 | /* | ||
4309 | * We should be on that channel for at least one jiffie, | ||
4310 | * and more than 5 seconds seems excessive. | ||
4311 | */ | ||
4312 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | ||
4313 | return -EINVAL; | ||
4314 | |||
4315 | rtnl_lock(); | ||
4316 | |||
4317 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4318 | if (err) | ||
4319 | goto unlock_rtnl; | ||
4320 | |||
4321 | if (!rdev->ops->remain_on_channel) { | ||
4322 | err = -EOPNOTSUPP; | ||
4323 | goto out; | ||
4324 | } | ||
4325 | |||
4326 | if (!netif_running(dev)) { | ||
4327 | err = -ENETDOWN; | ||
4328 | goto out; | ||
4329 | } | ||
4330 | |||
4331 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | ||
4332 | channel_type = nla_get_u32( | ||
4333 | info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | ||
4334 | if (channel_type != NL80211_CHAN_NO_HT && | ||
4335 | channel_type != NL80211_CHAN_HT20 && | ||
4336 | channel_type != NL80211_CHAN_HT40PLUS && | ||
4337 | channel_type != NL80211_CHAN_HT40MINUS) | ||
4338 | err = -EINVAL; | ||
4339 | goto out; | ||
4340 | } | ||
4341 | |||
4342 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||
4343 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | ||
4344 | if (chan == NULL) { | ||
4345 | err = -EINVAL; | ||
4346 | goto out; | ||
4347 | } | ||
4348 | |||
4349 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
4350 | if (!msg) { | ||
4351 | err = -ENOMEM; | ||
4352 | goto out; | ||
4353 | } | ||
4354 | |||
4355 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||
4356 | NL80211_CMD_REMAIN_ON_CHANNEL); | ||
4357 | |||
4358 | if (IS_ERR(hdr)) { | ||
4359 | err = PTR_ERR(hdr); | ||
4360 | goto free_msg; | ||
4361 | } | ||
4362 | |||
4363 | err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | ||
4364 | channel_type, duration, &cookie); | ||
4365 | |||
4366 | if (err) | ||
4367 | goto free_msg; | ||
4368 | |||
4369 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||
4370 | |||
4371 | genlmsg_end(msg, hdr); | ||
4372 | err = genlmsg_reply(msg, info); | ||
4373 | goto out; | ||
4374 | |||
4375 | nla_put_failure: | ||
4376 | err = -ENOBUFS; | ||
4377 | free_msg: | ||
4378 | nlmsg_free(msg); | ||
4379 | out: | ||
4380 | cfg80211_unlock_rdev(rdev); | ||
4381 | dev_put(dev); | ||
4382 | unlock_rtnl: | ||
4383 | rtnl_unlock(); | ||
4384 | return err; | ||
4385 | } | ||
4386 | |||
4387 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | ||
4388 | struct genl_info *info) | ||
4389 | { | ||
4390 | struct cfg80211_registered_device *rdev; | ||
4391 | struct net_device *dev; | ||
4392 | u64 cookie; | ||
4393 | int err; | ||
4394 | |||
4395 | if (!info->attrs[NL80211_ATTR_COOKIE]) | ||
4396 | return -EINVAL; | ||
4397 | |||
4398 | rtnl_lock(); | ||
4399 | |||
4400 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4401 | if (err) | ||
4402 | goto unlock_rtnl; | ||
4403 | |||
4404 | if (!rdev->ops->cancel_remain_on_channel) { | ||
4405 | err = -EOPNOTSUPP; | ||
4406 | goto out; | ||
4407 | } | ||
4408 | |||
4409 | if (!netif_running(dev)) { | ||
4410 | err = -ENETDOWN; | ||
4411 | goto out; | ||
4412 | } | ||
4413 | |||
4414 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | ||
4415 | |||
4416 | err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | ||
4417 | |||
4418 | out: | ||
4419 | cfg80211_unlock_rdev(rdev); | ||
4420 | dev_put(dev); | ||
4421 | unlock_rtnl: | ||
4422 | rtnl_unlock(); | ||
4423 | return err; | ||
4424 | } | ||
4425 | |||
4292 | static struct genl_ops nl80211_ops[] = { | 4426 | static struct genl_ops nl80211_ops[] = { |
4293 | { | 4427 | { |
4294 | .cmd = NL80211_CMD_GET_WIPHY, | 4428 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4551,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = { | |||
4551 | .policy = nl80211_policy, | 4685 | .policy = nl80211_policy, |
4552 | .flags = GENL_ADMIN_PERM, | 4686 | .flags = GENL_ADMIN_PERM, |
4553 | }, | 4687 | }, |
4554 | 4688 | { | |
4689 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | ||
4690 | .doit = nl80211_remain_on_channel, | ||
4691 | .policy = nl80211_policy, | ||
4692 | .flags = GENL_ADMIN_PERM, | ||
4693 | }, | ||
4694 | { | ||
4695 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | ||
4696 | .doit = nl80211_cancel_remain_on_channel, | ||
4697 | .policy = nl80211_policy, | ||
4698 | .flags = GENL_ADMIN_PERM, | ||
4699 | }, | ||
4555 | }; | 4700 | }; |
4701 | |||
4556 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4702 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4557 | .name = "mlme", | 4703 | .name = "mlme", |
4558 | }; | 4704 | }; |
@@ -5140,6 +5286,89 @@ nla_put_failure: | |||
5140 | nlmsg_free(msg); | 5286 | nlmsg_free(msg); |
5141 | } | 5287 | } |
5142 | 5288 | ||
5289 | static void nl80211_send_remain_on_chan_event( | ||
5290 | int cmd, struct cfg80211_registered_device *rdev, | ||
5291 | struct net_device *netdev, u64 cookie, | ||
5292 | struct ieee80211_channel *chan, | ||
5293 | enum nl80211_channel_type channel_type, | ||
5294 | unsigned int duration, gfp_t gfp) | ||
5295 | { | ||
5296 | struct sk_buff *msg; | ||
5297 | void *hdr; | ||
5298 | |||
5299 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
5300 | if (!msg) | ||
5301 | return; | ||
5302 | |||
5303 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
5304 | if (!hdr) { | ||
5305 | nlmsg_free(msg); | ||
5306 | return; | ||
5307 | } | ||
5308 | |||
5309 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
5310 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
5311 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq); | ||
5312 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type); | ||
5313 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||
5314 | |||
5315 | if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) | ||
5316 | NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); | ||
5317 | |||
5318 | if (genlmsg_end(msg, hdr) < 0) { | ||
5319 | nlmsg_free(msg); | ||
5320 | return; | ||
5321 | } | ||
5322 | |||
5323 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
5324 | nl80211_mlme_mcgrp.id, gfp); | ||
5325 | return; | ||
5326 | |||
5327 | nla_put_failure: | ||
5328 | genlmsg_cancel(msg, hdr); | ||
5329 | nlmsg_free(msg); | ||
5330 | } | ||
5331 | |||
5332 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||
5333 | struct net_device *netdev, u64 cookie, | ||
5334 | struct ieee80211_channel *chan, | ||
5335 | enum nl80211_channel_type channel_type, | ||
5336 | unsigned int duration, gfp_t gfp) | ||
5337 | { | ||
5338 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | ||
5339 | rdev, netdev, cookie, chan, | ||
5340 | channel_type, duration, gfp); | ||
5341 | } | ||
5342 | |||
5343 | void nl80211_send_remain_on_channel_cancel( | ||
5344 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | ||
5345 | u64 cookie, struct ieee80211_channel *chan, | ||
5346 | enum nl80211_channel_type channel_type, gfp_t gfp) | ||
5347 | { | ||
5348 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | ||
5349 | rdev, netdev, cookie, chan, | ||
5350 | channel_type, 0, gfp); | ||
5351 | } | ||
5352 | |||
5353 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||
5354 | struct net_device *dev, const u8 *mac_addr, | ||
5355 | struct station_info *sinfo, gfp_t gfp) | ||
5356 | { | ||
5357 | struct sk_buff *msg; | ||
5358 | |||
5359 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
5360 | if (!msg) | ||
5361 | return; | ||
5362 | |||
5363 | if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { | ||
5364 | nlmsg_free(msg); | ||
5365 | return; | ||
5366 | } | ||
5367 | |||
5368 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
5369 | nl80211_mlme_mcgrp.id, gfp); | ||
5370 | } | ||
5371 | |||
5143 | /* initialisation/exit functions */ | 5372 | /* initialisation/exit functions */ |
5144 | 5373 | ||
5145 | int nl80211_init(void) | 5374 | int nl80211_init(void) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 44cc2a76a1b0..14855b8fb430 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -59,4 +59,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
59 | struct net_device *netdev, const u8 *bssid, | 59 | struct net_device *netdev, const u8 *bssid, |
60 | gfp_t gfp); | 60 | gfp_t gfp); |
61 | 61 | ||
62 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||
63 | struct net_device *netdev, | ||
64 | u64 cookie, | ||
65 | struct ieee80211_channel *chan, | ||
66 | enum nl80211_channel_type channel_type, | ||
67 | unsigned int duration, gfp_t gfp); | ||
68 | void nl80211_send_remain_on_channel_cancel( | ||
69 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | ||
70 | u64 cookie, struct ieee80211_channel *chan, | ||
71 | enum nl80211_channel_type channel_type, gfp_t gfp); | ||
72 | |||
73 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||
74 | struct net_device *dev, const u8 *mac_addr, | ||
75 | struct station_info *sinfo, gfp_t gfp); | ||
76 | |||
62 | #endif /* __NET_WIRELESS_NL80211_H */ | 77 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index dc13c3ffeca6..87ea60d84c3c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -129,78 +129,6 @@ static char *ieee80211_regdom = "00"; | |||
129 | module_param(ieee80211_regdom, charp, 0444); | 129 | module_param(ieee80211_regdom, charp, 0444); |
130 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 130 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
131 | 131 | ||
132 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
133 | /* | ||
134 | * We assume 40 MHz bandwidth for the old regulatory work. | ||
135 | * We make emphasis we are using the exact same frequencies | ||
136 | * as before | ||
137 | */ | ||
138 | |||
139 | static const struct ieee80211_regdomain us_regdom = { | ||
140 | .n_reg_rules = 6, | ||
141 | .alpha2 = "US", | ||
142 | .reg_rules = { | ||
143 | /* IEEE 802.11b/g, channels 1..11 */ | ||
144 | REG_RULE(2412-10, 2462+10, 40, 6, 27, 0), | ||
145 | /* IEEE 802.11a, channel 36..48 */ | ||
146 | REG_RULE(5180-10, 5240+10, 40, 6, 17, 0), | ||
147 | /* IEEE 802.11a, channels 48..64 */ | ||
148 | REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), | ||
149 | /* IEEE 802.11a, channels 100..124 */ | ||
150 | REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS), | ||
151 | /* IEEE 802.11a, channels 132..144 */ | ||
152 | REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS), | ||
153 | /* IEEE 802.11a, channels 149..165, outdoor */ | ||
154 | REG_RULE(5745-10, 5825+10, 40, 6, 30, 0), | ||
155 | } | ||
156 | }; | ||
157 | |||
158 | static const struct ieee80211_regdomain jp_regdom = { | ||
159 | .n_reg_rules = 6, | ||
160 | .alpha2 = "JP", | ||
161 | .reg_rules = { | ||
162 | /* IEEE 802.11b/g, channels 1..11 */ | ||
163 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | ||
164 | /* IEEE 802.11b/g, channels 12..13 */ | ||
165 | REG_RULE(2467-10, 2472+10, 20, 6, 20, 0), | ||
166 | /* IEEE 802.11b/g, channel 14 */ | ||
167 | REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM), | ||
168 | /* IEEE 802.11a, channels 36..48 */ | ||
169 | REG_RULE(5180-10, 5240+10, 40, 6, 20, 0), | ||
170 | /* IEEE 802.11a, channels 52..64 */ | ||
171 | REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), | ||
172 | /* IEEE 802.11a, channels 100..144 */ | ||
173 | REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS), | ||
174 | } | ||
175 | }; | ||
176 | |||
177 | static const struct ieee80211_regdomain *static_regdom(char *alpha2) | ||
178 | { | ||
179 | if (alpha2[0] == 'U' && alpha2[1] == 'S') | ||
180 | return &us_regdom; | ||
181 | if (alpha2[0] == 'J' && alpha2[1] == 'P') | ||
182 | return &jp_regdom; | ||
183 | /* Use world roaming rules for "EU", since it was a pseudo | ||
184 | domain anyway... */ | ||
185 | if (alpha2[0] == 'E' && alpha2[1] == 'U') | ||
186 | return &world_regdom; | ||
187 | /* Default, world roaming rules */ | ||
188 | return &world_regdom; | ||
189 | } | ||
190 | |||
191 | static bool is_old_static_regdom(const struct ieee80211_regdomain *rd) | ||
192 | { | ||
193 | if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom) | ||
194 | return true; | ||
195 | return false; | ||
196 | } | ||
197 | #else | ||
198 | static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd) | ||
199 | { | ||
200 | return false; | ||
201 | } | ||
202 | #endif | ||
203 | |||
204 | static void reset_regdomains(void) | 132 | static void reset_regdomains(void) |
205 | { | 133 | { |
206 | /* avoid freeing static information or freeing something twice */ | 134 | /* avoid freeing static information or freeing something twice */ |
@@ -210,8 +138,6 @@ static void reset_regdomains(void) | |||
210 | cfg80211_world_regdom = NULL; | 138 | cfg80211_world_regdom = NULL; |
211 | if (cfg80211_regdomain == &world_regdom) | 139 | if (cfg80211_regdomain == &world_regdom) |
212 | cfg80211_regdomain = NULL; | 140 | cfg80211_regdomain = NULL; |
213 | if (is_old_static_regdom(cfg80211_regdomain)) | ||
214 | cfg80211_regdomain = NULL; | ||
215 | 141 | ||
216 | kfree(cfg80211_regdomain); | 142 | kfree(cfg80211_regdomain); |
217 | kfree(cfg80211_world_regdom); | 143 | kfree(cfg80211_world_regdom); |
@@ -1490,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy, | |||
1490 | return REG_INTERSECT; | 1416 | return REG_INTERSECT; |
1491 | case NL80211_REGDOM_SET_BY_DRIVER: | 1417 | case NL80211_REGDOM_SET_BY_DRIVER: |
1492 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { | 1418 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { |
1493 | if (is_old_static_regdom(cfg80211_regdomain)) | ||
1494 | return 0; | ||
1495 | if (regdom_changes(pending_request->alpha2)) | 1419 | if (regdom_changes(pending_request->alpha2)) |
1496 | return 0; | 1420 | return 0; |
1497 | return -EALREADY; | 1421 | return -EALREADY; |
@@ -1528,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1528 | return -EAGAIN; | 1452 | return -EAGAIN; |
1529 | } | 1453 | } |
1530 | 1454 | ||
1531 | if (!is_old_static_regdom(cfg80211_regdomain) && | 1455 | if (!regdom_changes(pending_request->alpha2)) |
1532 | !regdom_changes(pending_request->alpha2)) | ||
1533 | return -EALREADY; | 1456 | return -EALREADY; |
1534 | 1457 | ||
1535 | return 0; | 1458 | return 0; |
@@ -2111,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2111 | * If someone else asked us to change the rd lets only bother | 2034 | * If someone else asked us to change the rd lets only bother |
2112 | * checking if the alpha2 changes if CRDA was already called | 2035 | * checking if the alpha2 changes if CRDA was already called |
2113 | */ | 2036 | */ |
2114 | if (!is_old_static_regdom(cfg80211_regdomain) && | 2037 | if (!regdom_changes(rd->alpha2)) |
2115 | !regdom_changes(rd->alpha2)) | ||
2116 | return -EINVAL; | 2038 | return -EINVAL; |
2117 | } | 2039 | } |
2118 | 2040 | ||
@@ -2311,15 +2233,8 @@ int regulatory_init(void) | |||
2311 | spin_lock_init(®_requests_lock); | 2233 | spin_lock_init(®_requests_lock); |
2312 | spin_lock_init(®_pending_beacons_lock); | 2234 | spin_lock_init(®_pending_beacons_lock); |
2313 | 2235 | ||
2314 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
2315 | cfg80211_regdomain = static_regdom(ieee80211_regdom); | ||
2316 | |||
2317 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); | ||
2318 | print_regdomain_info(cfg80211_regdomain); | ||
2319 | #else | ||
2320 | cfg80211_regdomain = cfg80211_world_regdom; | 2236 | cfg80211_regdomain = cfg80211_world_regdom; |
2321 | 2237 | ||
2322 | #endif | ||
2323 | /* We always try to get an update for the static regdomain */ | 2238 | /* We always try to get an update for the static regdomain */ |
2324 | err = regulatory_hint_core(cfg80211_regdomain->alpha2); | 2239 | err = regulatory_hint_core(cfg80211_regdomain->alpha2); |
2325 | if (err) { | 2240 | if (err) { |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 12dfa62aad18..0c2cbbebca95 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -601,7 +601,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
601 | struct cfg80211_registered_device *rdev; | 601 | struct cfg80211_registered_device *rdev; |
602 | struct wiphy *wiphy; | 602 | struct wiphy *wiphy; |
603 | struct iw_scan_req *wreq = NULL; | 603 | struct iw_scan_req *wreq = NULL; |
604 | struct cfg80211_scan_request *creq; | 604 | struct cfg80211_scan_request *creq = NULL; |
605 | int i, err, n_channels = 0; | 605 | int i, err, n_channels = 0; |
606 | enum ieee80211_band band; | 606 | enum ieee80211_band band; |
607 | 607 | ||
@@ -694,8 +694,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
694 | /* translate "Scan for SSID" request */ | 694 | /* translate "Scan for SSID" request */ |
695 | if (wreq) { | 695 | if (wreq) { |
696 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { | 696 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { |
697 | if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) | 697 | if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) { |
698 | return -EINVAL; | 698 | err = -EINVAL; |
699 | goto out; | ||
700 | } | ||
699 | memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); | 701 | memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); |
700 | creq->ssids[0].ssid_len = wreq->essid_len; | 702 | creq->ssids[0].ssid_len = wreq->essid_len; |
701 | } | 703 | } |
@@ -707,12 +709,15 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
707 | err = rdev->ops->scan(wiphy, dev, creq); | 709 | err = rdev->ops->scan(wiphy, dev, creq); |
708 | if (err) { | 710 | if (err) { |
709 | rdev->scan_req = NULL; | 711 | rdev->scan_req = NULL; |
710 | kfree(creq); | 712 | /* creq will be freed below */ |
711 | } else { | 713 | } else { |
712 | nl80211_send_scan_start(rdev, dev); | 714 | nl80211_send_scan_start(rdev, dev); |
715 | /* creq now owned by driver */ | ||
716 | creq = NULL; | ||
713 | dev_hold(dev); | 717 | dev_hold(dev); |
714 | } | 718 | } |
715 | out: | 719 | out: |
720 | kfree(creq); | ||
716 | cfg80211_unlock_rdev(rdev); | 721 | cfg80211_unlock_rdev(rdev); |
717 | return err; | 722 | return err; |
718 | } | 723 | } |