diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-08 08:22:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-24 15:05:09 -0400 |
commit | fffd0934b9390f34bec45762192b7edd3b12b4b5 (patch) | |
tree | d9779803763261f5795fe39a402d79c4220a3a22 /net/wireless/wext-compat.c | |
parent | b9454e83cac42fcdc90bfbfba479132bd6629455 (diff) |
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.
In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.
Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/wext-compat.c')
-rw-r--r-- | net/wireless/wext-compat.c | 163 |
1 files changed, 101 insertions, 62 deletions
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5088d89a30fc..5d0176338539 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
453 | } | 453 | } |
454 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 454 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
455 | 455 | ||
456 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 456 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
457 | struct net_device *dev, const u8 *addr, | 457 | struct net_device *dev, const u8 *addr, |
458 | bool remove, bool tx_key, int idx, | 458 | bool remove, bool tx_key, int idx, |
459 | struct key_params *params) | 459 | struct key_params *params) |
460 | { | 460 | { |
461 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 461 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
462 | int err; | 462 | int err, i; |
463 | |||
464 | if (!wdev->wext.keys) { | ||
465 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | ||
466 | GFP_KERNEL); | ||
467 | if (!wdev->wext.keys) | ||
468 | return -ENOMEM; | ||
469 | for (i = 0; i < 6; i++) | ||
470 | wdev->wext.keys->params[i].key = | ||
471 | wdev->wext.keys->data[i]; | ||
472 | } | ||
473 | |||
474 | if (wdev->iftype != NL80211_IFTYPE_ADHOC && | ||
475 | wdev->iftype != NL80211_IFTYPE_STATION) | ||
476 | return -EOPNOTSUPP; | ||
463 | 477 | ||
464 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | 478 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { |
479 | if (!wdev->current_bss) | ||
480 | return -ENOLINK; | ||
481 | |||
465 | if (!rdev->ops->set_default_mgmt_key) | 482 | if (!rdev->ops->set_default_mgmt_key) |
466 | return -EOPNOTSUPP; | 483 | return -EOPNOTSUPP; |
467 | 484 | ||
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
471 | return -EINVAL; | 488 | return -EINVAL; |
472 | 489 | ||
473 | if (remove) { | 490 | if (remove) { |
474 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 491 | err = 0; |
492 | if (wdev->current_bss) | ||
493 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | ||
475 | if (!err) { | 494 | if (!err) { |
495 | if (!addr) { | ||
496 | wdev->wext.keys->params[idx].key_len = 0; | ||
497 | wdev->wext.keys->params[idx].cipher = 0; | ||
498 | } | ||
476 | if (idx == wdev->wext.default_key) | 499 | if (idx == wdev->wext.default_key) |
477 | wdev->wext.default_key = -1; | 500 | wdev->wext.default_key = -1; |
478 | else if (idx == wdev->wext.default_mgmt_key) | 501 | else if (idx == wdev->wext.default_mgmt_key) |
@@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
486 | return 0; | 509 | return 0; |
487 | 510 | ||
488 | return err; | 511 | return err; |
489 | } else { | 512 | } |
490 | if (addr) | ||
491 | tx_key = false; | ||
492 | 513 | ||
493 | if (cfg80211_validate_key_settings(params, idx, addr)) | 514 | if (addr) |
494 | return -EINVAL; | 515 | tx_key = false; |
495 | 516 | ||
517 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | ||
518 | return -EINVAL; | ||
519 | |||
520 | err = 0; | ||
521 | if (wdev->current_bss) | ||
496 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 522 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); |
497 | if (err) | 523 | if (err) |
498 | return err; | 524 | return err; |
525 | |||
526 | if (!addr) { | ||
527 | wdev->wext.keys->params[idx] = *params; | ||
528 | memcpy(wdev->wext.keys->data[idx], | ||
529 | params->key, params->key_len); | ||
530 | wdev->wext.keys->params[idx].key = | ||
531 | wdev->wext.keys->data[idx]; | ||
532 | } | ||
499 | 533 | ||
500 | if (tx_key || (!addr && wdev->wext.default_key == -1)) { | 534 | if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC && |
535 | (tx_key || (!addr && wdev->wext.default_key == -1))) { | ||
536 | if (wdev->current_bss) | ||
501 | err = rdev->ops->set_default_key(&rdev->wiphy, | 537 | err = rdev->ops->set_default_key(&rdev->wiphy, |
502 | dev, idx); | 538 | dev, idx); |
503 | if (!err) | 539 | if (!err) |
504 | wdev->wext.default_key = idx; | 540 | wdev->wext.default_key = idx; |
505 | return err; | 541 | return err; |
506 | } | 542 | } |
507 | 543 | ||
508 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && | 544 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && |
509 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { | 545 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { |
546 | if (wdev->current_bss) | ||
510 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | 547 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, |
511 | dev, idx); | 548 | dev, idx); |
512 | if (!err) | 549 | if (!err) |
513 | wdev->wext.default_mgmt_key = idx; | 550 | wdev->wext.default_mgmt_key = idx; |
514 | return err; | 551 | return err; |
515 | } | ||
516 | |||
517 | return 0; | ||
518 | } | 552 | } |
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | ||
558 | struct net_device *dev, const u8 *addr, | ||
559 | bool remove, bool tx_key, int idx, | ||
560 | struct key_params *params) | ||
561 | { | ||
562 | int err; | ||
563 | |||
564 | wdev_lock(dev->ieee80211_ptr); | ||
565 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | ||
566 | tx_key, idx, params); | ||
567 | wdev_unlock(dev->ieee80211_ptr); | ||
568 | |||
569 | return err; | ||
519 | } | 570 | } |
520 | 571 | ||
521 | int cfg80211_wext_siwencode(struct net_device *dev, | 572 | int cfg80211_wext_siwencode(struct net_device *dev, |
@@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
528 | bool remove = false; | 579 | bool remove = false; |
529 | struct key_params params; | 580 | struct key_params params; |
530 | 581 | ||
582 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
583 | wdev->iftype != NL80211_IFTYPE_ADHOC) | ||
584 | return -EOPNOTSUPP; | ||
585 | |||
531 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | 586 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
532 | if (!rdev->ops->del_key || | 587 | if (!rdev->ops->del_key || |
533 | !rdev->ops->add_key || | 588 | !rdev->ops->add_key || |
@@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
548 | remove = true; | 603 | remove = true; |
549 | else if (erq->length == 0) { | 604 | else if (erq->length == 0) { |
550 | /* No key data - just set the default TX key index */ | 605 | /* No key data - just set the default TX key index */ |
551 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); | 606 | err = 0; |
607 | wdev_lock(wdev); | ||
608 | if (wdev->current_bss) | ||
609 | err = rdev->ops->set_default_key(&rdev->wiphy, | ||
610 | dev, idx); | ||
552 | if (!err) | 611 | if (!err) |
553 | wdev->wext.default_key = idx; | 612 | wdev->wext.default_key = idx; |
613 | wdev_unlock(wdev); | ||
554 | return err; | 614 | return err; |
555 | } | 615 | } |
556 | 616 | ||
@@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
583 | struct key_params params; | 643 | struct key_params params; |
584 | u32 cipher; | 644 | u32 cipher; |
585 | 645 | ||
646 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
647 | wdev->iftype != NL80211_IFTYPE_ADHOC) | ||
648 | return -EOPNOTSUPP; | ||
649 | |||
586 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | 650 | /* no use -- only MFP (set_default_mgmt_key) is optional */ |
587 | if (!rdev->ops->del_key || | 651 | if (!rdev->ops->del_key || |
588 | !rdev->ops->add_key || | 652 | !rdev->ops->add_key || |
@@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
656 | } | 720 | } |
657 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); | 721 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); |
658 | 722 | ||
659 | struct giwencode_cookie { | ||
660 | size_t buflen; | ||
661 | char *keybuf; | ||
662 | }; | ||
663 | |||
664 | static void giwencode_get_key_cb(void *cookie, struct key_params *params) | ||
665 | { | ||
666 | struct giwencode_cookie *data = cookie; | ||
667 | |||
668 | if (!params->key) { | ||
669 | data->buflen = 0; | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | data->buflen = min_t(size_t, data->buflen, params->key_len); | ||
674 | memcpy(data->keybuf, params->key, data->buflen); | ||
675 | } | ||
676 | |||
677 | int cfg80211_wext_giwencode(struct net_device *dev, | 723 | int cfg80211_wext_giwencode(struct net_device *dev, |
678 | struct iw_request_info *info, | 724 | struct iw_request_info *info, |
679 | struct iw_point *erq, char *keybuf) | 725 | struct iw_point *erq, char *keybuf) |
680 | { | 726 | { |
681 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 727 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
682 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 728 | int idx; |
683 | int idx, err; | ||
684 | struct giwencode_cookie data = { | ||
685 | .keybuf = keybuf, | ||
686 | .buflen = erq->length, | ||
687 | }; | ||
688 | 729 | ||
689 | if (!rdev->ops->get_key) | 730 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
731 | wdev->iftype != NL80211_IFTYPE_ADHOC) | ||
690 | return -EOPNOTSUPP; | 732 | return -EOPNOTSUPP; |
691 | 733 | ||
692 | idx = erq->flags & IW_ENCODE_INDEX; | 734 | idx = erq->flags & IW_ENCODE_INDEX; |
@@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_device *dev, | |||
701 | 743 | ||
702 | erq->flags = idx + 1; | 744 | erq->flags = idx + 1; |
703 | 745 | ||
704 | err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, | 746 | if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { |
705 | giwencode_get_key_cb); | ||
706 | if (!err) { | ||
707 | erq->length = data.buflen; | ||
708 | erq->flags |= IW_ENCODE_ENABLED; | ||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | if (err == -ENOENT) { | ||
713 | erq->flags |= IW_ENCODE_DISABLED; | 747 | erq->flags |= IW_ENCODE_DISABLED; |
714 | erq->length = 0; | 748 | erq->length = 0; |
715 | return 0; | 749 | return 0; |
716 | } | 750 | } |
717 | 751 | ||
718 | return err; | 752 | erq->length = min_t(size_t, erq->length, |
753 | wdev->wext.keys->params[idx].key_len); | ||
754 | memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); | ||
755 | erq->flags |= IW_ENCODE_ENABLED; | ||
756 | |||
757 | return 0; | ||
719 | } | 758 | } |
720 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | 759 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); |
721 | 760 | ||