diff options
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r-- | net/rfkill/rfkill.c | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 47e0b2d232e3..d5735799ccd9 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -37,7 +37,7 @@ MODULE_DESCRIPTION("RF switch support"); | |||
37 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
38 | 38 | ||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | 39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ |
40 | static DEFINE_MUTEX(rfkill_mutex); | 40 | static DEFINE_MUTEX(rfkill_global_mutex); |
41 | 41 | ||
42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; | 42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; |
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); | 43 | module_param_named(default_state, rfkill_default_state, uint, 0444); |
@@ -76,6 +76,7 @@ static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | |||
76 | */ | 76 | */ |
77 | int register_rfkill_notifier(struct notifier_block *nb) | 77 | int register_rfkill_notifier(struct notifier_block *nb) |
78 | { | 78 | { |
79 | BUG_ON(!nb); | ||
79 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); | 80 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); |
80 | } | 81 | } |
81 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); | 82 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); |
@@ -91,6 +92,7 @@ EXPORT_SYMBOL_GPL(register_rfkill_notifier); | |||
91 | */ | 92 | */ |
92 | int unregister_rfkill_notifier(struct notifier_block *nb) | 93 | int unregister_rfkill_notifier(struct notifier_block *nb) |
93 | { | 94 | { |
95 | BUG_ON(!nb); | ||
94 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); | 96 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); |
95 | } | 97 | } |
96 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); | 98 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); |
@@ -202,6 +204,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
202 | * RFKILL_STATE_HARD_BLOCKED */ | 204 | * RFKILL_STATE_HARD_BLOCKED */ |
203 | break; | 205 | break; |
204 | default: | 206 | default: |
207 | WARN(1, KERN_WARNING | ||
208 | "rfkill: illegal state %d passed as parameter " | ||
209 | "to rfkill_toggle_radio\n", state); | ||
205 | return -EINVAL; | 210 | return -EINVAL; |
206 | } | 211 | } |
207 | 212 | ||
@@ -229,14 +234,18 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
229 | * unless a specific switch is claimed by userspace (in which case, | 234 | * unless a specific switch is claimed by userspace (in which case, |
230 | * that switch is left alone) or suspended. | 235 | * that switch is left alone) or suspended. |
231 | * | 236 | * |
232 | * Caller must have acquired rfkill_mutex. | 237 | * Caller must have acquired rfkill_global_mutex. |
233 | */ | 238 | */ |
234 | static void __rfkill_switch_all(const enum rfkill_type type, | 239 | static void __rfkill_switch_all(const enum rfkill_type type, |
235 | const enum rfkill_state state) | 240 | const enum rfkill_state state) |
236 | { | 241 | { |
237 | struct rfkill *rfkill; | 242 | struct rfkill *rfkill; |
238 | 243 | ||
239 | if (unlikely(state >= RFKILL_STATE_MAX)) | 244 | if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), |
245 | KERN_WARNING | ||
246 | "rfkill: illegal state %d or type %d " | ||
247 | "passed as parameter to __rfkill_switch_all\n", | ||
248 | state, type)) | ||
240 | return; | 249 | return; |
241 | 250 | ||
242 | rfkill_global_states[type].current_state = state; | 251 | rfkill_global_states[type].current_state = state; |
@@ -254,14 +263,14 @@ static void __rfkill_switch_all(const enum rfkill_type type, | |||
254 | * @type: type of interfaces to be affected | 263 | * @type: type of interfaces to be affected |
255 | * @state: the new state | 264 | * @state: the new state |
256 | * | 265 | * |
257 | * Acquires rfkill_mutex and calls __rfkill_switch_all(@type, @state). | 266 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). |
258 | * Please refer to __rfkill_switch_all() for details. | 267 | * Please refer to __rfkill_switch_all() for details. |
259 | */ | 268 | */ |
260 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | 269 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) |
261 | { | 270 | { |
262 | mutex_lock(&rfkill_mutex); | 271 | mutex_lock(&rfkill_global_mutex); |
263 | __rfkill_switch_all(type, state); | 272 | __rfkill_switch_all(type, state); |
264 | mutex_unlock(&rfkill_mutex); | 273 | mutex_unlock(&rfkill_global_mutex); |
265 | } | 274 | } |
266 | EXPORT_SYMBOL(rfkill_switch_all); | 275 | EXPORT_SYMBOL(rfkill_switch_all); |
267 | 276 | ||
@@ -269,7 +278,7 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
269 | * rfkill_epo - emergency power off all transmitters | 278 | * rfkill_epo - emergency power off all transmitters |
270 | * | 279 | * |
271 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | 280 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, |
272 | * ignoring everything in its path but rfkill_mutex and rfkill->mutex. | 281 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. |
273 | * | 282 | * |
274 | * The global state before the EPO is saved and can be restored later | 283 | * The global state before the EPO is saved and can be restored later |
275 | * using rfkill_restore_states(). | 284 | * using rfkill_restore_states(). |
@@ -279,7 +288,8 @@ void rfkill_epo(void) | |||
279 | struct rfkill *rfkill; | 288 | struct rfkill *rfkill; |
280 | int i; | 289 | int i; |
281 | 290 | ||
282 | mutex_lock(&rfkill_mutex); | 291 | mutex_lock(&rfkill_global_mutex); |
292 | |||
283 | list_for_each_entry(rfkill, &rfkill_list, node) { | 293 | list_for_each_entry(rfkill, &rfkill_list, node) { |
284 | mutex_lock(&rfkill->mutex); | 294 | mutex_lock(&rfkill->mutex); |
285 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 295 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
@@ -291,7 +301,7 @@ void rfkill_epo(void) | |||
291 | rfkill_global_states[i].current_state = | 301 | rfkill_global_states[i].current_state = |
292 | RFKILL_STATE_SOFT_BLOCKED; | 302 | RFKILL_STATE_SOFT_BLOCKED; |
293 | } | 303 | } |
294 | mutex_unlock(&rfkill_mutex); | 304 | mutex_unlock(&rfkill_global_mutex); |
295 | } | 305 | } |
296 | EXPORT_SYMBOL_GPL(rfkill_epo); | 306 | EXPORT_SYMBOL_GPL(rfkill_epo); |
297 | 307 | ||
@@ -306,10 +316,11 @@ void rfkill_restore_states(void) | |||
306 | { | 316 | { |
307 | int i; | 317 | int i; |
308 | 318 | ||
309 | mutex_lock(&rfkill_mutex); | 319 | mutex_lock(&rfkill_global_mutex); |
320 | |||
310 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | 321 | for (i = 0; i < RFKILL_TYPE_MAX; i++) |
311 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); | 322 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); |
312 | mutex_unlock(&rfkill_mutex); | 323 | mutex_unlock(&rfkill_global_mutex); |
313 | } | 324 | } |
314 | EXPORT_SYMBOL_GPL(rfkill_restore_states); | 325 | EXPORT_SYMBOL_GPL(rfkill_restore_states); |
315 | 326 | ||
@@ -334,7 +345,11 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | |||
334 | { | 345 | { |
335 | enum rfkill_state oldstate; | 346 | enum rfkill_state oldstate; |
336 | 347 | ||
337 | if (unlikely(state >= RFKILL_STATE_MAX)) | 348 | BUG_ON(!rfkill); |
349 | if (WARN((state >= RFKILL_STATE_MAX), | ||
350 | KERN_WARNING | ||
351 | "rfkill: illegal state %d passed as parameter " | ||
352 | "to rfkill_force_state\n", state)) | ||
338 | return -EINVAL; | 353 | return -EINVAL; |
339 | 354 | ||
340 | mutex_lock(&rfkill->mutex); | 355 | mutex_lock(&rfkill->mutex); |
@@ -402,12 +417,16 @@ static ssize_t rfkill_state_store(struct device *dev, | |||
402 | const char *buf, size_t count) | 417 | const char *buf, size_t count) |
403 | { | 418 | { |
404 | struct rfkill *rfkill = to_rfkill(dev); | 419 | struct rfkill *rfkill = to_rfkill(dev); |
405 | unsigned int state = simple_strtoul(buf, NULL, 0); | 420 | unsigned long state; |
406 | int error; | 421 | int error; |
407 | 422 | ||
408 | if (!capable(CAP_NET_ADMIN)) | 423 | if (!capable(CAP_NET_ADMIN)) |
409 | return -EPERM; | 424 | return -EPERM; |
410 | 425 | ||
426 | error = strict_strtoul(buf, 0, &state); | ||
427 | if (error) | ||
428 | return error; | ||
429 | |||
411 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | 430 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ |
412 | if (state != RFKILL_STATE_UNBLOCKED && | 431 | if (state != RFKILL_STATE_UNBLOCKED && |
413 | state != RFKILL_STATE_SOFT_BLOCKED) | 432 | state != RFKILL_STATE_SOFT_BLOCKED) |
@@ -427,7 +446,7 @@ static ssize_t rfkill_claim_show(struct device *dev, | |||
427 | { | 446 | { |
428 | struct rfkill *rfkill = to_rfkill(dev); | 447 | struct rfkill *rfkill = to_rfkill(dev); |
429 | 448 | ||
430 | return sprintf(buf, "%d", rfkill->user_claim); | 449 | return sprintf(buf, "%d\n", rfkill->user_claim); |
431 | } | 450 | } |
432 | 451 | ||
433 | static ssize_t rfkill_claim_store(struct device *dev, | 452 | static ssize_t rfkill_claim_store(struct device *dev, |
@@ -435,7 +454,8 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
435 | const char *buf, size_t count) | 454 | const char *buf, size_t count) |
436 | { | 455 | { |
437 | struct rfkill *rfkill = to_rfkill(dev); | 456 | struct rfkill *rfkill = to_rfkill(dev); |
438 | bool claim = !!simple_strtoul(buf, NULL, 0); | 457 | unsigned long claim_tmp; |
458 | bool claim; | ||
439 | int error; | 459 | int error; |
440 | 460 | ||
441 | if (!capable(CAP_NET_ADMIN)) | 461 | if (!capable(CAP_NET_ADMIN)) |
@@ -444,11 +464,16 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
444 | if (rfkill->user_claim_unsupported) | 464 | if (rfkill->user_claim_unsupported) |
445 | return -EOPNOTSUPP; | 465 | return -EOPNOTSUPP; |
446 | 466 | ||
467 | error = strict_strtoul(buf, 0, &claim_tmp); | ||
468 | if (error) | ||
469 | return error; | ||
470 | claim = !!claim_tmp; | ||
471 | |||
447 | /* | 472 | /* |
448 | * Take the global lock to make sure the kernel is not in | 473 | * Take the global lock to make sure the kernel is not in |
449 | * the middle of rfkill_switch_all | 474 | * the middle of rfkill_switch_all |
450 | */ | 475 | */ |
451 | error = mutex_lock_interruptible(&rfkill_mutex); | 476 | error = mutex_lock_interruptible(&rfkill_global_mutex); |
452 | if (error) | 477 | if (error) |
453 | return error; | 478 | return error; |
454 | 479 | ||
@@ -463,7 +488,7 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
463 | rfkill->user_claim = claim; | 488 | rfkill->user_claim = claim; |
464 | } | 489 | } |
465 | 490 | ||
466 | mutex_unlock(&rfkill_mutex); | 491 | mutex_unlock(&rfkill_global_mutex); |
467 | 492 | ||
468 | return error ? error : count; | 493 | return error ? error : count; |
469 | } | 494 | } |
@@ -583,10 +608,10 @@ static int rfkill_check_duplicity(const struct rfkill *rfkill) | |||
583 | memset(seen, 0, sizeof(seen)); | 608 | memset(seen, 0, sizeof(seen)); |
584 | 609 | ||
585 | list_for_each_entry(p, &rfkill_list, node) { | 610 | list_for_each_entry(p, &rfkill_list, node) { |
586 | if (p == rfkill) { | 611 | if (WARN((p == rfkill), KERN_WARNING |
587 | WARN_ON(1); | 612 | "rfkill: illegal attempt to register " |
613 | "an already registered rfkill struct\n")) | ||
588 | return -EEXIST; | 614 | return -EEXIST; |
589 | } | ||
590 | set_bit(p->type, seen); | 615 | set_bit(p->type, seen); |
591 | } | 616 | } |
592 | 617 | ||
@@ -598,7 +623,7 @@ static int rfkill_add_switch(struct rfkill *rfkill) | |||
598 | { | 623 | { |
599 | int error; | 624 | int error; |
600 | 625 | ||
601 | mutex_lock(&rfkill_mutex); | 626 | mutex_lock(&rfkill_global_mutex); |
602 | 627 | ||
603 | error = rfkill_check_duplicity(rfkill); | 628 | error = rfkill_check_duplicity(rfkill); |
604 | if (error < 0) | 629 | if (error < 0) |
@@ -619,16 +644,16 @@ static int rfkill_add_switch(struct rfkill *rfkill) | |||
619 | 644 | ||
620 | error = 0; | 645 | error = 0; |
621 | unlock_out: | 646 | unlock_out: |
622 | mutex_unlock(&rfkill_mutex); | 647 | mutex_unlock(&rfkill_global_mutex); |
623 | 648 | ||
624 | return error; | 649 | return error; |
625 | } | 650 | } |
626 | 651 | ||
627 | static void rfkill_remove_switch(struct rfkill *rfkill) | 652 | static void rfkill_remove_switch(struct rfkill *rfkill) |
628 | { | 653 | { |
629 | mutex_lock(&rfkill_mutex); | 654 | mutex_lock(&rfkill_global_mutex); |
630 | list_del_init(&rfkill->node); | 655 | list_del_init(&rfkill->node); |
631 | mutex_unlock(&rfkill_mutex); | 656 | mutex_unlock(&rfkill_global_mutex); |
632 | 657 | ||
633 | mutex_lock(&rfkill->mutex); | 658 | mutex_lock(&rfkill->mutex); |
634 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 659 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
@@ -654,6 +679,12 @@ struct rfkill * __must_check rfkill_allocate(struct device *parent, | |||
654 | struct rfkill *rfkill; | 679 | struct rfkill *rfkill; |
655 | struct device *dev; | 680 | struct device *dev; |
656 | 681 | ||
682 | if (WARN((type >= RFKILL_TYPE_MAX), | ||
683 | KERN_WARNING | ||
684 | "rfkill: illegal type %d passed as parameter " | ||
685 | "to rfkill_allocate\n", type)) | ||
686 | return NULL; | ||
687 | |||
657 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); | 688 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); |
658 | if (!rfkill) | 689 | if (!rfkill) |
659 | return NULL; | 690 | return NULL; |
@@ -726,11 +757,12 @@ int __must_check rfkill_register(struct rfkill *rfkill) | |||
726 | struct device *dev = &rfkill->dev; | 757 | struct device *dev = &rfkill->dev; |
727 | int error; | 758 | int error; |
728 | 759 | ||
729 | if (!rfkill->toggle_radio) | 760 | if (WARN((!rfkill || !rfkill->toggle_radio || |
730 | return -EINVAL; | 761 | rfkill->type >= RFKILL_TYPE_MAX || |
731 | if (rfkill->type >= RFKILL_TYPE_MAX) | 762 | rfkill->state >= RFKILL_STATE_MAX), |
732 | return -EINVAL; | 763 | KERN_WARNING |
733 | if (rfkill->state >= RFKILL_STATE_MAX) | 764 | "rfkill: attempt to register a " |
765 | "badly initialized rfkill struct\n")) | ||
734 | return -EINVAL; | 766 | return -EINVAL; |
735 | 767 | ||
736 | snprintf(dev->bus_id, sizeof(dev->bus_id), | 768 | snprintf(dev->bus_id, sizeof(dev->bus_id), |
@@ -765,6 +797,7 @@ EXPORT_SYMBOL(rfkill_register); | |||
765 | */ | 797 | */ |
766 | void rfkill_unregister(struct rfkill *rfkill) | 798 | void rfkill_unregister(struct rfkill *rfkill) |
767 | { | 799 | { |
800 | BUG_ON(!rfkill); | ||
768 | device_del(&rfkill->dev); | 801 | device_del(&rfkill->dev); |
769 | rfkill_remove_switch(rfkill); | 802 | rfkill_remove_switch(rfkill); |
770 | rfkill_led_trigger_unregister(rfkill); | 803 | rfkill_led_trigger_unregister(rfkill); |
@@ -801,12 +834,15 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | |||
801 | { | 834 | { |
802 | int error; | 835 | int error; |
803 | 836 | ||
804 | if (type >= RFKILL_TYPE_MAX || | 837 | if (WARN((type >= RFKILL_TYPE_MAX || |
805 | (state != RFKILL_STATE_SOFT_BLOCKED && | 838 | (state != RFKILL_STATE_SOFT_BLOCKED && |
806 | state != RFKILL_STATE_UNBLOCKED)) | 839 | state != RFKILL_STATE_UNBLOCKED)), |
840 | KERN_WARNING | ||
841 | "rfkill: illegal state %d or type %d passed as " | ||
842 | "parameter to rfkill_set_default\n", state, type)) | ||
807 | return -EINVAL; | 843 | return -EINVAL; |
808 | 844 | ||
809 | mutex_lock(&rfkill_mutex); | 845 | mutex_lock(&rfkill_global_mutex); |
810 | 846 | ||
811 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { | 847 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { |
812 | rfkill_global_states[type].default_state = state; | 848 | rfkill_global_states[type].default_state = state; |
@@ -814,7 +850,7 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | |||
814 | } else | 850 | } else |
815 | error = -EPERM; | 851 | error = -EPERM; |
816 | 852 | ||
817 | mutex_unlock(&rfkill_mutex); | 853 | mutex_unlock(&rfkill_global_mutex); |
818 | return error; | 854 | return error; |
819 | } | 855 | } |
820 | EXPORT_SYMBOL_GPL(rfkill_set_default); | 856 | EXPORT_SYMBOL_GPL(rfkill_set_default); |