aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00crypto.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-08-04 10:37:44 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-22 16:29:58 -0400
commit2bb057d07a0bc17475a7bf897fc41667ab08b73f (patch)
tree55461e52caa34a45a67aaf9e3f1c608f96c77d59 /drivers/net/wireless/rt2x00/rt2x00crypto.c
parent8e7cdbb6333ef7654e708bd60e50a123688dcd7b (diff)
rt2x00: Implement HW encryption
Various rt2x00 devices support hardware encryption. Most of them require the IV/EIV to be generated by mac80211, but require it to be provided seperately instead of within the frame itself. This means that rt2x00lib should extract the data from the frame and place it in the frame descriptor. During RX the IV/EIV is provided in the descriptor by the hardware which means that it should be inserted into the frame by rt2x00lib. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00crypto.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c215
1 files changed, 215 insertions, 0 deletions
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
32enum 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
49unsigned 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
72void 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
96void 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
121void 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}