Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
  3 * All rights reserved.
  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 along
 16 * with this program; if not, write to the Free Software Foundation, Inc.,
 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 18 *
 19 *
 20 * File: key.c
 21 *
 22 * Purpose: Implement functions for 802.11i Key management
 23 *
 24 * Author: Jerry Chen
 25 *
 26 * Date: May 29, 2003
 27 *
 28 * Functions:
 29 *      KeyvInitTable - Init Key management table
 30 *      KeybGetKey - Get Key from table
 31 *      KeybSetKey - Set Key to table
 32 *      KeybRemoveKey - Remove Key from table
 33 *      KeybGetTransmitKey - Get Transmit Key from table
 34 *
 35 * Revision History:
 36 *
 37 */
 38
 39#include "tmacro.h"
 40#include "key.h"
 41#include "mac.h"
 42#include "rndis.h"
 43#include "control.h"
 44
 45/*---------------------  Static Definitions -------------------------*/
 46
 47/*---------------------  Static Classes  ----------------------------*/
 48
 49/*---------------------  Static Variables  --------------------------*/
 50static int          msglevel                =MSG_LEVEL_INFO;
 51//static int          msglevel                =MSG_LEVEL_DEBUG;
 52/*---------------------  Static Functions  --------------------------*/
 53
 54/*---------------------  Export Variables  --------------------------*/
 55
 56/*---------------------  Static Definitions -------------------------*/
 57
 58/*---------------------  Static Classes  ----------------------------*/
 59
 60/*---------------------  Static Variables  --------------------------*/
 61
 62/*---------------------  Static Functions  --------------------------*/
 63static void s_vCheckKeyTableValid(void *pDeviceHandler,
 64				  PSKeyManagement pTable)
 65{
 66    PSDevice    pDevice = (PSDevice) pDeviceHandler;
 67    int         i;
 68    WORD        wLength = 0;
 69    BYTE        pbyData[MAX_KEY_TABLE];
 70
 71    for (i=0;i<MAX_KEY_TABLE;i++) {
 72        if ((pTable->KeyTable[i].bInUse == TRUE) &&
 73            (pTable->KeyTable[i].PairwiseKey.bKeyValid == FALSE) &&
 74            (pTable->KeyTable[i].GroupKey[0].bKeyValid == FALSE) &&
 75            (pTable->KeyTable[i].GroupKey[1].bKeyValid == FALSE) &&
 76            (pTable->KeyTable[i].GroupKey[2].bKeyValid == FALSE) &&
 77            (pTable->KeyTable[i].GroupKey[3].bKeyValid == FALSE)
 78            ) {
 79
 80            pTable->KeyTable[i].bInUse = FALSE;
 81            pTable->KeyTable[i].wKeyCtl = 0;
 82            pTable->KeyTable[i].bSoftWEP = FALSE;
 83            pbyData[wLength++] = (BYTE) i;
 84            //MACvDisableKeyEntry(pDevice, i);
 85        }
 86    }
 87    if ( wLength != 0 ) {
 88        CONTROLnsRequestOut(pDevice,
 89                            MESSAGE_TYPE_CLRKEYENTRY,
 90                            0,
 91                            0,
 92                            wLength,
 93                            pbyData
 94                            );
 95    }
 96
 97}
 98
 99
100/*---------------------  Export Functions  --------------------------*/
101
102
103/*
104 * Description: Init Key management table
105 *
106 * Parameters:
107 *  In:
108 *      pTable          - Pointer to Key table
109 *  Out:
110 *      none
111 *
112 * Return Value: none
113 *
114 */
115void KeyvInitTable(void *pDeviceHandler, PSKeyManagement pTable)
116{
117    PSDevice    pDevice = (PSDevice) pDeviceHandler;
118    int i;
119    int jj;
120    BYTE       pbyData[MAX_KEY_TABLE+1];
121
122    spin_lock_irq(&pDevice->lock);
123    for (i=0;i<MAX_KEY_TABLE;i++) {
124        pTable->KeyTable[i].bInUse = FALSE;
125        pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
126	pTable->KeyTable[i].PairwiseKey.pvKeyTable =
127	  (void *)&pTable->KeyTable[i];
128        for (jj=0; jj < MAX_GROUP_KEY; jj++) {
129            pTable->KeyTable[i].GroupKey[jj].bKeyValid = FALSE;
130	    pTable->KeyTable[i].GroupKey[jj].pvKeyTable =
131	      (void *) &(pTable->KeyTable[i]);
132        }
133        pTable->KeyTable[i].wKeyCtl = 0;
134        pTable->KeyTable[i].dwGTKeyIndex = 0;
135        pTable->KeyTable[i].bSoftWEP = FALSE;
136        pbyData[i] = (BYTE) i;
137    }
138    pbyData[i] = (BYTE) i;
139    CONTROLnsRequestOut(pDevice,
140                        MESSAGE_TYPE_CLRKEYENTRY,
141                        0,
142                        0,
143                        11,
144                        pbyData
145                        );
146
147    spin_unlock_irq(&pDevice->lock);
148
149    return;
150}
151
152
153/*
154 * Description: Get Key from table
155 *
156 * Parameters:
157 *  In:
158 *      pTable          - Pointer to Key table
159 *      pbyBSSID        - BSSID of Key
160 *      dwKeyIndex      - Key Index (0xFFFFFFFF means pairwise key)
161 *  Out:
162 *      pKey            - Key return
163 *
164 * Return Value: TRUE if found otherwise FALSE
165 *
166 */
167BOOL KeybGetKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyIndex,
168		PSKeyItem *pKey)
169{
170    int i;
171
172    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetKey() \n");
173
174    *pKey = NULL;
175    for (i=0;i<MAX_KEY_TABLE;i++) {
176        if ((pTable->KeyTable[i].bInUse == TRUE) &&
177	    !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
178            if (dwKeyIndex == 0xFFFFFFFF) {
179                if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) {
180                    *pKey = &(pTable->KeyTable[i].PairwiseKey);
181                    return (TRUE);
182                }
183                else {
184                    return (FALSE);
185                }
186            } else if (dwKeyIndex < MAX_GROUP_KEY) {
187                if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == TRUE) {
188                    *pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex]);
189                    return (TRUE);
190                }
191                else {
192                    return (FALSE);
193                }
194            }
195            else {
196                return (FALSE);
197            }
198        }
199    }
200    return (FALSE);
201}
202
203
204/*
205 * Description: Set Key to table
206 *
207 * Parameters:
208 *  In:
209 *      pTable          - Pointer to Key table
210 *      pbyBSSID        - BSSID of Key
211 *      dwKeyIndex      - Key index (reference to NDIS DDK)
212 *      uKeyLength      - Key length
213 *      KeyRSC          - Key RSC
214 *      pbyKey          - Pointer to key
215 *  Out:
216 *      none
217 *
218 * Return Value: TRUE if success otherwise FALSE
219 *
220 */
221BOOL KeybSetKey(
222    void *pDeviceHandler,
223    PSKeyManagement pTable,
224    PBYTE           pbyBSSID,
225    DWORD           dwKeyIndex,
226    unsigned long           uKeyLength,
227    PQWORD          pKeyRSC,
228    PBYTE           pbyKey,
229    BYTE            byKeyDecMode
230    )
231{
232    PSDevice    pDevice = (PSDevice) pDeviceHandler;
233    int         i,j;
234    unsigned int        ii;
235    PSKeyItem   pKey;
236    unsigned int        uKeyIdx;
237
238    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetKey: %lX\n", dwKeyIndex);
239
240    j = (MAX_KEY_TABLE-1);
241    for (i=0;i<(MAX_KEY_TABLE-1);i++) {
242        if ((pTable->KeyTable[i].bInUse == FALSE) &&
243            (j == (MAX_KEY_TABLE-1))) {
244            // found empty table
245            j = i;
246        }
247        if ((pTable->KeyTable[i].bInUse == TRUE) &&
248	    !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
249            // found table already exist
250            if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
251                // Pairwise key
252                pKey = &(pTable->KeyTable[i].PairwiseKey);
253                pTable->KeyTable[i].wKeyCtl &= 0xFFF0;          // clear pairwise key control filed
254                pTable->KeyTable[i].wKeyCtl |= byKeyDecMode;
255                uKeyIdx = 4;                                    // use HW key entry 4 for pairwise key
256            } else {
257                // Group key
258                if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
259                    return (FALSE);
260                pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
261                if ((dwKeyIndex & TRANSMIT_KEY) != 0)  {
262                    // Group transmit key
263                    pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
264                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
265                }
266                pTable->KeyTable[i].wKeyCtl &= 0xFF0F;          // clear group key control filed
267                pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
268                pTable->KeyTable[i].wKeyCtl |= 0x0040;          // use group key for group address
269                uKeyIdx = (dwKeyIndex & 0x000000FF);
270            }
271            pTable->KeyTable[i].wKeyCtl |= 0x8000;              // enable on-fly
272
273            pKey->bKeyValid = TRUE;
274            pKey->uKeyLength = uKeyLength;
275            pKey->dwKeyIndex = dwKeyIndex;
276            pKey->byCipherSuite = byKeyDecMode;
277            memcpy(pKey->abyKey, pbyKey, uKeyLength);
278            if (byKeyDecMode == KEY_CTL_WEP) {
279                if (uKeyLength == WLAN_WEP40_KEYLEN)
280                    pKey->abyKey[15] &= 0x7F;
281                if (uKeyLength == WLAN_WEP104_KEYLEN)
282                    pKey->abyKey[15] |= 0x80;
283            }
284            MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey);
285
286            if ((dwKeyIndex & USE_KEYRSC) == 0) {
287                // RSC set by NIC
288		    memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
289            }
290            else {
291                memcpy(&(pKey->KeyRSC), pKeyRSC,  sizeof(QWORD));
292            }
293            pKey->dwTSC47_16 = 0;
294            pKey->wTSC15_0 = 0;
295
296            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
297            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
298            //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", pKey->uKeyLength);
299            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
300            for (ii = 0; ii < pKey->uKeyLength; ii++) {
301                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
302            }
303            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
304
305            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
306            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
307            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
308
309            return (TRUE);
310        }
311    }
312    if (j < (MAX_KEY_TABLE-1)) {
313	memcpy(pTable->KeyTable[j].abyBSSID, pbyBSSID, ETH_ALEN);
314        pTable->KeyTable[j].bInUse = TRUE;
315        if ((dwKeyIndex & PAIRWISE_KEY) != 0)  {
316            // Pairwise key
317            pKey = &(pTable->KeyTable[j].PairwiseKey);
318            pTable->KeyTable[j].wKeyCtl &= 0xFFF0;          // clear pairwise key control filed
319            pTable->KeyTable[j].wKeyCtl |= byKeyDecMode;
320            uKeyIdx = 4;                                    // use HW key entry 4 for pairwise key
321        } else {
322            // Group key
323            if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
324                return (FALSE);
325            pKey = &(pTable->KeyTable[j].GroupKey[dwKeyIndex & 0x000000FF]);
326            if ((dwKeyIndex & TRANSMIT_KEY) != 0)  {
327                // Group transmit key
328                pTable->KeyTable[j].dwGTKeyIndex = dwKeyIndex;
329                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(N)[%lX]: %d\n", pTable->KeyTable[j].dwGTKeyIndex, j);
330            }
331            pTable->KeyTable[j].wKeyCtl &= 0xFF0F;          // clear group key control filed
332            pTable->KeyTable[j].wKeyCtl |= (byKeyDecMode << 4);
333            pTable->KeyTable[j].wKeyCtl |= 0x0040;          // use group key for group address
334            uKeyIdx = (dwKeyIndex & 0x000000FF);
335        }
336        pTable->KeyTable[j].wKeyCtl |= 0x8000;              // enable on-fly
337
338        pKey->bKeyValid = TRUE;
339        pKey->uKeyLength = uKeyLength;
340        pKey->dwKeyIndex = dwKeyIndex;
341        pKey->byCipherSuite = byKeyDecMode;
342        memcpy(pKey->abyKey, pbyKey, uKeyLength);
343        if (byKeyDecMode == KEY_CTL_WEP) {
344            if (uKeyLength == WLAN_WEP40_KEYLEN)
345                pKey->abyKey[15] &= 0x7F;
346            if (uKeyLength == WLAN_WEP104_KEYLEN)
347                pKey->abyKey[15] |= 0x80;
348        }
349        MACvSetKeyEntry(pDevice, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey);
350
351        if ((dwKeyIndex & USE_KEYRSC) == 0) {
352            // RSC set by NIC
353		memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
354        }
355        else {
356            memcpy(&(pKey->KeyRSC), pKeyRSC,  sizeof(QWORD));
357        }
358        pKey->dwTSC47_16 = 0;
359        pKey->wTSC15_0 = 0;
360
361        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(N): \n");
362        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
363        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
364        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
365        for (ii = 0; ii < pKey->uKeyLength; ii++) {
366            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
367        }
368        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
369
370        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
371        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
372        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
373
374        return (TRUE);
375    }
376    return (FALSE);
377}
378
379
380/*
381 * Description: Remove Key from table
382 *
383 * Parameters:
384 *  In:
385 *      pTable          - Pointer to Key table
386 *      pbyBSSID        - BSSID of Key
387 *      dwKeyIndex      - Key Index (reference to NDIS DDK)
388 *  Out:
389 *      none
390 *
391 * Return Value: TRUE if success otherwise FALSE
392 *
393 */
394BOOL KeybRemoveKey(
395    void *pDeviceHandler,
396    PSKeyManagement pTable,
397    PBYTE           pbyBSSID,
398    DWORD           dwKeyIndex
399    )
400{
401    PSDevice    pDevice = (PSDevice) pDeviceHandler;
402    int     i;
403    BOOL    bReturnValue = FALSE;
404
405    if (is_broadcast_ether_addr(pbyBSSID)) {
406        // dealte all key
407        if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
408            for (i=0;i<MAX_KEY_TABLE;i++) {
409                pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
410            }
411            bReturnValue =  TRUE;
412        }
413        else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
414            for (i=0;i<MAX_KEY_TABLE;i++) {
415                pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
416                if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
417                    // remove Group transmit key
418                    pTable->KeyTable[i].dwGTKeyIndex = 0;
419                }
420            }
421            bReturnValue = TRUE;
422        }
423        else {
424            bReturnValue = FALSE;
425        }
426
427    } else {
428        for (i=0;i<MAX_KEY_TABLE;i++) {
429            if ( (pTable->KeyTable[i].bInUse == TRUE) &&
430		 !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
431
432                if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
433                    pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
434                    bReturnValue = TRUE;
435                    break;
436                }
437                else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
438                    pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
439                    if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
440                        // remove Group transmit key
441                        pTable->KeyTable[i].dwGTKeyIndex = 0;
442                    }
443                    bReturnValue = TRUE;
444                    break;
445                }
446                else {
447                    bReturnValue = FALSE;
448                    break;
449                }
450            } //pTable->KeyTable[i].bInUse == TRUE
451        }  //for
452        bReturnValue = TRUE;
453    }
454
455    s_vCheckKeyTableValid(pDevice,pTable);
456    return bReturnValue;
457
458
459}
460
461
462/*
463 * Description: Remove Key from table
464 *
465 * Parameters:
466 *  In:
467 *      pTable          - Pointer to Key table
468 *      pbyBSSID        - BSSID of Key
469 *  Out:
470 *      none
471 *
472 * Return Value: TRUE if success otherwise FALSE
473 *
474 */
475BOOL KeybRemoveAllKey(
476    void *pDeviceHandler,
477    PSKeyManagement pTable,
478    PBYTE           pbyBSSID
479    )
480{
481    PSDevice    pDevice = (PSDevice) pDeviceHandler;
482    int  i,u;
483
484    for (i=0;i<MAX_KEY_TABLE;i++) {
485        if ((pTable->KeyTable[i].bInUse == TRUE) &&
486	    !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
487            pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
488	    for (u = 0; u < MAX_GROUP_KEY; u++)
489		pTable->KeyTable[i].GroupKey[u].bKeyValid = FALSE;
490
491            pTable->KeyTable[i].dwGTKeyIndex = 0;
492            s_vCheckKeyTableValid(pDevice, pTable);
493            return (TRUE);
494        }
495    }
496    return (FALSE);
497}
498
499/*
500 * Description: Remove WEP Key from table
501 *
502 * Parameters:
503 *  In:
504 *      pTable          - Pointer to Key table
505 *  Out:
506 *      none
507 *
508 * Return Value: TRUE if success otherwise FALSE
509 *
510 */
511void KeyvRemoveWEPKey(
512    void *pDeviceHandler,
513    PSKeyManagement pTable,
514    DWORD           dwKeyIndex
515    )
516{
517    PSDevice    pDevice = (PSDevice) pDeviceHandler;
518
519   if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
520        if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == TRUE) {
521            if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) {
522                pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
523                if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) {
524                    // remove Group transmit key
525                    pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0;
526                }
527            }
528        }
529        s_vCheckKeyTableValid(pDevice, pTable);
530    }
531    return;
532}
533
534void KeyvRemoveAllWEPKey(void *pDeviceHandler, PSKeyManagement pTable)
535{
536	PSDevice pDevice = (PSDevice) pDeviceHandler;
537	int i;
538
539	for (i = 0; i < MAX_GROUP_KEY; i++)
540		KeyvRemoveWEPKey(pDevice, pTable, i);
541}
542
543/*
544 * Description: Get Transmit Key from table
545 *
546 * Parameters:
547 *  In:
548 *      pTable          - Pointer to Key table
549 *      pbyBSSID        - BSSID of Key
550 *  Out:
551 *      pKey            - Key return
552 *
553 * Return Value: TRUE if found otherwise FALSE
554 *
555 */
556BOOL KeybGetTransmitKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyType,
557			PSKeyItem *pKey)
558{
559    int i, ii;
560
561    *pKey = NULL;
562    for (i = 0; i < MAX_KEY_TABLE; i++) {
563        if ((pTable->KeyTable[i].bInUse == TRUE) &&
564	    !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
565
566            if (dwKeyType == PAIRWISE_KEY) {
567
568                if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) {
569                    *pKey = &(pTable->KeyTable[i].PairwiseKey);
570
571                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
572                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PAIRWISE_KEY: KeyTable.abyBSSID: ");
573                    for (ii = 0; ii < 6; ii++) {
574                        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]);
575                    }
576                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
577
578
579                    return (TRUE);
580                }
581                else {
582                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PairwiseKey.bKeyValid == FALSE\n");
583                    return (FALSE);
584                }
585            } // End of Type == PAIRWISE
586            else {
587                if (pTable->KeyTable[i].dwGTKeyIndex == 0) {
588                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: dwGTKeyIndex == 0 !!!\n");
589                    return FALSE;
590                }
591                if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == TRUE) {
592                    *pKey = &(pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)]);
593
594                        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
595                        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GROUP_KEY: KeyTable.abyBSSID\n");
596                        for (ii = 0; ii < 6; ii++) {
597                            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]);
598                        }
599                        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
600                        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex);
601
602                    return (TRUE);
603                }
604                else {
605                    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GroupKey.bKeyValid == FALSE\n");
606                    return (FALSE);
607                }
608            } // End of Type = GROUP
609        } // BSSID match
610    }
611    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: NO Match BSSID !!! ");
612    for (ii = 0; ii < 6; ii++) {
613        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(pbyBSSID+ii));
614    }
615    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
616    return (FALSE);
617}
618
619
620/*
621 * Description: Check Pairewise Key
622 *
623 * Parameters:
624 *  In:
625 *      pTable          - Pointer to Key table
626 *  Out:
627 *      none
628 *
629 * Return Value: TRUE if found otherwise FALSE
630 *
631 */
632BOOL KeybCheckPairewiseKey(PSKeyManagement pTable, PSKeyItem *pKey)
633{
634    int i;
635
636    *pKey = NULL;
637    for (i=0;i<MAX_KEY_TABLE;i++) {
638        if ((pTable->KeyTable[i].bInUse == TRUE) &&
639            (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE)) {
640            *pKey = &(pTable->KeyTable[i].PairwiseKey);
641            return (TRUE);
642        }
643    }
644    return (FALSE);
645}
646
647/*
648 * Description: Set Key to table
649 *
650 * Parameters:
651 *  In:
652 *      pTable          - Pointer to Key table
653 *      dwKeyIndex      - Key index (reference to NDIS DDK)
654 *      uKeyLength      - Key length
655 *      KeyRSC          - Key RSC
656 *      pbyKey          - Pointer to key
657 *  Out:
658 *      none
659 *
660 * Return Value: TRUE if success otherwise FALSE
661 *
662 */
663BOOL KeybSetDefaultKey(
664    void *pDeviceHandler,
665    PSKeyManagement pTable,
666    DWORD           dwKeyIndex,
667    unsigned long           uKeyLength,
668    PQWORD          pKeyRSC,
669    PBYTE           pbyKey,
670    BYTE            byKeyDecMode
671    )
672{
673    PSDevice    pDevice = (PSDevice) pDeviceHandler;
674    unsigned int        ii;
675    PSKeyItem   pKey;
676    unsigned int        uKeyIdx;
677
678    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enter KeybSetDefaultKey: %1x, %d\n",
679	    (int) dwKeyIndex, (int) uKeyLength);
680
681    if ((dwKeyIndex & PAIRWISE_KEY) != 0) {                  // Pairwise key
682        return (FALSE);
683    } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
684        return (FALSE);
685    }
686
687    pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = TRUE;
688    for (ii = 0; ii < ETH_ALEN; ii++)
689        pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF;
690
691    // Group key
692    pKey = &(pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF]);
693    if ((dwKeyIndex & TRANSMIT_KEY) != 0)  {
694        // Group transmit key
695        pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = dwKeyIndex;
696        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, MAX_KEY_TABLE-1);
697
698    }
699    pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl &= 0x7F00;          // clear all key control filed
700    pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode << 4);
701    pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode);
702    pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x0044;          // use group key for all address
703    uKeyIdx = (dwKeyIndex & 0x000000FF);
704
705    if ((uKeyLength == WLAN_WEP232_KEYLEN) &&
706        (byKeyDecMode == KEY_CTL_WEP)) {
707        pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x4000;              // disable on-fly disable address match
708        pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = TRUE;
709    } else {
710        if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == FALSE)
711            pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0xC000;          // enable on-fly disable address match
712    }
713
714    pKey->bKeyValid = TRUE;
715    pKey->uKeyLength = uKeyLength;
716    pKey->dwKeyIndex = dwKeyIndex;
717    pKey->byCipherSuite = byKeyDecMode;
718    memcpy(pKey->abyKey, pbyKey, uKeyLength);
719    if (byKeyDecMode == KEY_CTL_WEP) {
720        if (uKeyLength == WLAN_WEP40_KEYLEN)
721            pKey->abyKey[15] &= 0x7F;
722        if (uKeyLength == WLAN_WEP104_KEYLEN)
723            pKey->abyKey[15] |= 0x80;
724    }
725
726    MACvSetKeyEntry(pDevice, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (PDWORD) pKey->abyKey);
727
728    if ((dwKeyIndex & USE_KEYRSC) == 0) {
729        // RSC set by NIC
730	    memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
731    } else {
732        memcpy(&(pKey->KeyRSC), pKeyRSC,  sizeof(QWORD));
733    }
734    pKey->dwTSC47_16 = 0;
735    pKey->wTSC15_0 = 0;
736
737
738    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
739    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n", pKey->bKeyValid);
740    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n", (int)pKey->uKeyLength);
741    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: \n");
742    for (ii = 0; ii < pKey->uKeyLength; ii++) {
743        DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x", pKey->abyKey[ii]);
744    }
745    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
746
747    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n", pKey->dwTSC47_16);
748    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n", pKey->wTSC15_0);
749    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex);
750
751    return (TRUE);
752}
753
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
754
755/*
756 * Description: Set Key to table
757 *
758 * Parameters:
759 *  In:
760 *      pTable          - Pointer to Key table
761 *      dwKeyIndex      - Key index (reference to NDIS DDK)
762 *      uKeyLength      - Key length
763 *      KeyRSC          - Key RSC
764 *      pbyKey          - Pointer to key
765 *  Out:
766 *      none
767 *
768 * Return Value: TRUE if success otherwise FALSE
769 *
770 */
771BOOL KeybSetAllGroupKey(
772    void *pDeviceHandler,
773    PSKeyManagement pTable,
774    DWORD           dwKeyIndex,
775    unsigned long           uKeyLength,
776    PQWORD          pKeyRSC,
777    PBYTE           pbyKey,
778    BYTE            byKeyDecMode
779    )
780{
781    PSDevice    pDevice = (PSDevice) pDeviceHandler;
782    int         i;
783    unsigned int        ii;
784    PSKeyItem   pKey;
785    unsigned int        uKeyIdx;
786
787    DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex);
788
789
790    if ((dwKeyIndex & PAIRWISE_KEY) != 0) {                  // Pairwise key
791        return (FALSE);
792    } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
793        return (FALSE);
794    }
795
796    for (i=0; i < MAX_KEY_TABLE-1; i++) {
797        if (pTable->KeyTable[i].bInUse == TRUE) {
798            // found table already exist
799            // Group key
800            pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
801            if ((dwKeyIndex & TRANSMIT_KEY) != 0)  {
802                // Group transmit key
803                pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
804                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
805
806            }
807            pTable->KeyTable[i].wKeyCtl &= 0xFF0F;          // clear group key control filed
808            pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
809            pTable->KeyTable[i].wKeyCtl |= 0x0040;          // use group key for group address
810            uKeyIdx = (dwKeyIndex & 0x000000FF);
811
812            pTable->KeyTable[i].wKeyCtl |= 0x8000;              // enable on-fly
813
814            pKey->bKeyValid = TRUE;
815            pKey->uKeyLength = uKeyLength;
816            pKey->dwKeyIndex = dwKeyIndex;
817            pKey->byCipherSuite = byKeyDecMode;
818            memcpy(pKey->abyKey, pbyKey, uKeyLength);
819            if (byKeyDecMode == KEY_CTL_WEP) {
820                if (uKeyLength == WLAN_WEP40_KEYLEN)
821                    pKey->abyKey[15] &= 0x7F;
822                if (uKeyLength == WLAN_WEP104_KEYLEN)
823                    pKey->abyKey[15] |= 0x80;
824            }
825
826            MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (PDWORD) pKey->abyKey);
827
828            if ((dwKeyIndex & USE_KEYRSC) == 0) {
829                // RSC set by NIC
830		    memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
831            }
832            else {
833                memcpy(&(pKey->KeyRSC), pKeyRSC,  sizeof(QWORD));
834            }
835            pKey->dwTSC47_16 = 0;
836            pKey->wTSC15_0 = 0;
837
838            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
839            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
840            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
841            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
842            for (ii = 0; ii < pKey->uKeyLength; ii++) {
843                DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", pKey->abyKey[ii]);
844            }
845            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
846
847            //DBG_PRN_GRP12(("pKey->dwTSC47_16: %lX\n ", pKey->dwTSC47_16));
848            //DBG_PRN_GRP12(("pKey->wTSC15_0: %X\n ", pKey->wTSC15_0));
849            //DBG_PRN_GRP12(("pKey->dwKeyIndex: %lX\n ", pKey->dwKeyIndex));
850
851        } // (pTable->KeyTable[i].bInUse == TRUE)
852    }
853    return (TRUE);
854}
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
  4 * All rights reserved.
  5 *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  6 * File: key.c
  7 *
  8 * Purpose: Implement functions for 802.11i Key management
  9 *
 10 * Author: Jerry Chen
 11 *
 12 * Date: May 29, 2003
 13 *
 14 * Functions:
 
 
 
 
 
 15 *
 16 * Revision History:
 17 *
 18 */
 19
 
 
 20#include "mac.h"
 21#include "key.h"
 22#include "usbpipe.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 23
 24int vnt_key_init_table(struct vnt_private *priv)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 25{
 26	u8 i;
 27	u8 data[MAX_KEY_TABLE];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 28
 29	for (i = 0; i < MAX_KEY_TABLE; i++)
 30		data[i] = i;
 31
 32	return vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY,
 33			0, 0, ARRAY_SIZE(data), data);
 34}
 35
 36static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr,
 37			   struct ieee80211_key_conf *key, u32 key_type,
 38			   u32 mode)
 39{
 40	struct vnt_private *priv = hw->priv;
 41	u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 42	u16 key_mode = 0;
 43	u32 entry = 0;
 44	u8 *bssid;
 45	u8 key_inx = key->keyidx;
 46	u8 i;
 47
 48	if (mac_addr)
 49		bssid = mac_addr;
 50	else
 51		bssid = &broadcast[0];
 52
 53	if (key_type != VNT_KEY_DEFAULTKEY) {
 54		for (i = 0; i < (MAX_KEY_TABLE - 1); i++) {
 55			if (!test_bit(i, &priv->key_entry_inuse)) {
 56				set_bit(i, &priv->key_entry_inuse);
 57
 58				key->hw_key_idx = i;
 59				entry = key->hw_key_idx;
 60				break;
 61			}
 62		}
 63	}
 64
 65	switch (key_type) {
 66	case VNT_KEY_DEFAULTKEY:
 67		/* default key last entry */
 68		entry = MAX_KEY_TABLE - 1;
 69		key->hw_key_idx = entry;
 70		fallthrough;
 71	case VNT_KEY_GROUP_ADDRESS:
 72		key_mode = mode | (mode << 4);
 73		break;
 74	case VNT_KEY_GROUP:
 75		key_mode = mode << 4;
 76		break;
 77	case  VNT_KEY_PAIRWISE:
 78		key_mode |= mode;
 79		key_inx = 4;
 80		break;
 81	default:
 82		return -EINVAL;
 83	}
 84
 85	key_mode |= key_type;
 86
 87	if (mode == KEY_CTL_WEP) {
 88		if (key->keylen == WLAN_KEY_LEN_WEP40)
 89			key->key[15] &= 0x7f;
 90		if (key->keylen == WLAN_KEY_LEN_WEP104)
 91			key->key[15] |= 0x80;
 92	}
 93
 94	return vnt_mac_set_keyentry(priv, key_mode, entry,
 95				    key_inx, bssid, key->key);
 96}
 97
 98int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 99		 struct ieee80211_vif *vif, struct ieee80211_key_conf *key)
100{
101	struct vnt_private *priv = hw->priv;
102	u8 *mac_addr = NULL;
103	u8 key_dec_mode = 0;
104
105	if (sta)
106		mac_addr = &sta->addr[0];
107
108	switch (key->cipher) {
109	case WLAN_CIPHER_SUITE_WEP40:
110	case WLAN_CIPHER_SUITE_WEP104:
111		vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY,
112				KEY_CTL_WEP);
113
114		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
115
116		return vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY,
117				       KEY_CTL_WEP);
118
119	case WLAN_CIPHER_SUITE_TKIP:
120		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
121		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
122
123		key_dec_mode = KEY_CTL_TKIP;
124
125		break;
126	case WLAN_CIPHER_SUITE_CCMP:
127		if (priv->local_id <= MAC_REVISION_A1)
128			return -EOPNOTSUPP;
129
130		key_dec_mode = KEY_CTL_CCMP;
131
132		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
133		break;
134	default:
135		return -EOPNOTSUPP;
136	}
137
138	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
139		return vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE,
140				       key_dec_mode);
141
142	return vnt_set_keymode(hw, mac_addr, key,
143				VNT_KEY_GROUP_ADDRESS, key_dec_mode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144}