diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r-- | drivers/net/wireless/rt2x00/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 39 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00crypto.c | 215 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00debug.c | 97 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 30 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00lib.h | 47 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 110 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 81 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 73 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00reg.h | 19 |
11 files changed, 686 insertions, 30 deletions
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index d485a86bba75..2f60e175f039 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig | |||
@@ -33,6 +33,10 @@ config RT2X00_LIB_FIRMWARE | |||
33 | depends on RT2X00_LIB | 33 | depends on RT2X00_LIB |
34 | select FW_LOADER | 34 | select FW_LOADER |
35 | 35 | ||
36 | config RT2X00_LIB_CRYPTO | ||
37 | boolean | ||
38 | depends on RT2X00_LIB | ||
39 | |||
36 | config RT2X00_LIB_RFKILL | 40 | config RT2X00_LIB_RFKILL |
37 | boolean | 41 | boolean |
38 | depends on RT2X00_LIB | 42 | depends on RT2X00_LIB |
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 1087dbcf1a04..917cb4f3b038 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile | |||
@@ -3,6 +3,7 @@ rt2x00lib-y += rt2x00mac.o | |||
3 | rt2x00lib-y += rt2x00config.o | 3 | rt2x00lib-y += rt2x00config.o |
4 | rt2x00lib-y += rt2x00queue.o | 4 | rt2x00lib-y += rt2x00queue.o |
5 | rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o | 5 | rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o |
6 | rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o | ||
6 | rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o | 7 | rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o |
7 | rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o | 8 | rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o |
8 | rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o | 9 | rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 82c28dcc471d..0ffd972bb856 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -452,6 +452,23 @@ struct rt2x00lib_erp { | |||
452 | }; | 452 | }; |
453 | 453 | ||
454 | /* | 454 | /* |
455 | * Configuration structure for hardware encryption. | ||
456 | */ | ||
457 | struct rt2x00lib_crypto { | ||
458 | enum cipher cipher; | ||
459 | |||
460 | enum set_key_cmd cmd; | ||
461 | const u8 *address; | ||
462 | |||
463 | u32 bssidx; | ||
464 | u32 aid; | ||
465 | |||
466 | u8 key[16]; | ||
467 | u8 tx_mic[8]; | ||
468 | u8 rx_mic[8]; | ||
469 | }; | ||
470 | |||
471 | /* | ||
455 | * Configuration structure wrapper around the | 472 | * Configuration structure wrapper around the |
456 | * rt2x00 interface configuration handler. | 473 | * rt2x00 interface configuration handler. |
457 | */ | 474 | */ |
@@ -547,6 +564,12 @@ struct rt2x00lib_ops { | |||
547 | /* | 564 | /* |
548 | * Configuration handlers. | 565 | * Configuration handlers. |
549 | */ | 566 | */ |
567 | int (*config_shared_key) (struct rt2x00_dev *rt2x00dev, | ||
568 | struct rt2x00lib_crypto *crypto, | ||
569 | struct ieee80211_key_conf *key); | ||
570 | int (*config_pairwise_key) (struct rt2x00_dev *rt2x00dev, | ||
571 | struct rt2x00lib_crypto *crypto, | ||
572 | struct ieee80211_key_conf *key); | ||
550 | void (*config_filter) (struct rt2x00_dev *rt2x00dev, | 573 | void (*config_filter) (struct rt2x00_dev *rt2x00dev, |
551 | const unsigned int filter_flags); | 574 | const unsigned int filter_flags); |
552 | void (*config_intf) (struct rt2x00_dev *rt2x00dev, | 575 | void (*config_intf) (struct rt2x00_dev *rt2x00dev, |
@@ -609,7 +632,7 @@ enum rt2x00_flags { | |||
609 | DEVICE_DIRTY_CONFIG, | 632 | DEVICE_DIRTY_CONFIG, |
610 | 633 | ||
611 | /* | 634 | /* |
612 | * Driver features | 635 | * Driver requirements |
613 | */ | 636 | */ |
614 | DRIVER_REQUIRE_FIRMWARE, | 637 | DRIVER_REQUIRE_FIRMWARE, |
615 | DRIVER_REQUIRE_BEACON_GUARD, | 638 | DRIVER_REQUIRE_BEACON_GUARD, |
@@ -618,9 +641,14 @@ enum rt2x00_flags { | |||
618 | DRIVER_REQUIRE_DMA, | 641 | DRIVER_REQUIRE_DMA, |
619 | 642 | ||
620 | /* | 643 | /* |
621 | * Driver configuration | 644 | * Driver features |
622 | */ | 645 | */ |
623 | CONFIG_SUPPORT_HW_BUTTON, | 646 | CONFIG_SUPPORT_HW_BUTTON, |
647 | CONFIG_SUPPORT_HW_CRYPTO, | ||
648 | |||
649 | /* | ||
650 | * Driver configuration | ||
651 | */ | ||
624 | CONFIG_FRAME_TYPE, | 652 | CONFIG_FRAME_TYPE, |
625 | CONFIG_RF_SEQUENCE, | 653 | CONFIG_RF_SEQUENCE, |
626 | CONFIG_EXTERNAL_LNA_A, | 654 | CONFIG_EXTERNAL_LNA_A, |
@@ -966,6 +994,13 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | |||
966 | unsigned int changed_flags, | 994 | unsigned int changed_flags, |
967 | unsigned int *total_flags, | 995 | unsigned int *total_flags, |
968 | int mc_count, struct dev_addr_list *mc_list); | 996 | int mc_count, struct dev_addr_list *mc_list); |
997 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
998 | int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
999 | const u8 *local_address, const u8 *address, | ||
1000 | struct ieee80211_key_conf *key); | ||
1001 | #else | ||
1002 | #define rt2x00mac_set_key NULL | ||
1003 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | ||
969 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | 1004 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, |
970 | struct ieee80211_low_level_stats *stats); | 1005 | struct ieee80211_low_level_stats *stats); |
971 | int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, | 1006 | int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c new file mode 100644 index 000000000000..e1448cfa9444 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | Copyright (C) 2004 - 2008 rt2x00 SourceForge Project | ||
3 | <http://rt2x00.serialmonkey.com> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the | ||
17 | Free Software Foundation, Inc., | ||
18 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | Module: rt2x00lib | ||
23 | Abstract: rt2x00 crypto specific routines. | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include "rt2x00.h" | ||
30 | #include "rt2x00lib.h" | ||
31 | |||
32 | enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) | ||
33 | { | ||
34 | switch (key->alg) { | ||
35 | case ALG_WEP: | ||
36 | if (key->keylen == LEN_WEP40) | ||
37 | return CIPHER_WEP64; | ||
38 | else | ||
39 | return CIPHER_WEP128; | ||
40 | case ALG_TKIP: | ||
41 | return CIPHER_TKIP; | ||
42 | case ALG_CCMP: | ||
43 | return CIPHER_AES; | ||
44 | default: | ||
45 | return CIPHER_NONE; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) | ||
50 | { | ||
51 | struct ieee80211_key_conf *key = tx_info->control.hw_key; | ||
52 | unsigned int overhead = 0; | ||
53 | |||
54 | /* | ||
55 | * Extend frame length to include IV/EIV/ICV/MMIC, | ||
56 | * note that these lengths should only be added when | ||
57 | * mac80211 does not generate it. | ||
58 | */ | ||
59 | overhead += tx_info->control.icv_len; | ||
60 | |||
61 | if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) | ||
62 | overhead += tx_info->control.iv_len; | ||
63 | |||
64 | if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { | ||
65 | if (key->alg == ALG_TKIP) | ||
66 | overhead += 8; | ||
67 | } | ||
68 | |||
69 | return overhead; | ||
70 | } | ||
71 | |||
72 | void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) | ||
73 | { | ||
74 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | ||
75 | unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); | ||
76 | |||
77 | if (unlikely(!iv_len)) | ||
78 | return; | ||
79 | |||
80 | /* Copy IV/EIV data */ | ||
81 | if (iv_len >= 4) | ||
82 | memcpy(&skbdesc->iv, skb->data + header_length, 4); | ||
83 | if (iv_len >= 8) | ||
84 | memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4); | ||
85 | |||
86 | /* Move ieee80211 header */ | ||
87 | memmove(skb->data + iv_len, skb->data, header_length); | ||
88 | |||
89 | /* Pull buffer to correct size */ | ||
90 | skb_pull(skb, iv_len); | ||
91 | |||
92 | /* IV/EIV data has officially be stripped */ | ||
93 | skbdesc->flags |= FRAME_DESC_IV_STRIPPED; | ||
94 | } | ||
95 | |||
96 | void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) | ||
97 | { | ||
98 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | ||
99 | unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); | ||
100 | const unsigned int iv_len = | ||
101 | ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4); | ||
102 | |||
103 | if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) | ||
104 | return; | ||
105 | |||
106 | skb_push(skb, iv_len); | ||
107 | |||
108 | /* Move ieee80211 header */ | ||
109 | memmove(skb->data, skb->data + iv_len, header_length); | ||
110 | |||
111 | /* Copy IV/EIV data */ | ||
112 | if (iv_len >= 4) | ||
113 | memcpy(skb->data + header_length, &skbdesc->iv, 4); | ||
114 | if (iv_len >= 8) | ||
115 | memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4); | ||
116 | |||
117 | /* IV/EIV data has returned into the frame */ | ||
118 | skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; | ||
119 | } | ||
120 | |||
121 | void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, | ||
122 | unsigned int header_length, | ||
123 | struct rxdone_entry_desc *rxdesc) | ||
124 | { | ||
125 | unsigned int payload_len = rxdesc->size - header_length; | ||
126 | unsigned int iv_len; | ||
127 | unsigned int icv_len; | ||
128 | unsigned int transfer = 0; | ||
129 | |||
130 | /* | ||
131 | * WEP64/WEP128: Provides IV & ICV | ||
132 | * TKIP: Provides IV/EIV & ICV | ||
133 | * AES: Provies IV/EIV & ICV | ||
134 | */ | ||
135 | switch (rxdesc->cipher) { | ||
136 | case CIPHER_WEP64: | ||
137 | case CIPHER_WEP128: | ||
138 | iv_len = 4; | ||
139 | icv_len = 4; | ||
140 | break; | ||
141 | case CIPHER_TKIP: | ||
142 | iv_len = 8; | ||
143 | icv_len = 4; | ||
144 | break; | ||
145 | case CIPHER_AES: | ||
146 | iv_len = 8; | ||
147 | icv_len = 8; | ||
148 | break; | ||
149 | default: | ||
150 | /* Unsupport type */ | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Make room for new data, note that we increase both | ||
156 | * headsize and tailsize when required. The tailsize is | ||
157 | * only needed when ICV data needs to be inserted and | ||
158 | * the padding is smaller then the ICV data. | ||
159 | * When alignment requirements is greater then the | ||
160 | * ICV data we must trim the skb to the correct size | ||
161 | * because we need to remove the extra bytes. | ||
162 | */ | ||
163 | skb_push(skb, iv_len + align); | ||
164 | if (align < icv_len) | ||
165 | skb_put(skb, icv_len - align); | ||
166 | else if (align > icv_len) | ||
167 | skb_trim(skb, rxdesc->size + iv_len + icv_len); | ||
168 | |||
169 | /* Move ieee80211 header */ | ||
170 | memmove(skb->data + transfer, | ||
171 | skb->data + transfer + iv_len + align, | ||
172 | header_length); | ||
173 | transfer += header_length; | ||
174 | |||
175 | /* Copy IV data */ | ||
176 | if (iv_len >= 4) { | ||
177 | memcpy(skb->data + transfer, &rxdesc->iv, 4); | ||
178 | transfer += 4; | ||
179 | } | ||
180 | |||
181 | /* Copy EIV data */ | ||
182 | if (iv_len >= 8) { | ||
183 | memcpy(skb->data + transfer, &rxdesc->eiv, 4); | ||
184 | transfer += 4; | ||
185 | } | ||
186 | |||
187 | /* Move payload */ | ||
188 | if (align) { | ||
189 | memmove(skb->data + transfer, | ||
190 | skb->data + transfer + align, | ||
191 | payload_len); | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * NOTE: Always count the payload as transfered, | ||
196 | * even when alignment was set to zero. This is required | ||
197 | * for determining the correct offset for the ICV data. | ||
198 | */ | ||
199 | transfer += payload_len; | ||
200 | |||
201 | /* Copy ICV data */ | ||
202 | if (icv_len >= 4) { | ||
203 | memcpy(skb->data + transfer, &rxdesc->icv, 4); | ||
204 | /* | ||
205 | * AES appends 8 bytes, we can't fill the upper | ||
206 | * 4 bytes, but mac80211 doesn't care about what | ||
207 | * we provide here anyway and strips it immediately. | ||
208 | */ | ||
209 | transfer += icv_len; | ||
210 | } | ||
211 | |||
212 | /* IV/EIV/ICV has been inserted into frame */ | ||
213 | rxdesc->size = transfer; | ||
214 | rxdesc->flags &= ~RX_FLAG_IV_STRIPPED; | ||
215 | } | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 6bee1d611bbf..5cf4c859e39d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -35,6 +35,13 @@ | |||
35 | 35 | ||
36 | #define MAX_LINE_LENGTH 64 | 36 | #define MAX_LINE_LENGTH 64 |
37 | 37 | ||
38 | struct rt2x00debug_crypto { | ||
39 | unsigned long success; | ||
40 | unsigned long icv_error; | ||
41 | unsigned long mic_error; | ||
42 | unsigned long key_error; | ||
43 | }; | ||
44 | |||
38 | struct rt2x00debug_intf { | 45 | struct rt2x00debug_intf { |
39 | /* | 46 | /* |
40 | * Pointer to driver structure where | 47 | * Pointer to driver structure where |
@@ -63,6 +70,7 @@ struct rt2x00debug_intf { | |||
63 | * - queue folder | 70 | * - queue folder |
64 | * - frame dump file | 71 | * - frame dump file |
65 | * - queue stats file | 72 | * - queue stats file |
73 | * - crypto stats file | ||
66 | */ | 74 | */ |
67 | struct dentry *driver_folder; | 75 | struct dentry *driver_folder; |
68 | struct dentry *driver_entry; | 76 | struct dentry *driver_entry; |
@@ -80,6 +88,7 @@ struct rt2x00debug_intf { | |||
80 | struct dentry *queue_folder; | 88 | struct dentry *queue_folder; |
81 | struct dentry *queue_frame_dump_entry; | 89 | struct dentry *queue_frame_dump_entry; |
82 | struct dentry *queue_stats_entry; | 90 | struct dentry *queue_stats_entry; |
91 | struct dentry *crypto_stats_entry; | ||
83 | 92 | ||
84 | /* | 93 | /* |
85 | * The frame dump file only allows a single reader, | 94 | * The frame dump file only allows a single reader, |
@@ -98,6 +107,12 @@ struct rt2x00debug_intf { | |||
98 | wait_queue_head_t frame_dump_waitqueue; | 107 | wait_queue_head_t frame_dump_waitqueue; |
99 | 108 | ||
100 | /* | 109 | /* |
110 | * HW crypto statistics. | ||
111 | * All statistics are stored seperately per cipher type. | ||
112 | */ | ||
113 | struct rt2x00debug_crypto crypto_stats[CIPHER_MAX]; | ||
114 | |||
115 | /* | ||
101 | * Driver and chipset files will use a data buffer | 116 | * Driver and chipset files will use a data buffer |
102 | * that has been created in advance. This will simplify | 117 | * that has been created in advance. This will simplify |
103 | * the code since we can use the debugfs functions. | 118 | * the code since we can use the debugfs functions. |
@@ -114,6 +129,25 @@ struct rt2x00debug_intf { | |||
114 | unsigned int offset_rf; | 129 | unsigned int offset_rf; |
115 | }; | 130 | }; |
116 | 131 | ||
132 | void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, | ||
133 | enum cipher cipher, enum rx_crypto status) | ||
134 | { | ||
135 | struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; | ||
136 | |||
137 | if (cipher == CIPHER_TKIP_NO_MIC) | ||
138 | cipher = CIPHER_TKIP; | ||
139 | if (cipher == CIPHER_NONE || cipher > CIPHER_MAX) | ||
140 | return; | ||
141 | |||
142 | /* Remove CIPHER_NONE index */ | ||
143 | cipher--; | ||
144 | |||
145 | intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS); | ||
146 | intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV); | ||
147 | intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC); | ||
148 | intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY); | ||
149 | } | ||
150 | |||
117 | void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, | 151 | void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, |
118 | enum rt2x00_dump_type type, struct sk_buff *skb) | 152 | enum rt2x00_dump_type type, struct sk_buff *skb) |
119 | { | 153 | { |
@@ -327,6 +361,59 @@ static const struct file_operations rt2x00debug_fop_queue_stats = { | |||
327 | .release = rt2x00debug_file_release, | 361 | .release = rt2x00debug_file_release, |
328 | }; | 362 | }; |
329 | 363 | ||
364 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
365 | static ssize_t rt2x00debug_read_crypto_stats(struct file *file, | ||
366 | char __user *buf, | ||
367 | size_t length, | ||
368 | loff_t *offset) | ||
369 | { | ||
370 | struct rt2x00debug_intf *intf = file->private_data; | ||
371 | char *name[] = { "WEP64", "WEP128", "TKIP", "AES" }; | ||
372 | char *data; | ||
373 | char *temp; | ||
374 | size_t size; | ||
375 | unsigned int i; | ||
376 | |||
377 | if (*offset) | ||
378 | return 0; | ||
379 | |||
380 | data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); | ||
381 | if (!data) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | temp = data; | ||
385 | temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n"); | ||
386 | |||
387 | for (i = 0; i < CIPHER_MAX; i++) { | ||
388 | temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i], | ||
389 | intf->crypto_stats[i].success, | ||
390 | intf->crypto_stats[i].icv_error, | ||
391 | intf->crypto_stats[i].mic_error, | ||
392 | intf->crypto_stats[i].key_error); | ||
393 | } | ||
394 | |||
395 | size = strlen(data); | ||
396 | size = min(size, length); | ||
397 | |||
398 | if (copy_to_user(buf, data, size)) { | ||
399 | kfree(data); | ||
400 | return -EFAULT; | ||
401 | } | ||
402 | |||
403 | kfree(data); | ||
404 | |||
405 | *offset += size; | ||
406 | return size; | ||
407 | } | ||
408 | |||
409 | static const struct file_operations rt2x00debug_fop_crypto_stats = { | ||
410 | .owner = THIS_MODULE, | ||
411 | .read = rt2x00debug_read_crypto_stats, | ||
412 | .open = rt2x00debug_file_open, | ||
413 | .release = rt2x00debug_file_release, | ||
414 | }; | ||
415 | #endif | ||
416 | |||
330 | #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ | 417 | #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ |
331 | static ssize_t rt2x00debug_read_##__name(struct file *file, \ | 418 | static ssize_t rt2x00debug_read_##__name(struct file *file, \ |
332 | char __user *buf, \ | 419 | char __user *buf, \ |
@@ -569,6 +656,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) | |||
569 | debugfs_create_file("queue", S_IRUSR, intf->queue_folder, | 656 | debugfs_create_file("queue", S_IRUSR, intf->queue_folder, |
570 | intf, &rt2x00debug_fop_queue_stats); | 657 | intf, &rt2x00debug_fop_queue_stats); |
571 | 658 | ||
659 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
660 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) | ||
661 | intf->crypto_stats_entry = | ||
662 | debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, | ||
663 | intf, &rt2x00debug_fop_crypto_stats); | ||
664 | #endif | ||
665 | |||
572 | return; | 666 | return; |
573 | 667 | ||
574 | exit: | 668 | exit: |
@@ -587,6 +681,9 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) | |||
587 | 681 | ||
588 | skb_queue_purge(&intf->frame_dump_skbqueue); | 682 | skb_queue_purge(&intf->frame_dump_skbqueue); |
589 | 683 | ||
684 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
685 | debugfs_remove(intf->crypto_stats_entry); | ||
686 | #endif | ||
590 | debugfs_remove(intf->queue_stats_entry); | 687 | debugfs_remove(intf->queue_stats_entry); |
591 | debugfs_remove(intf->queue_frame_dump_entry); | 688 | debugfs_remove(intf->queue_frame_dump_entry); |
592 | debugfs_remove(intf->queue_folder); | 689 | debugfs_remove(intf->queue_folder); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f42283ad7b02..182952249a19 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -508,6 +508,15 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
508 | rt2x00queue_unmap_skb(rt2x00dev, entry->skb); | 508 | rt2x00queue_unmap_skb(rt2x00dev, entry->skb); |
509 | 509 | ||
510 | /* | 510 | /* |
511 | * If the IV/EIV data was stripped from the frame before it was | ||
512 | * passed to the hardware, we should now reinsert it again because | ||
513 | * mac80211 will expect the the same data to be present it the | ||
514 | * frame as it was passed to us. | ||
515 | */ | ||
516 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) | ||
517 | rt2x00crypto_tx_insert_iv(entry->skb); | ||
518 | |||
519 | /* | ||
511 | * Send frame to debugfs immediately, after this call is completed | 520 | * Send frame to debugfs immediately, after this call is completed |
512 | * we are going to overwrite the skb->cb array. | 521 | * we are going to overwrite the skb->cb array. |
513 | */ | 522 | */ |
@@ -585,7 +594,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
585 | struct ieee80211_supported_band *sband; | 594 | struct ieee80211_supported_band *sband; |
586 | struct ieee80211_hdr *hdr; | 595 | struct ieee80211_hdr *hdr; |
587 | const struct rt2x00_rate *rate; | 596 | const struct rt2x00_rate *rate; |
588 | unsigned int header_size; | 597 | unsigned int header_length; |
589 | unsigned int align; | 598 | unsigned int align; |
590 | unsigned int i; | 599 | unsigned int i; |
591 | int idx = -1; | 600 | int idx = -1; |
@@ -613,10 +622,19 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
613 | * The data behind the ieee80211 header must be | 622 | * The data behind the ieee80211 header must be |
614 | * aligned on a 4 byte boundary. | 623 | * aligned on a 4 byte boundary. |
615 | */ | 624 | */ |
616 | header_size = ieee80211_get_hdrlen_from_skb(entry->skb); | 625 | header_length = ieee80211_get_hdrlen_from_skb(entry->skb); |
617 | align = ((unsigned long)(entry->skb->data + header_size)) & 3; | 626 | align = ((unsigned long)(entry->skb->data + header_length)) & 3; |
618 | 627 | ||
619 | if (align) { | 628 | /* |
629 | * Hardware might have stripped the IV/EIV/ICV data, | ||
630 | * in that case it is possible that the data was | ||
631 | * provided seperately (through hardware descriptor) | ||
632 | * in which case we should reinsert the data into the frame. | ||
633 | */ | ||
634 | if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { | ||
635 | rt2x00crypto_rx_insert_iv(entry->skb, align, | ||
636 | header_length, &rxdesc); | ||
637 | } else if (align) { | ||
620 | skb_push(entry->skb, align); | 638 | skb_push(entry->skb, align); |
621 | /* Move entire frame in 1 command */ | 639 | /* Move entire frame in 1 command */ |
622 | memmove(entry->skb->data, entry->skb->data + align, | 640 | memmove(entry->skb->data, entry->skb->data + align, |
@@ -657,6 +675,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
657 | (rxdesc.dev_flags & RXDONE_MY_BSS)) | 675 | (rxdesc.dev_flags & RXDONE_MY_BSS)) |
658 | rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi); | 676 | rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi); |
659 | 677 | ||
678 | rt2x00debug_update_crypto(rt2x00dev, | ||
679 | rxdesc.cipher, | ||
680 | rxdesc.cipher_status); | ||
681 | |||
660 | rt2x00dev->link.qual.rx_success++; | 682 | rt2x00dev->link.qual.rx_success++; |
661 | 683 | ||
662 | rx_status->mactime = rxdesc.timestamp; | 684 | rx_status->mactime = rxdesc.timestamp; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c5fb3a72cf37..7bbc16b1b6c6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -181,6 +181,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); | |||
181 | void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); | 181 | void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); |
182 | void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, | 182 | void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, |
183 | enum rt2x00_dump_type type, struct sk_buff *skb); | 183 | enum rt2x00_dump_type type, struct sk_buff *skb); |
184 | void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, | ||
185 | enum cipher cipher, enum rx_crypto status); | ||
184 | #else | 186 | #else |
185 | static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) | 187 | static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) |
186 | { | 188 | { |
@@ -195,9 +197,54 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, | |||
195 | struct sk_buff *skb) | 197 | struct sk_buff *skb) |
196 | { | 198 | { |
197 | } | 199 | } |
200 | |||
201 | static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, | ||
202 | enum cipher cipher, | ||
203 | enum rx_crypto status) | ||
204 | { | ||
205 | } | ||
198 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | 206 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
199 | 207 | ||
200 | /* | 208 | /* |
209 | * Crypto handlers. | ||
210 | */ | ||
211 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
212 | enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); | ||
213 | unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); | ||
214 | void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); | ||
215 | void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); | ||
216 | void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, | ||
217 | unsigned int header_length, | ||
218 | struct rxdone_entry_desc *rxdesc); | ||
219 | #else | ||
220 | static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) | ||
221 | { | ||
222 | return CIPHER_NONE; | ||
223 | } | ||
224 | |||
225 | static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) | ||
226 | { | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, | ||
231 | unsigned int iv_len) | ||
232 | { | ||
233 | } | ||
234 | |||
235 | static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) | ||
236 | { | ||
237 | } | ||
238 | |||
239 | static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, | ||
240 | unsigned int align, | ||
241 | unsigned int header_length, | ||
242 | struct rxdone_entry_desc *rxdesc) | ||
243 | { | ||
244 | } | ||
245 | #endif | ||
246 | |||
247 | /* | ||
201 | * RFkill handlers. | 248 | * RFkill handlers. |
202 | */ | 249 | */ |
203 | #ifdef CONFIG_RT2X00_LIB_RFKILL | 250 | #ifdef CONFIG_RT2X00_LIB_RFKILL |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4b9fde903cd6..3af427339417 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -36,22 +36,22 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
36 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); | 36 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); |
37 | struct ieee80211_tx_info *rts_info; | 37 | struct ieee80211_tx_info *rts_info; |
38 | struct sk_buff *skb; | 38 | struct sk_buff *skb; |
39 | int size; | 39 | unsigned int data_length; |
40 | int retval = 0; | 40 | int retval = 0; |
41 | 41 | ||
42 | if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) | 42 | if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) |
43 | size = sizeof(struct ieee80211_cts); | 43 | data_length = sizeof(struct ieee80211_cts); |
44 | else | 44 | else |
45 | size = sizeof(struct ieee80211_rts); | 45 | data_length = sizeof(struct ieee80211_rts); |
46 | 46 | ||
47 | skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); | 47 | skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom); |
48 | if (unlikely(!skb)) { | 48 | if (unlikely(!skb)) { |
49 | WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); | 49 | WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); |
50 | return -ENOMEM; | 50 | return -ENOMEM; |
51 | } | 51 | } |
52 | 52 | ||
53 | skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); | 53 | skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); |
54 | skb_put(skb, size); | 54 | skb_put(skb, data_length); |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Copy TX information over from original frame to | 57 | * Copy TX information over from original frame to |
@@ -64,7 +64,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
64 | */ | 64 | */ |
65 | memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); | 65 | memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); |
66 | rts_info = IEEE80211_SKB_CB(skb); | 66 | rts_info = IEEE80211_SKB_CB(skb); |
67 | rts_info->control.hw_key = NULL; | ||
68 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; | 67 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; |
69 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; | 68 | rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; |
70 | rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; | 69 | rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; |
@@ -74,13 +73,24 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
74 | else | 73 | else |
75 | rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; | 74 | rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; |
76 | 75 | ||
76 | skb->do_not_encrypt = 1; | ||
77 | |||
78 | /* | ||
79 | * RTS/CTS frame should use the length of the frame plus any | ||
80 | * encryption overhead that will be added by the hardware. | ||
81 | */ | ||
82 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
83 | if (!frag_skb->do_not_encrypt) | ||
84 | data_length += rt2x00crypto_tx_overhead(tx_info); | ||
85 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | ||
86 | |||
77 | if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) | 87 | if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) |
78 | ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, | 88 | ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, |
79 | frag_skb->data, size, tx_info, | 89 | frag_skb->data, data_length, tx_info, |
80 | (struct ieee80211_cts *)(skb->data)); | 90 | (struct ieee80211_cts *)(skb->data)); |
81 | else | 91 | else |
82 | ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, | 92 | ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, |
83 | frag_skb->data, size, tx_info, | 93 | frag_skb->data, data_length, tx_info, |
84 | (struct ieee80211_rts *)(skb->data)); | 94 | (struct ieee80211_rts *)(skb->data)); |
85 | 95 | ||
86 | retval = rt2x00queue_write_tx_frame(queue, skb); | 96 | retval = rt2x00queue_write_tx_frame(queue, skb); |
@@ -464,6 +474,90 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | |||
464 | } | 474 | } |
465 | EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); | 475 | EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); |
466 | 476 | ||
477 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
478 | int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
479 | const u8 *local_address, const u8 *address, | ||
480 | struct ieee80211_key_conf *key) | ||
481 | { | ||
482 | struct rt2x00_dev *rt2x00dev = hw->priv; | ||
483 | int (*set_key) (struct rt2x00_dev *rt2x00dev, | ||
484 | struct rt2x00lib_crypto *crypto, | ||
485 | struct ieee80211_key_conf *key); | ||
486 | struct rt2x00lib_crypto crypto; | ||
487 | |||
488 | if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) | ||
489 | return -EOPNOTSUPP; | ||
490 | else if (key->keylen > 32) | ||
491 | return -ENOSPC; | ||
492 | |||
493 | memset(&crypto, 0, sizeof(crypto)); | ||
494 | |||
495 | /* | ||
496 | * When in STA mode, bssidx is always 0 otherwise local_address[5] | ||
497 | * contains the bss number, see BSS_ID_MASK comments for details. | ||
498 | */ | ||
499 | if (rt2x00dev->intf_sta_count) | ||
500 | crypto.bssidx = 0; | ||
501 | else | ||
502 | crypto.bssidx = | ||
503 | local_address[5] & (rt2x00dev->ops->max_ap_intf - 1); | ||
504 | |||
505 | crypto.cipher = rt2x00crypto_key_to_cipher(key); | ||
506 | if (crypto.cipher == CIPHER_NONE) | ||
507 | return -EOPNOTSUPP; | ||
508 | |||
509 | crypto.cmd = cmd; | ||
510 | crypto.address = address; | ||
511 | |||
512 | if (crypto.cipher == CIPHER_TKIP) { | ||
513 | if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY) | ||
514 | memcpy(&crypto.key, | ||
515 | &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY], | ||
516 | sizeof(crypto.key)); | ||
517 | |||
518 | if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) | ||
519 | memcpy(&crypto.tx_mic, | ||
520 | &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], | ||
521 | sizeof(crypto.tx_mic)); | ||
522 | |||
523 | if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY) | ||
524 | memcpy(&crypto.rx_mic, | ||
525 | &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], | ||
526 | sizeof(crypto.rx_mic)); | ||
527 | } else | ||
528 | memcpy(&crypto.key, &key->key[0], key->keylen); | ||
529 | |||
530 | /* | ||
531 | * Each BSS has a maximum of 4 shared keys. | ||
532 | * Shared key index values: | ||
533 | * 0) BSS0 key0 | ||
534 | * 1) BSS0 key1 | ||
535 | * ... | ||
536 | * 4) BSS1 key0 | ||
537 | * ... | ||
538 | * 8) BSS2 key0 | ||
539 | * ... | ||
540 | * Both pairwise as shared key indeces are determined by | ||
541 | * driver. This is required because the hardware requires | ||
542 | * keys to be assigned in correct order (When key 1 is | ||
543 | * provided but key 0 is not, then the key is not found | ||
544 | * by the hardware during RX). | ||
545 | */ | ||
546 | key->hw_key_idx = 0; | ||
547 | |||
548 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
549 | set_key = rt2x00dev->ops->lib->config_pairwise_key; | ||
550 | else | ||
551 | set_key = rt2x00dev->ops->lib->config_shared_key; | ||
552 | |||
553 | if (!set_key) | ||
554 | return -EOPNOTSUPP; | ||
555 | |||
556 | return set_key(rt2x00dev, &crypto, key); | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(rt2x00mac_set_key); | ||
559 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | ||
560 | |||
467 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | 561 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, |
468 | struct ieee80211_low_level_stats *stats) | 562 | struct ieee80211_low_level_stats *stats) |
469 | { | 563 | { |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 898cdd7f57d9..c0f97c53e5ce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -33,10 +33,11 @@ | |||
33 | struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, | 33 | struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, |
34 | struct queue_entry *entry) | 34 | struct queue_entry *entry) |
35 | { | 35 | { |
36 | unsigned int frame_size; | ||
37 | unsigned int reserved_size; | ||
38 | struct sk_buff *skb; | 36 | struct sk_buff *skb; |
39 | struct skb_frame_desc *skbdesc; | 37 | struct skb_frame_desc *skbdesc; |
38 | unsigned int frame_size; | ||
39 | unsigned int head_size = 0; | ||
40 | unsigned int tail_size = 0; | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * The frame size includes descriptor size, because the | 43 | * The frame size includes descriptor size, because the |
@@ -49,16 +50,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, | |||
49 | * this means we need at least 3 bytes for moving the frame | 50 | * this means we need at least 3 bytes for moving the frame |
50 | * into the correct offset. | 51 | * into the correct offset. |
51 | */ | 52 | */ |
52 | reserved_size = 4; | 53 | head_size = 4; |
54 | |||
55 | /* | ||
56 | * For IV/EIV/ICV assembly we must make sure there is | ||
57 | * at least 8 bytes bytes available in headroom for IV/EIV | ||
58 | * and 4 bytes for ICV data as tailroon. | ||
59 | */ | ||
60 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
61 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { | ||
62 | head_size += 8; | ||
63 | tail_size += 4; | ||
64 | } | ||
65 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | ||
53 | 66 | ||
54 | /* | 67 | /* |
55 | * Allocate skbuffer. | 68 | * Allocate skbuffer. |
56 | */ | 69 | */ |
57 | skb = dev_alloc_skb(frame_size + reserved_size); | 70 | skb = dev_alloc_skb(frame_size + head_size + tail_size); |
58 | if (!skb) | 71 | if (!skb) |
59 | return NULL; | 72 | return NULL; |
60 | 73 | ||
61 | skb_reserve(skb, reserved_size); | 74 | /* |
75 | * Make sure we not have a frame with the requested bytes | ||
76 | * available in the head and tail. | ||
77 | */ | ||
78 | skb_reserve(skb, head_size); | ||
62 | skb_put(skb, frame_size); | 79 | skb_put(skb, frame_size); |
63 | 80 | ||
64 | /* | 81 | /* |
@@ -140,7 +157,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
140 | txdesc->cw_max = entry->queue->cw_max; | 157 | txdesc->cw_max = entry->queue->cw_max; |
141 | txdesc->aifs = entry->queue->aifs; | 158 | txdesc->aifs = entry->queue->aifs; |
142 | 159 | ||
143 | /* Data length should be extended with 4 bytes for CRC */ | 160 | /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ |
144 | data_length = entry->skb->len + 4; | 161 | data_length = entry->skb->len + 4; |
145 | 162 | ||
146 | /* | 163 | /* |
@@ -149,6 +166,35 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
149 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) | 166 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) |
150 | __set_bit(ENTRY_TXD_ACK, &txdesc->flags); | 167 | __set_bit(ENTRY_TXD_ACK, &txdesc->flags); |
151 | 168 | ||
169 | #ifdef CONFIG_RT2X00_LIB_CRYPTO | ||
170 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) && | ||
171 | !entry->skb->do_not_encrypt) { | ||
172 | struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; | ||
173 | |||
174 | __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); | ||
175 | |||
176 | txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); | ||
177 | |||
178 | if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
179 | __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); | ||
180 | |||
181 | txdesc->key_idx = hw_key->hw_key_idx; | ||
182 | txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); | ||
183 | |||
184 | /* | ||
185 | * Extend frame length to include all encryption overhead | ||
186 | * that will be added by the hardware. | ||
187 | */ | ||
188 | data_length += rt2x00crypto_tx_overhead(tx_info); | ||
189 | |||
190 | if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) | ||
191 | __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); | ||
192 | |||
193 | if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) | ||
194 | __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); | ||
195 | } | ||
196 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | ||
197 | |||
152 | /* | 198 | /* |
153 | * Check if this is a RTS/CTS frame | 199 | * Check if this is a RTS/CTS frame |
154 | */ | 200 | */ |
@@ -305,6 +351,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | |||
305 | struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); | 351 | struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); |
306 | struct txentry_desc txdesc; | 352 | struct txentry_desc txdesc; |
307 | struct skb_frame_desc *skbdesc; | 353 | struct skb_frame_desc *skbdesc; |
354 | unsigned int iv_len = IEEE80211_SKB_CB(skb)->control.iv_len; | ||
308 | 355 | ||
309 | if (unlikely(rt2x00queue_full(queue))) | 356 | if (unlikely(rt2x00queue_full(queue))) |
310 | return -EINVAL; | 357 | return -EINVAL; |
@@ -326,15 +373,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | |||
326 | rt2x00queue_create_tx_descriptor(entry, &txdesc); | 373 | rt2x00queue_create_tx_descriptor(entry, &txdesc); |
327 | 374 | ||
328 | /* | 375 | /* |
329 | * skb->cb array is now ours and we are free to use it. | 376 | * All information is retreived from the skb->cb array, |
377 | * now we should claim ownership of the driver part of that | ||
378 | * array. | ||
330 | */ | 379 | */ |
331 | skbdesc = get_skb_frame_desc(entry->skb); | 380 | skbdesc = get_skb_frame_desc(entry->skb); |
332 | memset(skbdesc, 0, sizeof(*skbdesc)); | 381 | memset(skbdesc, 0, sizeof(*skbdesc)); |
333 | skbdesc->entry = entry; | 382 | skbdesc->entry = entry; |
334 | 383 | ||
384 | /* | ||
385 | * When hardware encryption is supported, and this frame | ||
386 | * is to be encrypted, we should strip the IV/EIV data from | ||
387 | * the frame so we can provide it to the driver seperately. | ||
388 | */ | ||
389 | if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && | ||
390 | !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) | ||
391 | rt2x00crypto_tx_remove_iv(skb, iv_len); | ||
392 | |||
393 | /* | ||
394 | * It could be possible that the queue was corrupted and this | ||
395 | * call failed. Just drop the frame, we cannot rollback and pass | ||
396 | * the frame to mac80211 because the skb->cb has now been tainted. | ||
397 | */ | ||
335 | if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { | 398 | if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { |
336 | __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); | 399 | __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); |
337 | return -EIO; | 400 | dev_kfree_skb_any(entry->skb); |
401 | entry->skb = NULL; | ||
402 | return 0; | ||
338 | } | 403 | } |
339 | 404 | ||
340 | if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) | 405 | if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index ff78e52ce43c..37f3f98d58a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -87,10 +87,13 @@ enum data_queue_qid { | |||
87 | * | 87 | * |
88 | * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX | 88 | * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX |
89 | * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX | 89 | * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX |
90 | * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by | ||
91 | * mac80211 but was stripped for processing by the driver. | ||
90 | */ | 92 | */ |
91 | enum skb_frame_desc_flags { | 93 | enum skb_frame_desc_flags { |
92 | SKBDESC_DMA_MAPPED_RX = (1 << 0), | 94 | SKBDESC_DMA_MAPPED_RX = 1 << 0, |
93 | SKBDESC_DMA_MAPPED_TX = (1 << 1), | 95 | SKBDESC_DMA_MAPPED_TX = 1 << 1, |
96 | FRAME_DESC_IV_STRIPPED = 1 << 2, | ||
94 | }; | 97 | }; |
95 | 98 | ||
96 | /** | 99 | /** |
@@ -104,6 +107,8 @@ enum skb_frame_desc_flags { | |||
104 | * @desc: Pointer to descriptor part of the frame. | 107 | * @desc: Pointer to descriptor part of the frame. |
105 | * Note that this pointer could point to something outside | 108 | * Note that this pointer could point to something outside |
106 | * of the scope of the skb->data pointer. | 109 | * of the scope of the skb->data pointer. |
110 | * @iv: IV data used during encryption/decryption. | ||
111 | * @eiv: EIV data used during encryption/decryption. | ||
107 | * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. | 112 | * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. |
108 | * @entry: The entry to which this sk buffer belongs. | 113 | * @entry: The entry to which this sk buffer belongs. |
109 | */ | 114 | */ |
@@ -113,6 +118,9 @@ struct skb_frame_desc { | |||
113 | unsigned int desc_len; | 118 | unsigned int desc_len; |
114 | void *desc; | 119 | void *desc; |
115 | 120 | ||
121 | __le32 iv; | ||
122 | __le32 eiv; | ||
123 | |||
116 | dma_addr_t skb_dma; | 124 | dma_addr_t skb_dma; |
117 | 125 | ||
118 | struct queue_entry *entry; | 126 | struct queue_entry *entry; |
@@ -152,7 +160,11 @@ enum rxdone_entry_desc_flags { | |||
152 | * @size: Data size of the received frame. | 160 | * @size: Data size of the received frame. |
153 | * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). | 161 | * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). |
154 | * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). | 162 | * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). |
155 | 163 | * @cipher: Cipher type used during decryption. | |
164 | * @cipher_status: Decryption status. | ||
165 | * @iv: IV data used during decryption. | ||
166 | * @eiv: EIV data used during decryption. | ||
167 | * @icv: ICV data used during decryption. | ||
156 | */ | 168 | */ |
157 | struct rxdone_entry_desc { | 169 | struct rxdone_entry_desc { |
158 | u64 timestamp; | 170 | u64 timestamp; |
@@ -161,6 +173,12 @@ struct rxdone_entry_desc { | |||
161 | int size; | 173 | int size; |
162 | int flags; | 174 | int flags; |
163 | int dev_flags; | 175 | int dev_flags; |
176 | u8 cipher; | ||
177 | u8 cipher_status; | ||
178 | |||
179 | __le32 iv; | ||
180 | __le32 eiv; | ||
181 | __le32 icv; | ||
164 | }; | 182 | }; |
165 | 183 | ||
166 | /** | 184 | /** |
@@ -206,6 +224,10 @@ struct txdone_entry_desc { | |||
206 | * @ENTRY_TXD_BURST: This frame belongs to the same burst event. | 224 | * @ENTRY_TXD_BURST: This frame belongs to the same burst event. |
207 | * @ENTRY_TXD_ACK: An ACK is required for this frame. | 225 | * @ENTRY_TXD_ACK: An ACK is required for this frame. |
208 | * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. | 226 | * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. |
227 | * @ENTRY_TXD_ENCRYPT: This frame should be encrypted. | ||
228 | * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared). | ||
229 | * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware. | ||
230 | * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware. | ||
209 | */ | 231 | */ |
210 | enum txentry_desc_flags { | 232 | enum txentry_desc_flags { |
211 | ENTRY_TXD_RTS_FRAME, | 233 | ENTRY_TXD_RTS_FRAME, |
@@ -218,6 +240,10 @@ enum txentry_desc_flags { | |||
218 | ENTRY_TXD_BURST, | 240 | ENTRY_TXD_BURST, |
219 | ENTRY_TXD_ACK, | 241 | ENTRY_TXD_ACK, |
220 | ENTRY_TXD_RETRY_MODE, | 242 | ENTRY_TXD_RETRY_MODE, |
243 | ENTRY_TXD_ENCRYPT, | ||
244 | ENTRY_TXD_ENCRYPT_PAIRWISE, | ||
245 | ENTRY_TXD_ENCRYPT_IV, | ||
246 | ENTRY_TXD_ENCRYPT_MMIC, | ||
221 | }; | 247 | }; |
222 | 248 | ||
223 | /** | 249 | /** |
@@ -236,6 +262,9 @@ enum txentry_desc_flags { | |||
236 | * @ifs: IFS value. | 262 | * @ifs: IFS value. |
237 | * @cw_min: cwmin value. | 263 | * @cw_min: cwmin value. |
238 | * @cw_max: cwmax value. | 264 | * @cw_max: cwmax value. |
265 | * @cipher: Cipher type used for encryption. | ||
266 | * @key_idx: Key index used for encryption. | ||
267 | * @iv_offset: Position where IV should be inserted by hardware. | ||
239 | */ | 268 | */ |
240 | struct txentry_desc { | 269 | struct txentry_desc { |
241 | unsigned long flags; | 270 | unsigned long flags; |
@@ -252,6 +281,10 @@ struct txentry_desc { | |||
252 | short ifs; | 281 | short ifs; |
253 | short cw_min; | 282 | short cw_min; |
254 | short cw_max; | 283 | short cw_max; |
284 | |||
285 | enum cipher cipher; | ||
286 | u16 key_idx; | ||
287 | u16 iv_offset; | ||
255 | }; | 288 | }; |
256 | 289 | ||
257 | /** | 290 | /** |
@@ -484,25 +517,51 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) | |||
484 | } | 517 | } |
485 | 518 | ||
486 | /** | 519 | /** |
487 | * rt2x00_desc_read - Read a word from the hardware descriptor. | 520 | * _rt2x00_desc_read - Read a word from the hardware descriptor. |
521 | * @desc: Base descriptor address | ||
522 | * @word: Word index from where the descriptor should be read. | ||
523 | * @value: Address where the descriptor value should be written into. | ||
524 | */ | ||
525 | static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) | ||
526 | { | ||
527 | *value = desc[word]; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * rt2x00_desc_read - Read a word from the hardware descriptor, this | ||
532 | * function will take care of the byte ordering. | ||
488 | * @desc: Base descriptor address | 533 | * @desc: Base descriptor address |
489 | * @word: Word index from where the descriptor should be read. | 534 | * @word: Word index from where the descriptor should be read. |
490 | * @value: Address where the descriptor value should be written into. | 535 | * @value: Address where the descriptor value should be written into. |
491 | */ | 536 | */ |
492 | static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) | 537 | static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) |
493 | { | 538 | { |
494 | *value = le32_to_cpu(desc[word]); | 539 | __le32 tmp; |
540 | _rt2x00_desc_read(desc, word, &tmp); | ||
541 | *value = le32_to_cpu(tmp); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * rt2x00_desc_write - write a word to the hardware descriptor, this | ||
546 | * function will take care of the byte ordering. | ||
547 | * @desc: Base descriptor address | ||
548 | * @word: Word index from where the descriptor should be written. | ||
549 | * @value: Value that should be written into the descriptor. | ||
550 | */ | ||
551 | static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value) | ||
552 | { | ||
553 | desc[word] = value; | ||
495 | } | 554 | } |
496 | 555 | ||
497 | /** | 556 | /** |
498 | * rt2x00_desc_write - wrote a word to the hardware descriptor. | 557 | * rt2x00_desc_write - write a word to the hardware descriptor. |
499 | * @desc: Base descriptor address | 558 | * @desc: Base descriptor address |
500 | * @word: Word index from where the descriptor should be written. | 559 | * @word: Word index from where the descriptor should be written. |
501 | * @value: Value that should be written into the descriptor. | 560 | * @value: Value that should be written into the descriptor. |
502 | */ | 561 | */ |
503 | static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value) | 562 | static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value) |
504 | { | 563 | { |
505 | desc[word] = cpu_to_le32(value); | 564 | _rt2x00_desc_write(desc, word, cpu_to_le32(value)); |
506 | } | 565 | } |
507 | 566 | ||
508 | #endif /* RT2X00QUEUE_H */ | 567 | #endif /* RT2X00QUEUE_H */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7e88ce5651b9..6d5acf99a1c5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h | |||
@@ -27,6 +27,16 @@ | |||
27 | #define RT2X00REG_H | 27 | #define RT2X00REG_H |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * RX crypto status | ||
31 | */ | ||
32 | enum rx_crypto { | ||
33 | RX_CRYPTO_SUCCESS = 0, | ||
34 | RX_CRYPTO_FAIL_ICV = 1, | ||
35 | RX_CRYPTO_FAIL_MIC = 2, | ||
36 | RX_CRYPTO_FAIL_KEY = 3, | ||
37 | }; | ||
38 | |||
39 | /* | ||
30 | * Antenna values | 40 | * Antenna values |
31 | */ | 41 | */ |
32 | enum antenna { | 42 | enum antenna { |
@@ -104,7 +114,14 @@ enum cipher { | |||
104 | */ | 114 | */ |
105 | CIPHER_CKIP64 = 5, | 115 | CIPHER_CKIP64 = 5, |
106 | CIPHER_CKIP128 = 6, | 116 | CIPHER_CKIP128 = 6, |
107 | CIPHER_TKIP_NO_MIC = 7, | 117 | CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */ |
118 | |||
119 | /* | ||
120 | * Max cipher type. | ||
121 | * Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128 | ||
122 | * are excluded due to limitations in mac80211. | ||
123 | */ | ||
124 | CIPHER_MAX = 4, | ||
108 | }; | 125 | }; |
109 | 126 | ||
110 | /* | 127 | /* |