diff options
-rw-r--r-- | include/net/ieee80211.h | 14 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 238 |
2 files changed, 244 insertions, 8 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index c7ab7cd9de13..dfc5d65cc6c1 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h | |||
@@ -447,6 +447,11 @@ struct ieee80211_device; | |||
447 | #define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ | 447 | #define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ |
448 | #define SEC_LEVEL_3 4 /* Level 2 + CCMP */ | 448 | #define SEC_LEVEL_3 4 /* Level 2 + CCMP */ |
449 | 449 | ||
450 | #define SEC_ALG_NONE 0 | ||
451 | #define SEC_ALG_WEP 1 | ||
452 | #define SEC_ALG_TKIP 2 | ||
453 | #define SEC_ALG_CCMP 3 | ||
454 | |||
450 | #define WEP_KEYS 4 | 455 | #define WEP_KEYS 4 |
451 | #define WEP_KEY_LEN 13 | 456 | #define WEP_KEY_LEN 13 |
452 | #define SCM_KEY_LEN 32 | 457 | #define SCM_KEY_LEN 32 |
@@ -456,6 +461,7 @@ struct ieee80211_security { | |||
456 | u16 active_key:2, | 461 | u16 active_key:2, |
457 | enabled:1, | 462 | enabled:1, |
458 | auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; | 463 | auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; |
464 | u8 encode_alg[WEP_KEYS]; | ||
459 | u8 key_sizes[WEP_KEYS]; | 465 | u8 key_sizes[WEP_KEYS]; |
460 | u8 keys[WEP_KEYS][SCM_KEY_LEN]; | 466 | u8 keys[WEP_KEYS][SCM_KEY_LEN]; |
461 | u8 level; | 467 | u8 level; |
@@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, | |||
824 | extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | 830 | extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, |
825 | struct iw_request_info *info, | 831 | struct iw_request_info *info, |
826 | union iwreq_data *wrqu, char *key); | 832 | union iwreq_data *wrqu, char *key); |
833 | #if WIRELESS_EXT > 17 | ||
834 | extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, | ||
835 | struct iw_request_info *info, | ||
836 | union iwreq_data *wrqu, char *extra); | ||
837 | extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, | ||
838 | struct iw_request_info *info, | ||
839 | union iwreq_data *wrqu, char *extra); | ||
840 | #endif | ||
827 | 841 | ||
828 | extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) | 842 | extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) |
829 | { | 843 | { |
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 49afea7989d0..db66217699d5 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c | |||
@@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, | |||
422 | * TODO: When WPA is added this is one place that needs to change */ | 422 | * TODO: When WPA is added this is one place that needs to change */ |
423 | sec.flags |= SEC_LEVEL; | 423 | sec.flags |= SEC_LEVEL; |
424 | sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ | 424 | sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ |
425 | sec.encode_alg[key] = SEC_ALG_WEP; | ||
425 | 426 | ||
426 | done: | 427 | done: |
427 | if (ieee->set_security) | 428 | if (ieee->set_security) |
@@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | |||
469 | return 0; | 470 | return 0; |
470 | } | 471 | } |
471 | 472 | ||
472 | if (sec->level != SEC_LEVEL_1) { | ||
473 | /* only WEP is supported with wireless extensions, so just | ||
474 | * report that encryption is used */ | ||
475 | erq->length = 0; | ||
476 | erq->flags |= IW_ENCODE_ENABLED; | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | len = sec->key_sizes[key]; | 473 | len = sec->key_sizes[key]; |
481 | memcpy(keybuf, sec->keys[key], len); | 474 | memcpy(keybuf, sec->keys[key], len); |
482 | 475 | ||
@@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | |||
491 | return 0; | 484 | return 0; |
492 | } | 485 | } |
493 | 486 | ||
487 | #if WIRELESS_EXT > 17 | ||
488 | int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, | ||
489 | struct iw_request_info *info, | ||
490 | union iwreq_data *wrqu, char *extra) | ||
491 | { | ||
492 | struct net_device *dev = ieee->dev; | ||
493 | struct iw_point *encoding = &wrqu->encoding; | ||
494 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
495 | int i, idx, ret = 0; | ||
496 | const char *alg, *module; | ||
497 | struct ieee80211_crypto_ops *ops; | ||
498 | struct ieee80211_crypt_data **crypt; | ||
499 | |||
500 | struct ieee80211_security sec = { | ||
501 | .flags = 0, | ||
502 | }; | ||
503 | |||
504 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
505 | if (idx) { | ||
506 | if (idx < 1 || idx > WEP_KEYS) | ||
507 | return -EINVAL; | ||
508 | idx--; | ||
509 | } else | ||
510 | idx = ieee->tx_keyidx; | ||
511 | |||
512 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) | ||
513 | crypt = &ieee->crypt[idx]; | ||
514 | else { | ||
515 | if (idx != 0) | ||
516 | return -EINVAL; | ||
517 | if (ieee->iw_mode == IW_MODE_INFRA) | ||
518 | crypt = &ieee->crypt[idx]; | ||
519 | else | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | sec.flags |= SEC_ENABLED | SEC_ENCRYPT; | ||
524 | if ((encoding->flags & IW_ENCODE_DISABLED) || | ||
525 | ext->alg == IW_ENCODE_ALG_NONE) { | ||
526 | if (*crypt) | ||
527 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
528 | |||
529 | for (i = 0; i < WEP_KEYS; i++) | ||
530 | if (ieee->crypt[i] != NULL) | ||
531 | break; | ||
532 | |||
533 | if (i == WEP_KEYS) { | ||
534 | sec.enabled = 0; | ||
535 | sec.encrypt = 0; | ||
536 | sec.level = SEC_LEVEL_0; | ||
537 | sec.flags |= SEC_LEVEL; | ||
538 | } | ||
539 | goto done; | ||
540 | } | ||
541 | |||
542 | sec.enabled = 1; | ||
543 | sec.encrypt = 1; | ||
544 | |||
545 | if (!(ieee->host_encrypt || ieee->host_decrypt)) | ||
546 | goto skip_host_crypt; | ||
547 | |||
548 | switch (ext->alg) { | ||
549 | case IW_ENCODE_ALG_WEP: | ||
550 | alg = "WEP"; | ||
551 | module = "ieee80211_crypt_wep"; | ||
552 | break; | ||
553 | case IW_ENCODE_ALG_TKIP: | ||
554 | alg = "TKIP"; | ||
555 | module = "ieee80211_crypt_tkip"; | ||
556 | break; | ||
557 | case IW_ENCODE_ALG_CCMP: | ||
558 | alg = "CCMP"; | ||
559 | module = "ieee80211_crypt_ccmp"; | ||
560 | break; | ||
561 | default: | ||
562 | IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", | ||
563 | dev->name, ext->alg); | ||
564 | ret = -EINVAL; | ||
565 | goto done; | ||
566 | } | ||
567 | |||
568 | ops = ieee80211_get_crypto_ops(alg); | ||
569 | if (ops == NULL) { | ||
570 | request_module(module); | ||
571 | ops = ieee80211_get_crypto_ops(alg); | ||
572 | } | ||
573 | if (ops == NULL) { | ||
574 | IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", | ||
575 | dev->name, ext->alg); | ||
576 | ret = -EINVAL; | ||
577 | goto done; | ||
578 | } | ||
579 | |||
580 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
581 | struct ieee80211_crypt_data *new_crypt; | ||
582 | |||
583 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
584 | |||
585 | new_crypt = (struct ieee80211_crypt_data *) | ||
586 | kmalloc(sizeof(*new_crypt), GFP_KERNEL); | ||
587 | if (new_crypt == NULL) { | ||
588 | ret = -ENOMEM; | ||
589 | goto done; | ||
590 | } | ||
591 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
592 | new_crypt->ops = ops; | ||
593 | if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | ||
594 | new_crypt->priv = new_crypt->ops->init(ieee, idx); | ||
595 | if (new_crypt->priv == NULL) { | ||
596 | kfree(new_crypt); | ||
597 | ret = -EINVAL; | ||
598 | goto done; | ||
599 | } | ||
600 | *crypt = new_crypt; | ||
601 | } | ||
602 | |||
603 | if (ext->key_len > 0 && (*crypt)->ops->set_key && | ||
604 | (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, | ||
605 | (*crypt)->priv) < 0) { | ||
606 | IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); | ||
607 | ret = -EINVAL; | ||
608 | goto done; | ||
609 | } | ||
610 | |||
611 | skip_host_crypt: | ||
612 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
613 | ieee->tx_keyidx = idx; | ||
614 | sec.active_key = idx; | ||
615 | sec.flags |= SEC_ACTIVE_KEY; | ||
616 | } | ||
617 | |||
618 | if (ext->alg != IW_ENCODE_ALG_NONE) { | ||
619 | memcpy(sec.keys[idx], ext->key, ext->key_len); | ||
620 | sec.key_sizes[idx] = ext->key_len; | ||
621 | sec.flags |= (1 << idx); | ||
622 | if (ext->alg == IW_ENCODE_ALG_WEP) { | ||
623 | sec.encode_alg[idx] = SEC_ALG_WEP; | ||
624 | sec.flags |= SEC_LEVEL; | ||
625 | sec.level = SEC_LEVEL_1; | ||
626 | } else if (ext->alg == IW_ENCODE_ALG_TKIP) { | ||
627 | sec.encode_alg[idx] = SEC_ALG_TKIP; | ||
628 | sec.flags |= SEC_LEVEL; | ||
629 | sec.level = SEC_LEVEL_2; | ||
630 | } else if (ext->alg == IW_ENCODE_ALG_CCMP) { | ||
631 | sec.encode_alg[idx] = SEC_ALG_CCMP; | ||
632 | sec.flags |= SEC_LEVEL; | ||
633 | sec.level = SEC_LEVEL_3; | ||
634 | } | ||
635 | } | ||
636 | done: | ||
637 | if (ieee->set_security) | ||
638 | ieee->set_security(ieee->dev, &sec); | ||
639 | |||
640 | /* | ||
641 | * Do not reset port if card is in Managed mode since resetting will | ||
642 | * generate new IEEE 802.11 authentication which may end up in looping | ||
643 | * with IEEE 802.1X. If your hardware requires a reset after WEP | ||
644 | * configuration (for example... Prism2), implement the reset_port in | ||
645 | * the callbacks structures used to initialize the 802.11 stack. | ||
646 | */ | ||
647 | if (ieee->reset_on_keychange && | ||
648 | ieee->iw_mode != IW_MODE_INFRA && | ||
649 | ieee->reset_port && ieee->reset_port(dev)) { | ||
650 | IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); | ||
651 | return -EINVAL; | ||
652 | } | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, | ||
658 | struct iw_request_info *info, | ||
659 | union iwreq_data *wrqu, char *extra) | ||
660 | { | ||
661 | struct iw_point *encoding = &wrqu->encoding; | ||
662 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
663 | struct ieee80211_security *sec = &ieee->sec; | ||
664 | int idx, max_key_len; | ||
665 | |||
666 | max_key_len = encoding->length - sizeof(*ext); | ||
667 | if (max_key_len < 0) | ||
668 | return -EINVAL; | ||
669 | |||
670 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
671 | if (idx) { | ||
672 | if (idx < 1 || idx > WEP_KEYS) | ||
673 | return -EINVAL; | ||
674 | idx--; | ||
675 | } else | ||
676 | idx = ieee->tx_keyidx; | ||
677 | |||
678 | if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) | ||
679 | if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) | ||
680 | return -EINVAL; | ||
681 | |||
682 | encoding->flags = idx + 1; | ||
683 | memset(ext, 0, sizeof(*ext)); | ||
684 | |||
685 | if (!sec->enabled) { | ||
686 | ext->alg = IW_ENCODE_ALG_NONE; | ||
687 | ext->key_len = 0; | ||
688 | encoding->flags |= IW_ENCODE_DISABLED; | ||
689 | } else { | ||
690 | if (sec->encode_alg[idx] == SEC_ALG_WEP) | ||
691 | ext->alg = IW_ENCODE_ALG_WEP; | ||
692 | else if (sec->encode_alg[idx] == SEC_ALG_TKIP) | ||
693 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
694 | else if (sec->encode_alg[idx] == SEC_ALG_CCMP) | ||
695 | ext->alg = IW_ENCODE_ALG_CCMP; | ||
696 | else | ||
697 | return -EINVAL; | ||
698 | |||
699 | ext->key_len = sec->key_sizes[idx]; | ||
700 | memcpy(ext->key, sec->keys[idx], ext->key_len); | ||
701 | encoding->flags |= IW_ENCODE_ENABLED; | ||
702 | if (ext->key_len && | ||
703 | (ext->alg == IW_ENCODE_ALG_TKIP || | ||
704 | ext->alg == IW_ENCODE_ALG_CCMP)) | ||
705 | ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; | ||
706 | |||
707 | } | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | EXPORT_SYMBOL(ieee80211_wx_set_encodeext); | ||
713 | EXPORT_SYMBOL(ieee80211_wx_get_encodeext); | ||
714 | #endif | ||
715 | |||
494 | EXPORT_SYMBOL(ieee80211_wx_get_scan); | 716 | EXPORT_SYMBOL(ieee80211_wx_get_scan); |
495 | EXPORT_SYMBOL(ieee80211_wx_set_encode); | 717 | EXPORT_SYMBOL(ieee80211_wx_set_encode); |
496 | EXPORT_SYMBOL(ieee80211_wx_get_encode); | 718 | EXPORT_SYMBOL(ieee80211_wx_get_encode); |