aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig3
-rw-r--r--net/wireless/core.c97
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c57
-rw-r--r--net/wireless/reg.c8
-rw-r--r--net/wireless/scan.c3
-rw-r--r--net/wireless/util.c13
-rw-r--r--net/wireless/wext-compat.c83
8 files changed, 251 insertions, 20 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 45005497c634..4428dd5e911d 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,5 +1,6 @@
1config CFG80211 1config CFG80211
2 tristate "Improved wireless configuration API" 2 tristate "Improved wireless configuration API"
3 depends on RFKILL || !RFKILL
3 4
4config CFG80211_REG_DEBUG 5config CFG80211_REG_DEBUG
5 bool "cfg80211 regulatory debugging" 6 bool "cfg80211 regulatory debugging"
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a5dbea1da476..3b74b88e10a3 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -12,6 +12,7 @@
12#include <linux/debugfs.h> 12#include <linux/debugfs.h>
13#include <linux/notifier.h> 13#include <linux/notifier.h>
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/rtnetlink.h>
15#include <net/genetlink.h> 16#include <net/genetlink.h>
16#include <net/cfg80211.h> 17#include <net/cfg80211.h>
17#include "nl80211.h" 18#include "nl80211.h"
@@ -227,6 +228,41 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
227 return 0; 228 return 0;
228} 229}
229 230
231static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
232{
233 struct cfg80211_registered_device *drv = data;
234
235 drv->ops->rfkill_poll(&drv->wiphy);
236}
237
238static int cfg80211_rfkill_set_block(void *data, bool blocked)
239{
240 struct cfg80211_registered_device *drv = data;
241 struct wireless_dev *wdev;
242
243 if (!blocked)
244 return 0;
245
246 rtnl_lock();
247 mutex_lock(&drv->devlist_mtx);
248
249 list_for_each_entry(wdev, &drv->netdev_list, list)
250 dev_close(wdev->netdev);
251
252 mutex_unlock(&drv->devlist_mtx);
253 rtnl_unlock();
254
255 return 0;
256}
257
258static void cfg80211_rfkill_sync_work(struct work_struct *work)
259{
260 struct cfg80211_registered_device *drv;
261
262 drv = container_of(work, struct cfg80211_registered_device, rfkill_sync);
263 cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
264}
265
230/* exported functions */ 266/* exported functions */
231 267
232struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) 268struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
@@ -274,6 +310,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
274 drv->wiphy.dev.class = &ieee80211_class; 310 drv->wiphy.dev.class = &ieee80211_class;
275 drv->wiphy.dev.platform_data = drv; 311 drv->wiphy.dev.platform_data = drv;
276 312
313 drv->rfkill_ops.set_block = cfg80211_rfkill_set_block;
314 drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev),
315 &drv->wiphy.dev, RFKILL_TYPE_WLAN,
316 &drv->rfkill_ops, drv);
317
318 if (!drv->rfkill) {
319 kfree(drv);
320 return NULL;
321 }
322
323 INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
324
277 /* 325 /*
278 * Initialize wiphy parameters to IEEE 802.11 MIB default values. 326 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
279 * Fragmentation and RTS threshold are disabled by default with the 327 * Fragmentation and RTS threshold are disabled by default with the
@@ -356,6 +404,10 @@ int wiphy_register(struct wiphy *wiphy)
356 if (res) 404 if (res)
357 goto out_unlock; 405 goto out_unlock;
358 406
407 res = rfkill_register(drv->rfkill);
408 if (res)
409 goto out_rm_dev;
410
359 list_add(&drv->list, &cfg80211_drv_list); 411 list_add(&drv->list, &cfg80211_drv_list);
360 412
361 /* add to debugfs */ 413 /* add to debugfs */
@@ -379,16 +431,41 @@ int wiphy_register(struct wiphy *wiphy)
379 cfg80211_debugfs_drv_add(drv); 431 cfg80211_debugfs_drv_add(drv);
380 432
381 res = 0; 433 res = 0;
382out_unlock: 434 goto out_unlock;
435
436 out_rm_dev:
437 device_del(&drv->wiphy.dev);
438 out_unlock:
383 mutex_unlock(&cfg80211_mutex); 439 mutex_unlock(&cfg80211_mutex);
384 return res; 440 return res;
385} 441}
386EXPORT_SYMBOL(wiphy_register); 442EXPORT_SYMBOL(wiphy_register);
387 443
444void wiphy_rfkill_start_polling(struct wiphy *wiphy)
445{
446 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
447
448 if (!drv->ops->rfkill_poll)
449 return;
450 drv->rfkill_ops.poll = cfg80211_rfkill_poll;
451 rfkill_resume_polling(drv->rfkill);
452}
453EXPORT_SYMBOL(wiphy_rfkill_start_polling);
454
455void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
456{
457 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
458
459 rfkill_pause_polling(drv->rfkill);
460}
461EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
462
388void wiphy_unregister(struct wiphy *wiphy) 463void wiphy_unregister(struct wiphy *wiphy)
389{ 464{
390 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); 465 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
391 466
467 rfkill_unregister(drv->rfkill);
468
392 /* protect the device list */ 469 /* protect the device list */
393 mutex_lock(&cfg80211_mutex); 470 mutex_lock(&cfg80211_mutex);
394 471
@@ -425,6 +502,7 @@ EXPORT_SYMBOL(wiphy_unregister);
425void cfg80211_dev_free(struct cfg80211_registered_device *drv) 502void cfg80211_dev_free(struct cfg80211_registered_device *drv)
426{ 503{
427 struct cfg80211_internal_bss *scan, *tmp; 504 struct cfg80211_internal_bss *scan, *tmp;
505 rfkill_destroy(drv->rfkill);
428 mutex_destroy(&drv->mtx); 506 mutex_destroy(&drv->mtx);
429 mutex_destroy(&drv->devlist_mtx); 507 mutex_destroy(&drv->devlist_mtx);
430 list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) 508 list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
@@ -438,6 +516,15 @@ void wiphy_free(struct wiphy *wiphy)
438} 516}
439EXPORT_SYMBOL(wiphy_free); 517EXPORT_SYMBOL(wiphy_free);
440 518
519void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
520{
521 struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
522
523 if (rfkill_set_hw_state(drv->rfkill, blocked))
524 schedule_work(&drv->rfkill_sync);
525}
526EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
527
441static int cfg80211_netdev_notifier_call(struct notifier_block * nb, 528static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
442 unsigned long state, 529 unsigned long state,
443 void *ndev) 530 void *ndev)
@@ -446,7 +533,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
446 struct cfg80211_registered_device *rdev; 533 struct cfg80211_registered_device *rdev;
447 534
448 if (!dev->ieee80211_ptr) 535 if (!dev->ieee80211_ptr)
449 return 0; 536 return NOTIFY_DONE;
450 537
451 rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); 538 rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
452 539
@@ -492,9 +579,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
492 } 579 }
493 mutex_unlock(&rdev->devlist_mtx); 580 mutex_unlock(&rdev->devlist_mtx);
494 break; 581 break;
582 case NETDEV_PRE_UP:
583 if (rfkill_blocked(rdev->rfkill))
584 return notifier_from_errno(-ERFKILL);
585 break;
495 } 586 }
496 587
497 return 0; 588 return NOTIFY_DONE;
498} 589}
499 590
500static struct notifier_block cfg80211_netdev_notifier = { 591static struct notifier_block cfg80211_netdev_notifier = {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ab512bcd8153..bfa340c7abb5 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -11,6 +11,8 @@
11#include <linux/kref.h> 11#include <linux/kref.h>
12#include <linux/rbtree.h> 12#include <linux/rbtree.h>
13#include <linux/debugfs.h> 13#include <linux/debugfs.h>
14#include <linux/rfkill.h>
15#include <linux/workqueue.h>
14#include <net/genetlink.h> 16#include <net/genetlink.h>
15#include <net/cfg80211.h> 17#include <net/cfg80211.h>
16#include "reg.h" 18#include "reg.h"
@@ -24,6 +26,11 @@ struct cfg80211_registered_device {
24 * any call is in progress */ 26 * any call is in progress */
25 struct mutex mtx; 27 struct mutex mtx;
26 28
29 /* rfkill support */
30 struct rfkill_ops rfkill_ops;
31 struct rfkill *rfkill;
32 struct work_struct rfkill_sync;
33
27 /* ISO / IEC 3166 alpha2 for which this device is receiving 34 /* ISO / IEC 3166 alpha2 for which this device is receiving
28 * country IEs on, this can help disregard country IEs from APs 35 * country IEs on, this can help disregard country IEs from APs
29 * on the same alpha2 quickly. The alpha2 may differ from 36 * on the same alpha2 quickly. The alpha2 may differ from
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4b4d3c8a1aed..24168560ebae 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1687,6 +1687,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1687 if (err) 1687 if (err)
1688 goto out_rtnl; 1688 goto out_rtnl;
1689 1689
1690 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
1691 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
1692 err = -EINVAL;
1693 goto out;
1694 }
1695
1690 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan); 1696 err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
1691 if (err) 1697 if (err)
1692 goto out; 1698 goto out;
@@ -1738,7 +1744,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1738 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); 1744 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
1739 params.listen_interval = 1745 params.listen_interval =
1740 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); 1746 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
1747
1741 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); 1748 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
1749 if (!params.aid || params.aid > IEEE80211_MAX_AID)
1750 return -EINVAL;
1751
1742 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) 1752 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
1743 params.ht_capa = 1753 params.ht_capa =
1744 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); 1754 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
@@ -3559,11 +3569,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
3559 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); 3569 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
3560} 3570}
3561 3571
3572static int nl80211_add_scan_req(struct sk_buff *msg,
3573 struct cfg80211_registered_device *rdev)
3574{
3575 struct cfg80211_scan_request *req = rdev->scan_req;
3576 struct nlattr *nest;
3577 int i;
3578
3579 if (WARN_ON(!req))
3580 return 0;
3581
3582 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
3583 if (!nest)
3584 goto nla_put_failure;
3585 for (i = 0; i < req->n_ssids; i++)
3586 NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid);
3587 nla_nest_end(msg, nest);
3588
3589 nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
3590 if (!nest)
3591 goto nla_put_failure;
3592 for (i = 0; i < req->n_channels; i++)
3593 NLA_PUT_U32(msg, i, req->channels[i]->center_freq);
3594 nla_nest_end(msg, nest);
3595
3596 if (req->ie)
3597 NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie);
3598
3599 return 0;
3600 nla_put_failure:
3601 return -ENOBUFS;
3602}
3603
3562static int nl80211_send_scan_donemsg(struct sk_buff *msg, 3604static int nl80211_send_scan_donemsg(struct sk_buff *msg,
3563 struct cfg80211_registered_device *rdev, 3605 struct cfg80211_registered_device *rdev,
3564 struct net_device *netdev, 3606 struct net_device *netdev,
3565 u32 pid, u32 seq, int flags, 3607 u32 pid, u32 seq, int flags,
3566 u32 cmd) 3608 u32 cmd)
3567{ 3609{
3568 void *hdr; 3610 void *hdr;
3569 3611
@@ -3574,7 +3616,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
3574 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); 3616 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
3575 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); 3617 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
3576 3618
3577 /* XXX: we should probably bounce back the request? */ 3619 /* ignore errors and send incomplete event anyway */
3620 nl80211_add_scan_req(msg, rdev);
3578 3621
3579 return genlmsg_end(msg, hdr); 3622 return genlmsg_end(msg, hdr);
3580 3623
@@ -3828,7 +3871,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
3828 struct sk_buff *msg; 3871 struct sk_buff *msg;
3829 void *hdr; 3872 void *hdr;
3830 3873
3831 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 3874 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
3832 if (!msg) 3875 if (!msg)
3833 return; 3876 return;
3834 3877
@@ -3852,7 +3895,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
3852 return; 3895 return;
3853 } 3896 }
3854 3897
3855 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); 3898 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
3856 return; 3899 return;
3857 3900
3858 nla_put_failure: 3901 nla_put_failure:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index f87ac1df2df5..ea4c299fbe3b 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2171,7 +2171,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2171 * the country IE rd with what CRDA believes that country should have 2171 * the country IE rd with what CRDA believes that country should have
2172 */ 2172 */
2173 2173
2174 BUG_ON(!country_ie_regdomain); 2174 /*
2175 * Userspace could have sent two replies with only
2176 * one kernel request. By the second reply we would have
2177 * already processed and consumed the country_ie_regdomain.
2178 */
2179 if (!country_ie_regdomain)
2180 return -EALREADY;
2175 BUG_ON(rd == country_ie_regdomain); 2181 BUG_ON(rd == country_ie_regdomain);
2176 2182
2177 /* 2183 /*
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index df59440290e5..e95b638b919f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -29,13 +29,14 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
29 goto out; 29 goto out;
30 30
31 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); 31 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
32 wiphy_to_dev(request->wiphy)->scan_req = NULL;
33 32
34 if (aborted) 33 if (aborted)
35 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); 34 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
36 else 35 else
37 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); 36 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
38 37
38 wiphy_to_dev(request->wiphy)->scan_req = NULL;
39
39#ifdef CONFIG_WIRELESS_EXT 40#ifdef CONFIG_WIRELESS_EXT
40 if (!aborted) { 41 if (!aborted) {
41 memset(&wrqu, 0, sizeof(wrqu)); 42 memset(&wrqu, 0, sizeof(wrqu));
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d072bff463aa..25550692dda6 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -157,26 +157,25 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
157 params->cipher != WLAN_CIPHER_SUITE_WEP104) 157 params->cipher != WLAN_CIPHER_SUITE_WEP104)
158 return -EINVAL; 158 return -EINVAL;
159 159
160 /* TODO: add definitions for the lengths to linux/ieee80211.h */
161 switch (params->cipher) { 160 switch (params->cipher) {
162 case WLAN_CIPHER_SUITE_WEP40: 161 case WLAN_CIPHER_SUITE_WEP40:
163 if (params->key_len != 5) 162 if (params->key_len != WLAN_KEY_LEN_WEP40)
164 return -EINVAL; 163 return -EINVAL;
165 break; 164 break;
166 case WLAN_CIPHER_SUITE_TKIP: 165 case WLAN_CIPHER_SUITE_TKIP:
167 if (params->key_len != 32) 166 if (params->key_len != WLAN_KEY_LEN_TKIP)
168 return -EINVAL; 167 return -EINVAL;
169 break; 168 break;
170 case WLAN_CIPHER_SUITE_CCMP: 169 case WLAN_CIPHER_SUITE_CCMP:
171 if (params->key_len != 16) 170 if (params->key_len != WLAN_KEY_LEN_CCMP)
172 return -EINVAL; 171 return -EINVAL;
173 break; 172 break;
174 case WLAN_CIPHER_SUITE_WEP104: 173 case WLAN_CIPHER_SUITE_WEP104:
175 if (params->key_len != 13) 174 if (params->key_len != WLAN_KEY_LEN_WEP104)
176 return -EINVAL; 175 return -EINVAL;
177 break; 176 break;
178 case WLAN_CIPHER_SUITE_AES_CMAC: 177 case WLAN_CIPHER_SUITE_AES_CMAC:
179 if (params->key_len != 16) 178 if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
180 return -EINVAL; 179 return -EINVAL;
181 break; 180 break;
182 default: 181 default:
@@ -259,7 +258,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
259} 258}
260EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); 259EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
261 260
262int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) 261static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
263{ 262{
264 int ae = meshhdr->flags & MESH_FLAGS_AE; 263 int ae = meshhdr->flags & MESH_FLAGS_AE;
265 /* 7.1.3.5a.2 */ 264 /* 7.1.3.5a.2 */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 711e00a0c9b5..d030c5315672 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -744,3 +744,86 @@ int cfg80211_wext_giwencode(struct net_device *dev,
744 return err; 744 return err;
745} 745}
746EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); 746EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
747
748int cfg80211_wext_siwtxpower(struct net_device *dev,
749 struct iw_request_info *info,
750 union iwreq_data *data, char *extra)
751{
752 struct wireless_dev *wdev = dev->ieee80211_ptr;
753 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
754 enum tx_power_setting type;
755 int dbm = 0;
756
757 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
758 return -EINVAL;
759 if (data->txpower.flags & IW_TXPOW_RANGE)
760 return -EINVAL;
761
762 if (!rdev->ops->set_tx_power)
763 return -EOPNOTSUPP;
764
765 /* only change when not disabling */
766 if (!data->txpower.disabled) {
767 rfkill_set_sw_state(rdev->rfkill, false);
768
769 if (data->txpower.fixed) {
770 /*
771 * wext doesn't support negative values, see
772 * below where it's for automatic
773 */
774 if (data->txpower.value < 0)
775 return -EINVAL;
776 dbm = data->txpower.value;
777 type = TX_POWER_FIXED;
778 /* TODO: do regulatory check! */
779 } else {
780 /*
781 * Automatic power level setting, max being the value
782 * passed in from userland.
783 */
784 if (data->txpower.value < 0) {
785 type = TX_POWER_AUTOMATIC;
786 } else {
787 dbm = data->txpower.value;
788 type = TX_POWER_LIMITED;
789 }
790 }
791 } else {
792 rfkill_set_sw_state(rdev->rfkill, true);
793 schedule_work(&rdev->rfkill_sync);
794 return 0;
795 }
796
797 return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
798}
799EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
800
801int cfg80211_wext_giwtxpower(struct net_device *dev,
802 struct iw_request_info *info,
803 union iwreq_data *data, char *extra)
804{
805 struct wireless_dev *wdev = dev->ieee80211_ptr;
806 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
807 int err, val;
808
809 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
810 return -EINVAL;
811 if (data->txpower.flags & IW_TXPOW_RANGE)
812 return -EINVAL;
813
814 if (!rdev->ops->get_tx_power)
815 return -EOPNOTSUPP;
816
817 err = rdev->ops->get_tx_power(wdev->wiphy, &val);
818 if (err)
819 return err;
820
821 /* well... oh well */
822 data->txpower.fixed = 1;
823 data->txpower.disabled = rfkill_blocked(rdev->rfkill);
824 data->txpower.value = val;
825 data->txpower.flags = IW_TXPOW_DBM;
826
827 return 0;
828}
829EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);