xref: /dragonfly/sys/dev/netif/ath/ath_hal/ar5212/ar5212_keycache.c (revision 572ff6f6e8b95055988f178b6ba12ce77bb5b3c2)
1 /*
2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * $FreeBSD$
18  */
19 #include "opt_ah.h"
20 
21 #include "ah.h"
22 #include "ah_internal.h"
23 
24 #include "ar5212/ar5212.h"
25 #include "ar5212/ar5212reg.h"
26 #include "ar5212/ar5212desc.h"
27 
28 /*
29  * Note: The key cache hardware requires that each double-word
30  * pair be written in even/odd order (since the destination is
31  * a 64-bit register).  Don't reorder the writes in this code
32  * w/o considering this!
33  */
34 #define   KEY_XOR                       0xaa
35 
36 #define   IS_MIC_ENABLED(ah) \
37           (AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
38 
39 /*
40  * Return the size of the hardware key cache.
41  */
42 uint32_t
ar5212GetKeyCacheSize(struct ath_hal * ah)43 ar5212GetKeyCacheSize(struct ath_hal *ah)
44 {
45           return AH_PRIVATE(ah)->ah_caps.halKeyCacheSize;
46 }
47 
48 /*
49  * Return true if the specific key cache entry is valid.
50  */
51 HAL_BOOL
ar5212IsKeyCacheEntryValid(struct ath_hal * ah,uint16_t entry)52 ar5212IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry)
53 {
54           if (entry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
55                     uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
56                     if (val & AR_KEYTABLE_VALID)
57                               return AH_TRUE;
58           }
59           return AH_FALSE;
60 }
61 
62 /*
63  * Clear the specified key cache entry and any associated MIC entry.
64  */
65 HAL_BOOL
ar5212ResetKeyCacheEntry(struct ath_hal * ah,uint16_t entry)66 ar5212ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry)
67 {
68           uint32_t keyType;
69 
70           if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
71                     HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
72                         __func__, entry);
73                     return AH_FALSE;
74           }
75           keyType = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));
76 
77           /* XXX why not clear key type/valid bit first? */
78           OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
79           OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
80           OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
81           OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
82           OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
83           OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
84           OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
85           OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
86           if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {
87                     uint16_t micentry = entry+64; /* MIC goes at slot+64 */
88 
89                     HALASSERT(micentry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize);
90                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
91                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
92                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
93                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
94                     /* NB: key type and MAC are known to be ok */
95           }
96           return AH_TRUE;
97 }
98 
99 /*
100  * Sets the mac part of the specified key cache entry (and any
101  * associated MIC entry) and mark them valid.
102  *
103  * Since mac[0] is shifted off and not presented to the hardware,
104  * it does double duty as a "don't use for unicast, use for multicast
105  * matching" flag. This interface should later be extended to
106  * explicitly do that rather than overloading a bit in the MAC
107  * address.
108  */
109 HAL_BOOL
ar5212SetKeyCacheEntryMac(struct ath_hal * ah,uint16_t entry,const uint8_t * mac)110 ar5212SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac)
111 {
112           uint32_t macHi, macLo;
113           uint32_t unicast_flag = AR_KEYTABLE_VALID;
114 
115           if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
116                     HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
117                         __func__, entry);
118                     return AH_FALSE;
119           }
120           /*
121            * Set MAC address -- shifted right by 1.  MacLo is
122            * the 4 MSBs, and MacHi is the 2 LSBs.
123            */
124           if (mac != AH_NULL) {
125                     /*
126                      * AR_KEYTABLE_VALID indicates that the address is a unicast
127                      * address, which must match the transmitter address for
128                      * decrypting frames.
129                      * Not setting this bit allows the hardware to use the key
130                      * for multicast frame decryption.
131                      */
132                     if (mac[0] & 0x01)
133                               unicast_flag = 0;
134 
135                     macHi = (mac[5] << 8) | mac[4];
136                     macLo = (mac[3] << 24)| (mac[2] << 16)
137                           | (mac[1] << 8) | mac[0];
138                     macLo >>= 1;
139                     macLo |= (macHi & 1) << 31;   /* carry */
140                     macHi >>= 1;
141           } else {
142                     macLo = macHi = 0;
143           }
144           OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
145           OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
146           return AH_TRUE;
147 }
148 
149 /*
150  * Sets the contents of the specified key cache entry
151  * and any associated MIC entry.
152  */
153 HAL_BOOL
ar5212SetKeyCacheEntry(struct ath_hal * ah,uint16_t entry,const HAL_KEYVAL * k,const uint8_t * mac,int xorKey)154 ar5212SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry,
155                        const HAL_KEYVAL *k, const uint8_t *mac,
156                        int xorKey)
157 {
158           struct ath_hal_5212 *ahp = AH5212(ah);
159           const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
160           uint32_t key0, key1, key2, key3, key4;
161           uint32_t keyType;
162           uint32_t xorMask = xorKey ?
163                     (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0;
164 
165           if (entry >= pCap->halKeyCacheSize) {
166                     HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
167                         __func__, entry);
168                     return AH_FALSE;
169           }
170           switch (k->kv_type) {
171           case HAL_CIPHER_AES_OCB:
172                     keyType = AR_KEYTABLE_TYPE_AES;
173                     break;
174           case HAL_CIPHER_AES_CCM:
175                     if (!pCap->halCipherAesCcmSupport) {
176                               HALDEBUG(ah, HAL_DEBUG_ANY,
177                                   "%s: AES-CCM not supported by mac rev 0x%x\n",
178                                   __func__, AH_PRIVATE(ah)->ah_macRev);
179                               return AH_FALSE;
180                     }
181                     keyType = AR_KEYTABLE_TYPE_CCM;
182                     break;
183           case HAL_CIPHER_TKIP:
184                     keyType = AR_KEYTABLE_TYPE_TKIP;
185                     if (IS_MIC_ENABLED(ah) && entry+64 >= pCap->halKeyCacheSize) {
186                               HALDEBUG(ah, HAL_DEBUG_ANY,
187                                   "%s: entry %u inappropriate for TKIP\n",
188                                   __func__, entry);
189                               return AH_FALSE;
190                     }
191                     break;
192           case HAL_CIPHER_WEP:
193                     if (k->kv_len < 40 / NBBY) {
194                               HALDEBUG(ah, HAL_DEBUG_ANY,
195                                   "%s: WEP key length %u too small\n",
196                                   __func__, k->kv_len);
197                               return AH_FALSE;
198                     }
199                     if (k->kv_len <= 40 / NBBY)
200                               keyType = AR_KEYTABLE_TYPE_40;
201                     else if (k->kv_len <= 104 / NBBY)
202                               keyType = AR_KEYTABLE_TYPE_104;
203                     else
204                               keyType = AR_KEYTABLE_TYPE_128;
205                     break;
206           case HAL_CIPHER_CLR:
207                     keyType = AR_KEYTABLE_TYPE_CLR;
208                     break;
209           default:
210                     HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n",
211                         __func__, k->kv_type);
212                     return AH_FALSE;
213           }
214 
215           key0 = LE_READ_4(k->kv_val+0) ^ xorMask;
216           key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff;
217           key2 = LE_READ_4(k->kv_val+6) ^ xorMask;
218           key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff;
219           key4 = LE_READ_4(k->kv_val+12) ^ xorMask;
220           if (k->kv_len <= 104 / NBBY)
221                     key4 &= 0xff;
222 
223           /*
224            * Note: key cache hardware requires that each double-word
225            * pair be written in even/odd order (since the destination is
226            * a 64-bit register).  Don't reorder these writes w/o
227            * considering this!
228            */
229           if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {
230                     uint16_t micentry = entry+64; /* MIC goes at slot+64 */
231                     uint32_t mic0, mic1, mic2, mic3, mic4;
232 
233                     /*
234                      * Invalidate the encrypt/decrypt key until the MIC
235                      * key is installed so pending rx frames will fail
236                      * with decrypt errors rather than a MIC error.
237                      */
238                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
239                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
240                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
241                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
242                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
243                     OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
244                     (void) ar5212SetKeyCacheEntryMac(ah, entry, mac);
245 
246 
247                     /*
248                      * Write MIC entry according to new or old key layout.
249                      * The MISC_MODE register is assumed already set so
250                      * these writes will be handled properly (happens on
251                      * attach and at every reset).
252                      */
253                     /* RX mic */
254                     mic0 = LE_READ_4(k->kv_mic+0);
255                     mic2 = LE_READ_4(k->kv_mic+4);
256                     if (ahp->ah_miscMode & AR_MISC_MODE_MIC_NEW_LOC_ENABLE) {
257                               /*
258                                * Both RX and TX mic values can be combined into
259                                * one cache slot entry:
260                                *  8*N + 800         31:0    RX Michael key 0
261                                *  8*N + 804         15:0    TX Michael key 0 [31:16]
262                                *  8*N + 808         31:0    RX Michael key 1
263                                *  8*N + 80C         15:0    TX Michael key 0 [15:0]
264                                *  8*N + 810         31:0    TX Michael key 1
265                                *  8*N + 814         15:0    reserved
266                                *  8*N + 818         31:0    reserved
267                                *  8*N + 81C         14:0    reserved
268                                *                    15      key valid == 0
269                                */
270                               /* TX mic */
271                               mic1 = LE_READ_2(k->kv_txmic+2) & 0xffff;
272                               mic3 = LE_READ_2(k->kv_txmic+0) & 0xffff;
273                               mic4 = LE_READ_4(k->kv_txmic+4);
274                     } else {
275                               mic1 = mic3 = mic4 = 0;
276                     }
277                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
278                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
279                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
280                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
281                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
282                     OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
283                               AR_KEYTABLE_TYPE_CLR);
284                     /* NB: MIC key is not marked valid and has no MAC address */
285                     OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
286                     OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
287 
288                     /* correct intentionally corrupted key */
289                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
290                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
291           } else {
292                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
293                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
294                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
295                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
296                     OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
297                     OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
298 
299                     (void) ar5212SetKeyCacheEntryMac(ah, entry, mac);
300           }
301           return AH_TRUE;
302 }
303