diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 6 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 57 | ||||
-rw-r--r-- | net/wireless/util.c | 45 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 257 |
5 files changed, 330 insertions, 41 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 15b2a1794805..47c20eb0c04d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the linux wireless configuration interface. | 2 | * This is the linux wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
457 | "symlink to netdev!\n"); | 457 | "symlink to netdev!\n"); |
458 | } | 458 | } |
459 | dev->ieee80211_ptr->netdev = dev; | 459 | dev->ieee80211_ptr->netdev = dev; |
460 | #ifdef CONFIG_WIRELESS_EXT | ||
461 | dev->ieee80211_ptr->wext.default_key = -1; | ||
462 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | ||
463 | #endif | ||
460 | mutex_unlock(&rdev->devlist_mtx); | 464 | mutex_unlock(&rdev->devlist_mtx); |
461 | break; | 465 | break; |
462 | case NETDEV_GOING_DOWN: | 466 | case NETDEV_GOING_DOWN: |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 3e49d3399311..f14b6c5f4221 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Wireless configuration interface internals. | 2 | * Wireless configuration interface internals. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #ifndef __NET_WIRELESS_CORE_H | 6 | #ifndef __NET_WIRELESS_CORE_H |
7 | #define __NET_WIRELESS_CORE_H | 7 | #define __NET_WIRELESS_CORE_H |
@@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | |||
151 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 151 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
152 | struct net_device *dev, bool nowext); | 152 | struct net_device *dev, bool nowext); |
153 | 153 | ||
154 | /* internal helpers */ | ||
155 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | ||
156 | const u8 *mac_addr); | ||
157 | |||
154 | #endif /* __NET_WIRELESS_CORE_H */ | 158 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a39e4644778b..f88dbbec7521 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the new netlink-based wireless configuration interface. | 2 | * This is the new netlink-based wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -1073,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | err = func(&drv->wiphy, dev, key_idx); | 1075 | err = func(&drv->wiphy, dev, key_idx); |
1076 | #ifdef CONFIG_WIRELESS_EXT | ||
1077 | if (!err) { | ||
1078 | if (func == drv->ops->set_default_key) | ||
1079 | dev->ieee80211_ptr->wext.default_key = key_idx; | ||
1080 | else | ||
1081 | dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; | ||
1082 | } | ||
1083 | #endif | ||
1076 | 1084 | ||
1077 | out: | 1085 | out: |
1078 | cfg80211_put_dev(drv); | 1086 | cfg80211_put_dev(drv); |
@@ -1111,45 +1119,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1111 | if (info->attrs[NL80211_ATTR_MAC]) | 1119 | if (info->attrs[NL80211_ATTR_MAC]) |
1112 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1120 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1113 | 1121 | ||
1114 | if (key_idx > 5) | 1122 | if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) |
1115 | return -EINVAL; | 1123 | return -EINVAL; |
1116 | 1124 | ||
1117 | /* | ||
1118 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
1119 | * (because current deployments use pairwise WEP keys with | ||
1120 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
1121 | */ | ||
1122 | if (mac_addr && key_idx && | ||
1123 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
1124 | params.cipher != WLAN_CIPHER_SUITE_WEP104) | ||
1125 | return -EINVAL; | ||
1126 | |||
1127 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
1128 | switch (params.cipher) { | ||
1129 | case WLAN_CIPHER_SUITE_WEP40: | ||
1130 | if (params.key_len != 5) | ||
1131 | return -EINVAL; | ||
1132 | break; | ||
1133 | case WLAN_CIPHER_SUITE_TKIP: | ||
1134 | if (params.key_len != 32) | ||
1135 | return -EINVAL; | ||
1136 | break; | ||
1137 | case WLAN_CIPHER_SUITE_CCMP: | ||
1138 | if (params.key_len != 16) | ||
1139 | return -EINVAL; | ||
1140 | break; | ||
1141 | case WLAN_CIPHER_SUITE_WEP104: | ||
1142 | if (params.key_len != 13) | ||
1143 | return -EINVAL; | ||
1144 | break; | ||
1145 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1146 | if (params.key_len != 16) | ||
1147 | return -EINVAL; | ||
1148 | break; | ||
1149 | default: | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1153 | rtnl_lock(); | 1125 | rtnl_lock(); |
1154 | 1126 | ||
1155 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1127 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -1210,6 +1182,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1210 | 1182 | ||
1211 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 1183 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
1212 | 1184 | ||
1185 | #ifdef CONFIG_WIRELESS_EXT | ||
1186 | if (!err) { | ||
1187 | if (key_idx == dev->ieee80211_ptr->wext.default_key) | ||
1188 | dev->ieee80211_ptr->wext.default_key = -1; | ||
1189 | else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) | ||
1190 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | ||
1191 | } | ||
1192 | #endif | ||
1193 | |||
1213 | out: | 1194 | out: |
1214 | cfg80211_put_dev(drv); | 1195 | cfg80211_put_dev(drv); |
1215 | dev_put(dev); | 1196 | dev_put(dev); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5f7e997195c7..beb226e78cd7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
138 | if (wiphy->bands[band]) | 138 | if (wiphy->bands[band]) |
139 | set_mandatory_flags_band(wiphy->bands[band], band); | 139 | set_mandatory_flags_band(wiphy->bands[band], band); |
140 | } | 140 | } |
141 | |||
142 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | ||
143 | const u8 *mac_addr) | ||
144 | { | ||
145 | if (key_idx > 5) | ||
146 | return -EINVAL; | ||
147 | |||
148 | /* | ||
149 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
150 | * (because current deployments use pairwise WEP keys with | ||
151 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
152 | */ | ||
153 | if (mac_addr && key_idx && | ||
154 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
155 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | ||
156 | return -EINVAL; | ||
157 | |||
158 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
159 | switch (params->cipher) { | ||
160 | case WLAN_CIPHER_SUITE_WEP40: | ||
161 | if (params->key_len != 5) | ||
162 | return -EINVAL; | ||
163 | break; | ||
164 | case WLAN_CIPHER_SUITE_TKIP: | ||
165 | if (params->key_len != 32) | ||
166 | return -EINVAL; | ||
167 | break; | ||
168 | case WLAN_CIPHER_SUITE_CCMP: | ||
169 | if (params->key_len != 16) | ||
170 | return -EINVAL; | ||
171 | break; | ||
172 | case WLAN_CIPHER_SUITE_WEP104: | ||
173 | if (params->key_len != 13) | ||
174 | return -EINVAL; | ||
175 | break; | ||
176 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
177 | if (params->key_len != 16) | ||
178 | return -EINVAL; | ||
179 | break; | ||
180 | default: | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index abf6b0a047d8..ffc98a8d6e5c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -5,12 +5,13 @@ | |||
5 | * into cfg80211, when that happens all the exports here go away and | 5 | * into cfg80211, when that happens all the exports here go away and |
6 | * we directly assign the wireless handlers of wireless interfaces. | 6 | * we directly assign the wireless handlers of wireless interfaces. |
7 | * | 7 | * |
8 | * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> | 8 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/wireless.h> | 11 | #include <linux/wireless.h> |
12 | #include <linux/nl80211.h> | 12 | #include <linux/nl80211.h> |
13 | #include <linux/if_arp.h> | 13 | #include <linux/if_arp.h> |
14 | #include <linux/etherdevice.h> | ||
14 | #include <net/iw_handler.h> | 15 | #include <net/iw_handler.h> |
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
16 | #include "core.h" | 17 | #include "core.h" |
@@ -477,3 +478,257 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
477 | return 0; | 478 | return 0; |
478 | } | 479 | } |
479 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 480 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
481 | |||
482 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | ||
483 | struct net_device *dev, const u8 *addr, | ||
484 | bool remove, bool tx_key, int idx, | ||
485 | struct key_params *params) | ||
486 | { | ||
487 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
488 | int err; | ||
489 | |||
490 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | ||
491 | if (!rdev->ops->set_default_mgmt_key) | ||
492 | return -EOPNOTSUPP; | ||
493 | |||
494 | if (idx < 4 || idx > 5) | ||
495 | return -EINVAL; | ||
496 | } else if (idx < 0 || idx > 3) | ||
497 | return -EINVAL; | ||
498 | |||
499 | if (remove) { | ||
500 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | ||
501 | if (!err) { | ||
502 | if (idx == wdev->wext.default_key) | ||
503 | wdev->wext.default_key = -1; | ||
504 | else if (idx == wdev->wext.default_mgmt_key) | ||
505 | wdev->wext.default_mgmt_key = -1; | ||
506 | } | ||
507 | return err; | ||
508 | } else { | ||
509 | if (addr) | ||
510 | tx_key = false; | ||
511 | |||
512 | if (cfg80211_validate_key_settings(params, idx, addr)) | ||
513 | return -EINVAL; | ||
514 | |||
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | ||
516 | if (err) | ||
517 | return err; | ||
518 | |||
519 | if (tx_key || (!addr && wdev->wext.default_key == -1)) { | ||
520 | err = rdev->ops->set_default_key(&rdev->wiphy, | ||
521 | dev, idx); | ||
522 | if (!err) | ||
523 | wdev->wext.default_key = idx; | ||
524 | return err; | ||
525 | } | ||
526 | |||
527 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && | ||
528 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { | ||
529 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | ||
530 | dev, idx); | ||
531 | if (!err) | ||
532 | wdev->wext.default_mgmt_key = idx; | ||
533 | return err; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | int cfg80211_wext_siwencode(struct net_device *dev, | ||
541 | struct iw_request_info *info, | ||
542 | struct iw_point *erq, char *keybuf) | ||
543 | { | ||
544 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
545 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
546 | int idx, err; | ||
547 | bool remove = false; | ||
548 | struct key_params params; | ||
549 | |||
550 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | ||
551 | if (!rdev->ops->del_key || | ||
552 | !rdev->ops->add_key || | ||
553 | !rdev->ops->set_default_key) | ||
554 | return -EOPNOTSUPP; | ||
555 | |||
556 | idx = erq->flags & IW_ENCODE_INDEX; | ||
557 | if (idx == 0) { | ||
558 | idx = wdev->wext.default_key; | ||
559 | if (idx < 0) | ||
560 | idx = 0; | ||
561 | } else if (idx < 1 || idx > 4) | ||
562 | return -EINVAL; | ||
563 | else | ||
564 | idx--; | ||
565 | |||
566 | if (erq->flags & IW_ENCODE_DISABLED) | ||
567 | remove = true; | ||
568 | else if (erq->length == 0) { | ||
569 | /* No key data - just set the default TX key index */ | ||
570 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); | ||
571 | if (!err) | ||
572 | wdev->wext.default_key = idx; | ||
573 | return err; | ||
574 | } | ||
575 | |||
576 | memset(¶ms, 0, sizeof(params)); | ||
577 | params.key = keybuf; | ||
578 | params.key_len = erq->length; | ||
579 | if (erq->length == 5) | ||
580 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | ||
581 | else if (erq->length == 13) | ||
582 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | ||
583 | else if (!remove) | ||
584 | return -EINVAL; | ||
585 | |||
586 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | ||
587 | wdev->wext.default_key == -1, | ||
588 | idx, ¶ms); | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); | ||
591 | |||
592 | int cfg80211_wext_siwencodeext(struct net_device *dev, | ||
593 | struct iw_request_info *info, | ||
594 | struct iw_point *erq, char *extra) | ||
595 | { | ||
596 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
598 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
599 | const u8 *addr; | ||
600 | int idx; | ||
601 | bool remove = false; | ||
602 | struct key_params params; | ||
603 | u32 cipher; | ||
604 | |||
605 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | ||
606 | if (!rdev->ops->del_key || | ||
607 | !rdev->ops->add_key || | ||
608 | !rdev->ops->set_default_key) | ||
609 | return -EOPNOTSUPP; | ||
610 | |||
611 | switch (ext->alg) { | ||
612 | case IW_ENCODE_ALG_NONE: | ||
613 | remove = true; | ||
614 | cipher = 0; | ||
615 | break; | ||
616 | case IW_ENCODE_ALG_WEP: | ||
617 | if (ext->key_len == 5) | ||
618 | cipher = WLAN_CIPHER_SUITE_WEP40; | ||
619 | else if (ext->key_len == 13) | ||
620 | cipher = WLAN_CIPHER_SUITE_WEP104; | ||
621 | else | ||
622 | return -EINVAL; | ||
623 | break; | ||
624 | case IW_ENCODE_ALG_TKIP: | ||
625 | cipher = WLAN_CIPHER_SUITE_TKIP; | ||
626 | break; | ||
627 | case IW_ENCODE_ALG_CCMP: | ||
628 | cipher = WLAN_CIPHER_SUITE_CCMP; | ||
629 | break; | ||
630 | case IW_ENCODE_ALG_AES_CMAC: | ||
631 | cipher = WLAN_CIPHER_SUITE_AES_CMAC; | ||
632 | break; | ||
633 | default: | ||
634 | return -EOPNOTSUPP; | ||
635 | } | ||
636 | |||
637 | if (erq->flags & IW_ENCODE_DISABLED) | ||
638 | remove = true; | ||
639 | |||
640 | idx = erq->flags & IW_ENCODE_INDEX; | ||
641 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | ||
642 | if (idx < 4 || idx > 5) { | ||
643 | idx = wdev->wext.default_mgmt_key; | ||
644 | if (idx < 0) | ||
645 | return -EINVAL; | ||
646 | } else | ||
647 | idx--; | ||
648 | } else { | ||
649 | if (idx < 1 || idx > 4) { | ||
650 | idx = wdev->wext.default_key; | ||
651 | if (idx < 0) | ||
652 | return -EINVAL; | ||
653 | } else | ||
654 | idx--; | ||
655 | } | ||
656 | |||
657 | addr = ext->addr.sa_data; | ||
658 | if (is_broadcast_ether_addr(addr)) | ||
659 | addr = NULL; | ||
660 | |||
661 | memset(¶ms, 0, sizeof(params)); | ||
662 | params.key = ext->key; | ||
663 | params.key_len = ext->key_len; | ||
664 | params.cipher = cipher; | ||
665 | |||
666 | return cfg80211_set_encryption( | ||
667 | rdev, dev, addr, remove, | ||
668 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | ||
669 | idx, ¶ms); | ||
670 | } | ||
671 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); | ||
672 | |||
673 | struct giwencode_cookie { | ||
674 | size_t buflen; | ||
675 | char *keybuf; | ||
676 | }; | ||
677 | |||
678 | static void giwencode_get_key_cb(void *cookie, struct key_params *params) | ||
679 | { | ||
680 | struct giwencode_cookie *data = cookie; | ||
681 | |||
682 | if (!params->key) { | ||
683 | data->buflen = 0; | ||
684 | return; | ||
685 | } | ||
686 | |||
687 | data->buflen = min_t(size_t, data->buflen, params->key_len); | ||
688 | memcpy(data->keybuf, params->key, data->buflen); | ||
689 | } | ||
690 | |||
691 | int cfg80211_wext_giwencode(struct net_device *dev, | ||
692 | struct iw_request_info *info, | ||
693 | struct iw_point *erq, char *keybuf) | ||
694 | { | ||
695 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
696 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
697 | int idx, err; | ||
698 | struct giwencode_cookie data = { | ||
699 | .keybuf = keybuf, | ||
700 | .buflen = erq->length, | ||
701 | }; | ||
702 | |||
703 | if (!rdev->ops->get_key) | ||
704 | return -EOPNOTSUPP; | ||
705 | |||
706 | idx = erq->flags & IW_ENCODE_INDEX; | ||
707 | if (idx == 0) { | ||
708 | idx = wdev->wext.default_key; | ||
709 | if (idx < 0) | ||
710 | idx = 0; | ||
711 | } else if (idx < 1 || idx > 4) | ||
712 | return -EINVAL; | ||
713 | else | ||
714 | idx--; | ||
715 | |||
716 | erq->flags = idx + 1; | ||
717 | |||
718 | err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, | ||
719 | giwencode_get_key_cb); | ||
720 | if (!err) { | ||
721 | erq->length = data.buflen; | ||
722 | erq->flags |= IW_ENCODE_ENABLED; | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | if (err == -ENOENT) { | ||
727 | erq->flags |= IW_ENCODE_DISABLED; | ||
728 | erq->length = 0; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | return err; | ||
733 | } | ||
734 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | ||