1
2
3
4
5
6
7
8#include <crypto/arc4.h>
9#include <linux/fips.h>
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/slab.h>
13#include <linux/random.h>
14#include <linux/skbuff.h>
15#include <linux/string.h>
16#include "rtllib.h"
17
18#include <linux/crc32.h>
19
20struct prism2_wep_data {
21 u32 iv;
22#define WEP_KEY_LEN 13
23 u8 key[WEP_KEY_LEN + 1];
24 u8 key_len;
25 u8 key_idx;
26 struct arc4_ctx rx_ctx_arc4;
27 struct arc4_ctx tx_ctx_arc4;
28};
29
30
31static void *prism2_wep_init(int keyidx)
32{
33 struct prism2_wep_data *priv;
34
35 if (fips_enabled)
36 return NULL;
37
38 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
39 if (priv == NULL)
40 return NULL;
41 priv->key_idx = keyidx;
42
43
44 get_random_bytes(&priv->iv, 4);
45
46 return priv;
47}
48
49
50static void prism2_wep_deinit(void *priv)
51{
52 kfree_sensitive(priv);
53}
54
55
56
57
58
59
60
61static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
62{
63 struct prism2_wep_data *wep = priv;
64 u32 klen, len;
65 u8 key[WEP_KEY_LEN + 3];
66 u8 *pos;
67 struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
68 MAX_DEV_ADDR_SIZE);
69 u32 crc;
70 u8 *icv;
71
72 if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
73 skb->len < hdr_len){
74 pr_err("Error!!! headroom=%d tailroom=%d skblen=%d hdr_len=%d\n",
75 skb_headroom(skb), skb_tailroom(skb), skb->len, hdr_len);
76 return -1;
77 }
78 len = skb->len - hdr_len;
79 pos = skb_push(skb, 4);
80 memmove(pos, pos + 4, hdr_len);
81 pos += hdr_len;
82
83 klen = 3 + wep->key_len;
84
85 wep->iv++;
86
87
88
89
90
91 if ((wep->iv & 0xff00) == 0xff00) {
92 u8 B = (wep->iv >> 16) & 0xff;
93
94 if (B >= 3 && B < klen)
95 wep->iv += 0x0100;
96 }
97
98
99 *pos++ = key[0] = (wep->iv >> 16) & 0xff;
100 *pos++ = key[1] = (wep->iv >> 8) & 0xff;
101 *pos++ = key[2] = wep->iv & 0xff;
102 *pos++ = wep->key_idx << 6;
103
104
105 memcpy(key + 3, wep->key, wep->key_len);
106
107 if (!tcb_desc->bHwSec) {
108
109 crc = ~crc32_le(~0, pos, len);
110 icv = skb_put(skb, 4);
111 icv[0] = crc;
112 icv[1] = crc >> 8;
113 icv[2] = crc >> 16;
114 icv[3] = crc >> 24;
115
116 arc4_setkey(&wep->tx_ctx_arc4, key, klen);
117 arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4);
118 }
119
120 return 0;
121}
122
123
124
125
126
127
128
129
130
131static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
132{
133 struct prism2_wep_data *wep = priv;
134 u32 klen, plen;
135 u8 key[WEP_KEY_LEN + 3];
136 u8 keyidx, *pos;
137 struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
138 MAX_DEV_ADDR_SIZE);
139 u32 crc;
140 u8 icv[4];
141
142 if (skb->len < hdr_len + 8)
143 return -1;
144
145 pos = skb->data + hdr_len;
146 key[0] = *pos++;
147 key[1] = *pos++;
148 key[2] = *pos++;
149 keyidx = *pos++ >> 6;
150 if (keyidx != wep->key_idx)
151 return -1;
152
153 klen = 3 + wep->key_len;
154
155
156 memcpy(key + 3, wep->key, wep->key_len);
157
158
159 plen = skb->len - hdr_len - 8;
160
161 if (!tcb_desc->bHwSec) {
162 arc4_setkey(&wep->rx_ctx_arc4, key, klen);
163 arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4);
164
165 crc = ~crc32_le(~0, pos, plen);
166 icv[0] = crc;
167 icv[1] = crc >> 8;
168 icv[2] = crc >> 16;
169 icv[3] = crc >> 24;
170 if (memcmp(icv, pos + plen, 4) != 0) {
171
172 return -2;
173 }
174 }
175
176 memmove(skb->data + 4, skb->data, hdr_len);
177 skb_pull(skb, 4);
178 skb_trim(skb, skb->len - 4);
179
180 return 0;
181}
182
183
184static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
185{
186 struct prism2_wep_data *wep = priv;
187
188 if (len < 0 || len > WEP_KEY_LEN)
189 return -1;
190
191 memcpy(wep->key, key, len);
192 wep->key_len = len;
193
194 return 0;
195}
196
197
198static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
199{
200 struct prism2_wep_data *wep = priv;
201
202 if (len < wep->key_len)
203 return -1;
204
205 memcpy(key, wep->key, wep->key_len);
206
207 return wep->key_len;
208}
209
210
211static void prism2_wep_print_stats(struct seq_file *m, void *priv)
212{
213 struct prism2_wep_data *wep = priv;
214
215 seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
216}
217
218static struct lib80211_crypto_ops rtllib_crypt_wep = {
219 .name = "R-WEP",
220 .init = prism2_wep_init,
221 .deinit = prism2_wep_deinit,
222 .encrypt_mpdu = prism2_wep_encrypt,
223 .decrypt_mpdu = prism2_wep_decrypt,
224 .encrypt_msdu = NULL,
225 .decrypt_msdu = NULL,
226 .set_key = prism2_wep_set_key,
227 .get_key = prism2_wep_get_key,
228 .print_stats = prism2_wep_print_stats,
229 .extra_mpdu_prefix_len = 4,
230 .extra_mpdu_postfix_len = 4,
231 .owner = THIS_MODULE,
232};
233
234
235static int __init rtllib_crypto_wep_init(void)
236{
237 return lib80211_register_crypto_ops(&rtllib_crypt_wep);
238}
239
240
241static void __exit rtllib_crypto_wep_exit(void)
242{
243 lib80211_unregister_crypto_ops(&rtllib_crypt_wep);
244}
245
246module_init(rtllib_crypto_wep_init);
247module_exit(rtllib_crypto_wep_exit);
248
249MODULE_LICENSE("GPL");
250