aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-06-02 07:01:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:06:14 -0400
commit1f87f7d3a3b42b20f34cb03f0fd1a41c3d0e27f3 (patch)
tree642882153a48e910a415e6bb23bcfb79fadef6dd
parent6081162e2ed78dfcf149b076b047078ab1445cc2 (diff)
cfg80211: add rfkill support
To be easier on drivers and users, have cfg80211 register an rfkill structure that drivers can access. When soft-killed, simply take down all interfaces; when hard-killed the driver needs to notify us and we will take down the interfaces after the fact. While rfkilled, interfaces cannot be set UP. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/asm-generic/errno.h2
-rw-r--r--include/net/cfg80211.h29
-rw-r--r--include/net/mac80211.h20
-rw-r--r--net/mac80211/cfg.c20
-rw-r--r--net/mac80211/driver-ops.h7
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/util.c2
-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/wext-compat.c11
11 files changed, 172 insertions, 30 deletions
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index e8852c092fea..28cc03bf19e6 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -106,4 +106,6 @@
106#define EOWNERDEAD 130 /* Owner died */ 106#define EOWNERDEAD 130 /* Owner died */
107#define ENOTRECOVERABLE 131 /* State not recoverable */ 107#define ENOTRECOVERABLE 131 /* State not recoverable */
108 108
109#define ERFKILL 132 /* Operation not possible due to RF-kill */
110
109#endif 111#endif
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8b8e4b893625..1a21895b732b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -757,13 +757,11 @@ enum wiphy_params_flags {
757 * @TX_POWER_AUTOMATIC: the dbm parameter is ignored 757 * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
758 * @TX_POWER_LIMITED: limit TX power by the dbm parameter 758 * @TX_POWER_LIMITED: limit TX power by the dbm parameter
759 * @TX_POWER_FIXED: fix TX power to the dbm parameter 759 * @TX_POWER_FIXED: fix TX power to the dbm parameter
760 * @TX_POWER_OFF: turn off completely (will go away)
761 */ 760 */
762enum tx_power_setting { 761enum tx_power_setting {
763 TX_POWER_AUTOMATIC, 762 TX_POWER_AUTOMATIC,
764 TX_POWER_LIMITED, 763 TX_POWER_LIMITED,
765 TX_POWER_FIXED, 764 TX_POWER_FIXED,
766 TX_POWER_OFF,
767}; 765};
768 766
769/** 767/**
@@ -855,8 +853,10 @@ enum tx_power_setting {
855 * 853 *
856 * @set_tx_power: set the transmit power according to the parameters 854 * @set_tx_power: set the transmit power according to the parameters
857 * @get_tx_power: store the current TX power into the dbm variable; 855 * @get_tx_power: store the current TX power into the dbm variable;
858 * return 0 if successful; or -ENETDOWN if successful but power 856 * return 0 if successful
859 * is disabled (this will go away) 857 *
858 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
859 * functions to adjust rfkill hw state
860 */ 860 */
861struct cfg80211_ops { 861struct cfg80211_ops {
862 int (*suspend)(struct wiphy *wiphy); 862 int (*suspend)(struct wiphy *wiphy);
@@ -952,6 +952,8 @@ struct cfg80211_ops {
952 int (*set_tx_power)(struct wiphy *wiphy, 952 int (*set_tx_power)(struct wiphy *wiphy,
953 enum tx_power_setting type, int dbm); 953 enum tx_power_setting type, int dbm);
954 int (*get_tx_power)(struct wiphy *wiphy, int *dbm); 954 int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
955
956 void (*rfkill_poll)(struct wiphy *wiphy);
955}; 957};
956 958
957/* 959/*
@@ -1666,4 +1668,23 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
1666 */ 1668 */
1667void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); 1669void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
1668 1670
1671/**
1672 * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state
1673 * @wiphy: the wiphy
1674 * @blocked: block status
1675 */
1676void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked);
1677
1678/**
1679 * wiphy_rfkill_start_polling - start polling rfkill
1680 * @wiphy: the wiphy
1681 */
1682void wiphy_rfkill_start_polling(struct wiphy *wiphy);
1683
1684/**
1685 * wiphy_rfkill_stop_polling - stop polling rfkill
1686 * @wiphy: the wiphy
1687 */
1688void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
1689
1669#endif /* __NET_CFG80211_H */ 1690#endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0270aa6e08f2..17d61d19d912 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -526,7 +526,7 @@ enum ieee80211_conf_flags {
526/** 526/**
527 * enum ieee80211_conf_changed - denotes which configuration changed 527 * enum ieee80211_conf_changed - denotes which configuration changed
528 * 528 *
529 * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed 529 * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED
530 * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed 530 * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
531 * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed 531 * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
532 * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed 532 * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
@@ -536,7 +536,7 @@ enum ieee80211_conf_flags {
536 * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed 536 * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
537 */ 537 */
538enum ieee80211_conf_changed { 538enum ieee80211_conf_changed {
539 IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), 539 _IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0),
540 IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), 540 IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2),
541 IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), 541 IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3),
542 IEEE80211_CONF_CHANGE_PS = BIT(4), 542 IEEE80211_CONF_CHANGE_PS = BIT(4),
@@ -546,6 +546,14 @@ enum ieee80211_conf_changed {
546 IEEE80211_CONF_CHANGE_IDLE = BIT(8), 546 IEEE80211_CONF_CHANGE_IDLE = BIT(8),
547}; 547};
548 548
549static inline __deprecated enum ieee80211_conf_changed
550__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
551{
552 return _IEEE80211_CONF_CHANGE_RADIO_ENABLED;
553}
554#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \
555 __IEEE80211_CONF_CHANGE_RADIO_ENABLED()
556
549/** 557/**
550 * struct ieee80211_conf - configuration of the device 558 * struct ieee80211_conf - configuration of the device
551 * 559 *
@@ -585,7 +593,7 @@ struct ieee80211_conf {
585 int max_sleep_period; 593 int max_sleep_period;
586 594
587 u16 listen_interval; 595 u16 listen_interval;
588 bool radio_enabled; 596 bool __deprecated radio_enabled;
589 597
590 u8 long_frame_max_tx_count, short_frame_max_tx_count; 598 u8 long_frame_max_tx_count, short_frame_max_tx_count;
591 599
@@ -1396,6 +1404,10 @@ enum ieee80211_ampdu_mlme_action {
1396 * is the first frame we expect to perform the action on. Notice 1404 * is the first frame we expect to perform the action on. Notice
1397 * that TX/RX_STOP can pass NULL for this parameter. 1405 * that TX/RX_STOP can pass NULL for this parameter.
1398 * Returns a negative error code on failure. 1406 * Returns a negative error code on failure.
1407 *
1408 * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
1409 * need to set wiphy->rfkill_poll to %true before registration,
1410 * and need to call wiphy_rfkill_set_hw_state() in the callback.
1399 */ 1411 */
1400struct ieee80211_ops { 1412struct ieee80211_ops {
1401 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); 1413 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1444,6 +1456,8 @@ struct ieee80211_ops {
1444 int (*ampdu_action)(struct ieee80211_hw *hw, 1456 int (*ampdu_action)(struct ieee80211_hw *hw,
1445 enum ieee80211_ampdu_mlme_action action, 1457 enum ieee80211_ampdu_mlme_action action,
1446 struct ieee80211_sta *sta, u16 tid, u16 *ssn); 1458 struct ieee80211_sta *sta, u16 tid, u16 *ssn);
1459
1460 void (*rfkill_poll)(struct ieee80211_hw *hw);
1447}; 1461};
1448 1462
1449/** 1463/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 81258acf48bc..a9211cc183cb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1340,7 +1340,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
1340 struct ieee80211_local *local = wiphy_priv(wiphy); 1340 struct ieee80211_local *local = wiphy_priv(wiphy);
1341 struct ieee80211_channel *chan = local->hw.conf.channel; 1341 struct ieee80211_channel *chan = local->hw.conf.channel;
1342 u32 changes = 0; 1342 u32 changes = 0;
1343 bool radio_enabled = true;
1344 1343
1345 switch (type) { 1344 switch (type) {
1346 case TX_POWER_AUTOMATIC: 1345 case TX_POWER_AUTOMATIC:
@@ -1359,14 +1358,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
1359 return -EINVAL; 1358 return -EINVAL;
1360 local->user_power_level = dbm; 1359 local->user_power_level = dbm;
1361 break; 1360 break;
1362 case TX_POWER_OFF:
1363 radio_enabled = false;
1364 break;
1365 }
1366
1367 if (radio_enabled != local->hw.conf.radio_enabled) {
1368 changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
1369 local->hw.conf.radio_enabled = radio_enabled;
1370 } 1361 }
1371 1362
1372 ieee80211_hw_config(local, changes); 1363 ieee80211_hw_config(local, changes);
@@ -1380,12 +1371,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
1380 1371
1381 *dbm = local->hw.conf.power_level; 1372 *dbm = local->hw.conf.power_level;
1382 1373
1383 if (!local->hw.conf.radio_enabled)
1384 return -ENETDOWN;
1385
1386 return 0; 1374 return 0;
1387} 1375}
1388 1376
1377static void ieee80211_rfkill_poll(struct wiphy *wiphy)
1378{
1379 struct ieee80211_local *local = wiphy_priv(wiphy);
1380
1381 drv_rfkill_poll(local);
1382}
1383
1389struct cfg80211_ops mac80211_config_ops = { 1384struct cfg80211_ops mac80211_config_ops = {
1390 .add_virtual_intf = ieee80211_add_iface, 1385 .add_virtual_intf = ieee80211_add_iface,
1391 .del_virtual_intf = ieee80211_del_iface, 1386 .del_virtual_intf = ieee80211_del_iface,
@@ -1427,4 +1422,5 @@ struct cfg80211_ops mac80211_config_ops = {
1427 .set_wiphy_params = ieee80211_set_wiphy_params, 1422 .set_wiphy_params = ieee80211_set_wiphy_params,
1428 .set_tx_power = ieee80211_set_tx_power, 1423 .set_tx_power = ieee80211_set_tx_power,
1429 .get_tx_power = ieee80211_get_tx_power, 1424 .get_tx_power = ieee80211_get_tx_power,
1425 .rfkill_poll = ieee80211_rfkill_poll,
1430}; 1426};
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3912b5334b9c..b13446afd48f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
181 sta, tid, ssn); 181 sta, tid, ssn);
182 return -EOPNOTSUPP; 182 return -EOPNOTSUPP;
183} 183}
184
185
186static inline void drv_rfkill_poll(struct ieee80211_local *local)
187{
188 if (local->ops->rfkill_poll)
189 local->ops->rfkill_poll(&local->hw);
190}
184#endif /* __MAC80211_DRIVER_OPS */ 191#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8c9f1c722cdb..b7c8a4484298 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev)
170 goto err_del_bss; 170 goto err_del_bss;
171 /* we're brought up, everything changes */ 171 /* we're brought up, everything changes */
172 hw_reconf_flags = ~0; 172 hw_reconf_flags = ~0;
173 ieee80211_led_radio(local, local->hw.conf.radio_enabled); 173 ieee80211_led_radio(local, true);
174 } 174 }
175 175
176 /* 176 /*
@@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev)
560 560
561 drv_stop(local); 561 drv_stop(local);
562 562
563 ieee80211_led_radio(local, 0); 563 ieee80211_led_radio(local, false);
564 564
565 flush_workqueue(local->hw.workqueue); 565 flush_workqueue(local->hw.workqueue);
566 566
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 31284c984e38..22f63815fb36 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -973,7 +973,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
973 if (local->open_count) { 973 if (local->open_count) {
974 res = drv_start(local); 974 res = drv_start(local);
975 975
976 ieee80211_led_radio(local, hw->conf.radio_enabled); 976 ieee80211_led_radio(local, true);
977 } 977 }
978 978
979 /* add interfaces */ 979 /* add interfaces */
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/wext-compat.c b/net/wireless/wext-compat.c
index 9fbfb8536e75..d030c5315672 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -764,6 +764,8 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
764 764
765 /* only change when not disabling */ 765 /* only change when not disabling */
766 if (!data->txpower.disabled) { 766 if (!data->txpower.disabled) {
767 rfkill_set_sw_state(rdev->rfkill, false);
768
767 if (data->txpower.fixed) { 769 if (data->txpower.fixed) {
768 /* 770 /*
769 * wext doesn't support negative values, see 771 * wext doesn't support negative values, see
@@ -787,7 +789,9 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
787 } 789 }
788 } 790 }
789 } else { 791 } else {
790 type = TX_POWER_OFF; 792 rfkill_set_sw_state(rdev->rfkill, true);
793 schedule_work(&rdev->rfkill_sync);
794 return 0;
791 } 795 }
792 796
793 return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; 797 return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
@@ -811,13 +815,12 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
811 return -EOPNOTSUPP; 815 return -EOPNOTSUPP;
812 816
813 err = rdev->ops->get_tx_power(wdev->wiphy, &val); 817 err = rdev->ops->get_tx_power(wdev->wiphy, &val);
814 /* HACK!!! */ 818 if (err)
815 if (err && err != -ENETDOWN)
816 return err; 819 return err;
817 820
818 /* well... oh well */ 821 /* well... oh well */
819 data->txpower.fixed = 1; 822 data->txpower.fixed = 1;
820 data->txpower.disabled = err == -ENETDOWN; 823 data->txpower.disabled = rfkill_blocked(rdev->rfkill);
821 data->txpower.value = val; 824 data->txpower.value = val;
822 data->txpower.flags = IW_TXPOW_DBM; 825 data->txpower.flags = IW_TXPOW_DBM;
823 826