⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wlc_key.c

📁 wi-fi sources for asus wl138g v2 pci card
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Key Management routines for * Broadcom 802.11abg Networking Device Driver * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved.                 *                                      * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * * $Id$ */#include <wlc_cfg.h>#include <typedefs.h>#include <bcmdefs.h>#include <osl.h>#include <sbutils.h>#include <bcmutils.h>#include <wlioctl.h>#include <bcmwpa.h>#include <proto/802.11.h>#include <sbhndpio.h>#include <sbhnddma.h>#include <hnddma.h>#include <d11.h>#include <wlc_rate.h>#include <wlc_rate_sel.h>#include <wlc_key.h>#include <wlc_bsscfg.h>#include <wlc_channel.h>#include <wlc_pub.h>#include <wlc_bsscfg.h>#include <wlc_pio.h>#include <wlc.h>#include <wlc_scb.h>#include <wl_export.h>#define WLC_CHECK_WEP_UPDATE(wlc, update) (update)#define RC4_STATE_NBYTES	256	static int wlc_key_allocate(wlc_info_t *wlc);static void wlc_key_reset(wlc_info_t *wlc, wsec_key_t *key);static void wlc_key_hw_reallocate(wlc_info_t *wlc, int hw_index);static void wlc_key_hw_clear_all(wlc_info_t *wlc);static void wlc_key_write_addr(wlc_info_t *wlc, int i, const struct ether_addr *ea);/* * Find a free key slot in the wsec_keys array, and allocate a new key entry. */static intwlc_key_allocate(wlc_info_t *wlc){	int max_keys = WLC_MAX_WSEC_KEYS(wlc);	int i;	/* find a free key */	for (i = WSEC_MAX_DEFAULT_KEYS; i < max_keys; i++) {		if (wlc->wsec_keys[i] == NULL)			break;	}	if (i >= max_keys) {		WL_WSEC(("wl%d: out of per station key slots\n", wlc->pub.unit));		return BCME_NORESOURCE;	}	wlc->wsec_keys[i] = MALLOC(wlc->pub.osh, sizeof(wsec_key_t));	if (wlc->wsec_keys[i] == NULL) {		WL_ERROR(("wl%d: wlc_key_allocate: out of memory, malloced %d bytes\n",		          wlc->pub.unit, MALLOCED(wlc->pub.osh)));		return BCME_NOMEM;	}	return i;}/* * Insert a key.  At exit the key can be used as an rx key * but not tx.  wlc_set_crypto_index() needs to be called for that. */intwlc_key_insert(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, uint32 key_len,	uint32 key_id, uint32 key_flags, uint32 key_algo,	uint8 *key_data, struct ether_addr *key_ea,	wsec_iv_t *initial_iv){	struct scb *scb = NULL;	struct scb *scb_otherband = NULL;	wsec_key_t *key;	int wsec_idx;	WL_WSEC(("wl%d: wlc_key_insert: index %d keylen %d addr %s\n",	         wlc->pub.unit, key_id, key_len,	         bcm_ether_ntoa(key_ea, eabuf)));	ASSERT(bsscfg);	/* check length and IV index */	if (key_len != WEP1_KEY_SIZE &&	    key_len != WEP128_KEY_SIZE &&	    key_len != TKIP_KEY_SIZE &&	    key_len != AES_KEY_SIZE) {	  WL_ERROR(("wl%d: wlc_key_insert: unsupported key size %d\n",	            wlc->pub.unit, key_len));	  return BCME_BADLEN;	}	if (key_id >= WSEC_MAX_DEFAULT_KEYS) {		WL_ERROR(("wl%d: wlc_key_insert: illegal key index %d\n", wlc->pub.unit, key_id));		return BCME_BADKEYIDX;	}	/* set a default key */	if (ETHER_ISNULLADDR(key_ea) || ETHER_ISBCAST(key_ea)) {		if (BSSCFG_STA(bsscfg)) {			/* 			 * If the bsscfg key pointer has not already been set, set it to point to			 * the statically allocated memory here.			 */			if (bsscfg->bss_def_keys[key_id] == NULL) {				bsscfg->bss_def_keys[key_id] = &wlc->wsec_def_keys[key_id];			}			ASSERT(bsscfg->bss_def_keys[key_id]->idx == key_id);			wsec_idx = key_id;		}		else {			if (bsscfg->bss_def_keys[key_id]) {				wsec_idx = WSEC_KEY_INDEX(wlc, bsscfg->bss_def_keys[key_id]);				ASSERT((wsec_idx >= 0) && (wsec_idx < WLC_MAX_WSEC_KEYS(wlc)));				ASSERT(bsscfg->bss_def_keys[key_id] == wlc->wsec_keys[wsec_idx]);			}			else {				/* Get a new key. */				if ((wsec_idx = wlc_key_allocate(wlc)) < 0)					return wsec_idx;				bsscfg->bss_def_keys[key_id] = wlc->wsec_keys[wsec_idx];			}		}	}	/* set a per station key */	else {		if (wlc->pub.associated && wlc->band->bandunit != CHANNEL_BANDUNIT(wlc,			wlc->pub.current_bss.channel)) {		}		if (!(scb = wlc_scblookup(wlc, key_ea))) {			WL_ERROR(("wl%d: out of scbs\n", wlc->pub.unit));			return BCME_NOTFOUND;		}		if (scb->key) {			/* replace the existing scb key */			wsec_idx = WSEC_KEY_INDEX(wlc, scb->key);			ASSERT((wsec_idx >= WSEC_MAX_DEFAULT_KEYS) &&			       (wsec_idx < WLC_MAX_WSEC_KEYS(wlc)));			ASSERT(scb->key == wlc->wsec_keys[wsec_idx]);		}		else if (NBANDS(wlc) > 1 &&		         (scb_otherband = wlc_scbfindband(wlc, key_ea,		                                          OTHERBANDUNIT(wlc))) &&		         scb_otherband->key) {			/* use the same key for scbs with the same MAC in each band */			wsec_idx = WSEC_KEY_INDEX(wlc, scb_otherband->key);			ASSERT((wsec_idx >= WSEC_MAX_DEFAULT_KEYS) &&			       (wsec_idx < WLC_MAX_WSEC_KEYS(wlc)));			ASSERT(scb_otherband->key == wlc->wsec_keys[wsec_idx]);			scb->key = wlc->wsec_keys[wsec_idx];		} else {			/* Get a new key. */			if ((wsec_idx = wlc_key_allocate(wlc)) < 0)				return wsec_idx;			scb->key = wlc->wsec_keys[wsec_idx];		}	}	WL_WSEC(("wlc_key_insert: using the key idx  %d, key_id is %d\n", wsec_idx, key_id));	/* update the key */	/* The following line can't use WSEC_KEY macro, since the len might be 0. */	key = wlc->wsec_keys[wsec_idx];	bzero((char*)key, sizeof(wsec_key_t));	key->idx = (uint8)wsec_idx;	bcopy((char*)key_data, (char*)key->data, key_len);	key->len = (uint8)key_len;	key->id = (uint8)key_id;	bcopy((char*)key_ea, (char*)&key->ea, ETHER_ADDR_LEN);	key->aes_mode = AES_MODE_NONE;	switch (key_len) {	case WEP1_KEY_SIZE:		WL_WSEC(("wl%d: wlc_key_insert: WEP (40-bit)\n", wlc->pub.unit));		key->algo = CRYPTO_ALGO_WEP1;		key->algo_hw = WSEC_ALGO_WEP1;		key->iv_len = DOT11_IV_LEN;		key->icv_len = DOT11_ICV_LEN;		break;	case WEP128_KEY_SIZE:		WL_WSEC(("wl%d: wlc_key_insert: WEP (128-bit)\n", wlc->pub.unit));		key->algo = CRYPTO_ALGO_WEP128;		key->algo_hw = WSEC_ALGO_WEP128;		key->iv_len = DOT11_IV_LEN;		key->icv_len = DOT11_ICV_LEN;		break;	case TKIP_KEY_SIZE:		WL_WSEC(("wl%d: wlc_key_insert: TKIP\n", wlc->pub.unit));		key->algo = CRYPTO_ALGO_TKIP;		key->algo_hw = WSEC_ALGO_TKIP;		key->iv_len = DOT11_IV_TKIP_LEN;		key->icv_len = DOT11_ICV_LEN;		break;	case AES_KEY_SIZE:		switch (key_algo) {		case CRYPTO_ALGO_AES_OCB_MSDU :		case CRYPTO_ALGO_AES_OCB_MPDU:			WL_WSEC(("wl%d: wlc_key_insert: AES\n", wlc->pub.unit));			key->algo = (uint8)key_algo;			key->algo_hw = WSEC_ALGO_AES;			key->iv_len = DOT11_IV_AES_OCB_LEN;			key->icv_len = DOT11_ICV_AES_LEN;			if (key->algo == CRYPTO_ALGO_AES_OCB_MSDU)				key->aes_mode = AES_MODE_OCB_MSDU;			else				key->aes_mode = AES_MODE_OCB_MPDU;			break;		case CRYPTO_ALGO_AES_CCM:		default:			WL_WSEC(("wl%d: wlc_key_insert: AES\n", wlc->pub.unit));			key->algo = CRYPTO_ALGO_AES_CCM;			if (scb && (scb->flags & SCB_LEGACY_AES)) {				WL_WSEC(("wl%d: wlc_key_insert: setting pairwise key for Legacy"					" AES\n", wlc->pub.unit));				key->algo_hw = WSEC_ALGO_AES_LEGACY;			} else {				/* 				 * If this STA is talking to a legacy AP, mark the group key				 * as legacy also.				 */				if (BSSCFG_STA(bsscfg)) {					struct scb *apscb = NULL;					if (!(apscb = wlc_scbfind(wlc,						&wlc->pub.current_bss.BSSID))) {						WL_ERROR(("wl%d: wlc_key_insert: scb for associated"							" AP not found\n", wlc->pub.unit));						return BCME_NOTFOUND;					}					if (apscb->flags & SCB_LEGACY_AES) {						WL_WSEC(("wl%d: wlc_key_insert: setting group key"							" for Legacy AES\n", wlc->pub.unit));						key->algo_hw = WSEC_ALGO_AES_LEGACY;					} else						key->algo_hw = WSEC_ALGO_AES;				} else					key->algo_hw = WSEC_ALGO_AES;			}			key->iv_len = DOT11_IV_AES_CCM_LEN;			key->icv_len = DOT11_ICV_AES_LEN;			key->aes_mode = AES_MODE_CCM;			break;		}		break;	}	/* set new default key */	if (ETHER_ISNULLADDR(key_ea) || 		( (key->algo == CRYPTO_ALGO_WEP1 || 		  key->algo == CRYPTO_ALGO_WEP128) && ETHER_ISBCAST(key_ea))) {		if (key_flags & WL_PRIMARY_KEY) {			if (WSEC_BSS_DEFAULT_KEY(bsscfg)) {				WSEC_BSS_DEFAULT_KEY(bsscfg)->flags &= ~WSEC_PRIMARY_KEY;			}			bsscfg->wsec_index = key_id;			key->flags |= WSEC_PRIMARY_KEY;		} else if ((uint32)bsscfg->wsec_index == key_id) {			/* this key was the primary, but the key insert cleared the flag */			bsscfg->wsec_index = -1;		}	}	/* call the tkip module for the key setup */	if (key->algo == CRYPTO_ALGO_TKIP) {		wl_tkip_keyset(wlc->wl, key);	}	WL_WSEC(("wl%d: wlc_key_insert: key algo %d algo_hw %d flags %d\n", wlc->pub.unit,		key->algo, key->algo_hw, key->flags));	/* check for a provided IV init value */	wlc_key_iv_init(wlc, key, initial_iv);	wlc_key_update(wlc, bsscfg, wsec_idx);	if (BSSCFG_STA(bsscfg) && (wsec_idx < WSEC_MAX_DEFAULT_KEYS)) {		bool prev_psallowed = PS_ALLOWED(wlc);		/*		 * A default key is used as an indication of the presence of a group		 * key, which in turn indicates whether the port is considered open		 * or closed		 */		wlc->wsec_portopen = TRUE;		/*		 * If PS_ALLOWED was waiting on the portopen state then		 *    initiate the PM state change		 */		if (!prev_psallowed && PS_ALLOWED(wlc))			wlc_set_pmstate(wlc, TRUE);	}	return 0;}/*  * If the MSSID indication flag has been changed, the default config must * adapt its default key table to reflect the current status of Multi-SSID: * if Multi-SSID is enabled, the four statically allocated keys which * correspond to the hardware default keys cannot be used, whereas if * Multi-SSID is not enabled, it is better to use the hardware default keys. * Thus, if the mssid flag is changed, the type of keys used must also be * changed, and any pre-existing keys must be copied over. */voidwlc_key_mssid_change(wlc_info_t *wlc, bool old_mssid, bool new_mssid){	int ii;	int index;	int wsec_index;	wsec_key_t *key;	WL_WSEC(("\nwl%d: wlc_key_mssid_change: old mssid val: %d, new mssid val: %d\n",	         wlc->pub.unit, old_mssid, new_mssid));	if (old_mssid == new_mssid)		return;	wsec_index = wlc->bsscfg[0]->wsec_index;	for (ii = 0; ii < WLC_DEFAULT_KEYS; ii++) {		if (wlc->bsscfg[0]->bss_def_keys[ii]) {			key = wlc->bsscfg[0]->bss_def_keys[ii];			wlc->bsscfg[0]->bss_def_keys[ii] = NULL;			ASSERT(key->idx >= WSEC_MAX_DEFAULT_KEYS);			index = ii;			wlc->bsscfg[0]->bss_def_keys[ii] = &wlc->wsec_def_keys[ii];			bcopy((char*)key, (char*)wlc->bsscfg[0]->bss_def_keys[ii],			      sizeof(wsec_key_t));			wlc->bsscfg[0]->bss_def_keys[ii]->idx = (uint8)index;			if (key->idx >= WSEC_MAX_DEFAULT_KEYS)				wlc_key_delete(wlc, wlc->bsscfg[0], key->idx);		}	}	wlc->bsscfg[0]->wsec_index = wsec_index;}voidwlc_key_remove_all(wlc_info_t *wlc){	int i;	for (i = 0; i < WLC_MAX_WSEC_KEYS(wlc); i++)		wlc_key_delete(wlc, wlc->bsscfg[0], i);}voidwlc_key_remove(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, wl_wsec_key_t *remove){	struct scb *scb;	wsec_key_t *key = NULL;	/* remove a default key */	if (ETHER_ISNULLADDR(&remove->ea) || ETHER_ISBCAST(&remove->ea)) {		if (remove->index < WSEC_MAX_DEFAULT_KEYS) {			key = bsscfg->bss_def_keys[remove->index];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -