📄 wlc_key.c
字号:
} break; default: WL_ERROR(("wl%d: wlc_key_iv_update: unsupported algorithm %d\n", wlc->pub.unit, key->algo)); ASSERT(1 == 0); break; } WL_WSEC(("wl%d: wlc_key_iv_update end: iv32 0x%08x iv16 0x%04x\n", wlc->pub.unit, txiv->hi, txiv->lo));}wsec_key_t*wlc_key_lookup(wlc_info_t *wlc, struct scb *scb, wlc_bsscfg_t *bsscfg, uint index, bool ismulti){ wsec_key_t *key = NULL; WL_WSEC(("\nwl%d: wlc_key_lookup: index %d\n", wlc->pub.unit, index)); if (scb->key && !ismulti) { key = scb->key; ASSERT(WSEC_KEY_INDEX(wlc, key) < WLC_MAX_WSEC_KEYS(wlc)); /* ASSERT(key->index == index); */ /* indexes should both be zero for per-path key */ WL_WSEC(("wl%d: wlc_key_lookup: per-path key-ID %d index %d, algo %d\n", wlc->pub.unit, key->id, key->idx, key->algo)); } else { ASSERT(index < WSEC_MAX_DEFAULT_KEYS); key = WLC_BSSCFG_WEPKEY(bsscfg, index); if (key) { WL_WSEC(("wl%d: wlc_key_lookup: valid group key at key-ID %d, algo %d\n", wlc->pub.unit, index, key->algo)); } else { WL_WSEC(("wl%d: wlc_key_lookup: no valid group key at key-ID %d\n", wlc->pub.unit, index)); } } return key;}/* initialize all hardware keys for the current core */voidwlc_key_hw_init_all(wlc_info_t *wlc){ uint i; uint hw_keys; WL_TRACE(("wl%d: wlc_key_hw_init_all\n", wlc->pub.unit)); wlc_key_hw_clear_all(wlc); if (WLC_SW_KEYS(wlc)) return; hw_keys = WLC_MAX_WSEC_HW_KEYS(wlc); for (i = 0; i < hw_keys; i++) { if (WSEC_KEY(wlc, i)) wlc_key_hw_init(wlc, i); }}/* Clear all hardware key state in the current core. * This assumes that the core has been reset so all registers * have their reset value. */static voidwlc_key_hw_clear_all(wlc_info_t *wlc){ struct ether_addr addr; int i, hw_keys, num_addrs; uint16 v; WL_TRACE(("wl%d: wlc_key_hw_clear_all\n", wlc->pub.unit)); hw_keys = WLC_MAX_WSEC_HW_KEYS(wlc); /* zero out the entire key table */ wlc_set_shm(wlc, wlc->seckeys, 0, hw_keys * D11_MAX_KEY_SIZE); for (i = 0; i < hw_keys; i++) { /* Set the matching SECALGO table entry */ v = WSEC_ALGO_OFF | (i << SKL_INDEX_SHIFT); wlc_write_shm(wlc, M_SECKINDXALGO_BLK + i*2, v); } /* clear the Rx-TA MAC addresses */ bzero(addr.octet, ETHER_ADDR_LEN); WL_NONE(("**** KEY SETTING\n")); if (D11REV_LT(wlc->pub.corerev, 5)) { WL_NONE(("**** KEY SETTING SET ADDR corerev %d \n", wlc->pub.corerev)); /* clear the 4 Rx-TA addrs in the RXE COND registers */ wlc_set_addrmatch(wlc, RCM_WEP_TA0_OFFSET, &addr); wlc_set_addrmatch(wlc, RCM_WEP_TA1_OFFSET, &addr); wlc_set_addrmatch(wlc, RCM_WEP_TA2_OFFSET, &addr); wlc_set_addrmatch(wlc, RCM_WEP_TA3_OFFSET, &addr); /* clear the soft Rx-TA addrs in shm */ num_addrs = WSEC_MAX_SEC_KEYS - (WSEC_MAX_DEFAULT_KEYS + WSEC_MAX_RXE_KEYS); wlc_set_shm(wlc, M_SECPSMRXTAMCH_BLK, 0, num_addrs * ETHER_ADDR_LEN); /* set the soft Rx-TA addr count */ wlc_write_shm(wlc, M_SEC_VALNUMSOFTMCHTA, WSEC_MAX_SEC_KEYS - (WSEC_MAX_DEFAULT_KEYS + WSEC_MAX_RXE_KEYS)); } else { WL_NONE(("**** KEY SETTING RCMTA corerev %d \n", wlc->pub.corerev)); /* clear the address table */ for (i = 0; i < (WSEC_MAX_RCMTA_KEYS - WSEC_MAX_DEFAULT_KEYS); i++) wlc_set_rcmta(wlc, i, &addr); /* update the rcmta_size reg in case we are running with a * WSEC_MAX_RCMTA_KEYS value different than the reset value */ W_REG(&wlc->regs->rcmta_size, (WSEC_MAX_RCMTA_KEYS - WSEC_MAX_DEFAULT_KEYS)); } /* clear the ucode default key flag MHF_DEFKEYVALID */ wlc_mhf(wlc, MHF_DEFKEYVALID, 0, TRUE); WL_WSEC(("wl%d: wlc_key_hw_clear_all: clear MHF_DEFKEYVALID\n", wlc->pub.unit));}/* Updates all hw keys marked for band switch update in wlc->wsec_bsupdate */voidwlc_key_bsupdate(wlc_info_t *wlc){ int i; /* update and clear the update flag if set */ for (i = 0; i < WLC_MAX_WSEC_HW_KEYS(wlc); i++) { if (isset(wlc->wsec_bsupdate.vec, i)) { clrbit(wlc->wsec_bsupdate.vec, i); wlc_key_hw_init(wlc, i); } }}/* * Return MHF_DEFKEYVALID flag based on soft keys and/or default WEP keys * existances and other factors. *//* * ucode flag MHF_DEFKEYVALID should be SET only when WEP encryption is * enabled, only one SSID is in use, there are valid default WEP keys and * there are no soft keys. It is cleared in all other cases. * The following explains why. * * This flag is meaningful only to encrypted unicast frames received. When * processing a rx'd unicast frame the ucode tries a pairwise key match first * based on the frame's TA and then falls back to a default key indicated by * the key index field in IV field of the frame if no pairwise key match is * found. For multicast/broadcast frames the ucode uses the key index field * in the frames' IV anyway to find the key entry. * * In case of Multi-SSID, the default keys are only valid for one SSID, and * the ucode does not distinguish between the SSIDs when checking the flag. * * In case of software encryption/decryption when soft keys are installed * this flag must be cleared so that encrypted unicast frames can be sent up * to the driver without any decryption attempt when there is no key installed * in the hardware for the TA. It is true for both STA and AP. * * In case of WPA/TKIP|AES we don't support group-key-only configuration and * there must be a pairwise key there on STA and one pairwise key per * associated STA on AP therefore this flag should always be cleared on both * STA and AP. * * In case of mixed WPA/TKIP|AES and 802.1x/WEP this flag should be always * cleared on AP since there must be a pairwise key for each STA. * * In case of 802.1x/WEP it should be always cleared on AP. However it must * be set on STA since there is no pairwise key on STA. * * In case of mixed WPA/TKIP|AES and 802.11/WEP this flag should be always * cleared on AP since the current transition mode support on AP plumbs * pairwise key for WEP STAs too. * * In case of multiple SSID configuration (AP-STA and/or AP-MSSID), default * keys are invalid. * In any other case of 802.11/WEP this flag should always be set. It is true * for both STA and AP. */uint32wlc_key_defkeyflag(wlc_info_t *wlc){ bool defkeys = FALSE, swkeys = FALSE; wsec_key_t *key; int j; /* no default key attempt for WPA */ /* assuming AES or TKIP is enabled */ if (wlc->cfg.WPA_auth != WPA_AUTH_DISABLED) return 0; /* set defkeys to TRUE if there are any default WEP keys */ /* assuming WEP is enabled */ for (j = 0; j < WSEC_MAX_DEFAULT_KEYS; j ++) { if ((key = WSEC_KEY(wlc, j)) && (key->algo == CRYPTO_ALGO_WEP1 || key->algo == CRYPTO_ALGO_WEP128)) { defkeys = TRUE; break; } } /* set swkeys to TRUE if there are any soft keys */ for (j = WLC_MAX_WSEC_HW_KEYS(wlc); j < WLC_MAX_WSEC_KEYS(wlc); j++) { if (WSEC_KEY(wlc, j)) { swkeys = TRUE; break; } } /* set the flag only when there are default WEP keys and there are no soft keys */ WL_WSEC(("wl%d: wlc_key_defkeyflag: default WEP keys %s, soft keys %s\n", wlc->pub.unit, defkeys ? "Yes" : "No", swkeys ? "Yes" : "No")); return (defkeys && !swkeys) ? MHF_DEFKEYVALID : 0;}/* Carry out any hardware actions needed after a wlc->wsec_key has been modified */voidwlc_key_update(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, int index){ wsec_key_t *key; WL_TRACE(("wl%d: wlc_key_update key %d\n", wlc->pub.unit, index)); key = WSEC_KEY(wlc, index); if ((key) && (key->algo == CRYPTO_ALGO_TKIP)) return; /* * Clear the ucode default key valid flag MHF_DEFKEYVALID if inserting * a per-STA soft key */ if (index >= WLC_MAX_WSEC_HW_KEYS(wlc) && WSEC_KEY(wlc, index)) { wlc_mhf(wlc, MHF_DEFKEYVALID, 0, TRUE); WL_WSEC(("wl%d: wlc_key_update: insert soft key %d, clear MHF_DEFKEYVALID\n", wlc->pub.unit, index)); } /* * Need to check both soft keys and default WEP keys before * making decision to clear or set this flag when deleting a soft key */ else if ((index >= WLC_MAX_WSEC_HW_KEYS(wlc) && !WSEC_KEY(wlc, index))) { uint32 flag = wlc_key_defkeyflag(wlc); wlc_mhf(wlc, MHF_DEFKEYVALID, flag, TRUE); WL_WSEC(("wl%d: wlc_key_update: delete soft key %d, %s MHF_DEFKEYVALID\n", wlc->pub.unit, index, flag ? "set" : "clear")); } /* if this is a soft key, then the hardware needs no update */ if (index >= WLC_MAX_WSEC_HW_KEYS(wlc)) return; /* since we only update the hardware for the current core, * mark the key for update on band switch if we are running on * multiple cores */ if (wlc->ncores > 1) setbit(wlc->wsec_bsupdate.vec, index); /* update the hardware */ if (wlc->pub.up) wlc_key_hw_init(wlc, index);}/* update the hardware with values to match the corresponding wlc->wsec_key */voidwlc_key_hw_init(wlc_info_t *wlc, int index){ wsec_key_t *key; struct ether_addr ea; uint offset; uint16 v; WL_TRACE(("wl%d: wlc_key_hw_init key %d\n", wlc->pub.unit, index)); ASSERT(index < WLC_MAX_WSEC_HW_KEYS(wlc)); ASSERT(wlc->sbclk); if (!WLC_SW_KEYS(wlc)) key = WSEC_KEY(wlc, index); else key = NULL; /* Clear the MAC address match if this is a paired key. * This protects the ucode or hardware from getting an * address match while we update this key. */ if (index >= WSEC_MAX_DEFAULT_KEYS) { bzero(ea.octet, ETHER_ADDR_LEN); wlc_key_write_addr(wlc, index, &ea); } /* Set the matching SECALGO table entry (algorithm and table index) */ if (!key) v = WSEC_ALGO_OFF | (index << SKL_INDEX_SHIFT); else v = key->algo_hw | (index << SKL_INDEX_SHIFT); wlc_write_shm(wlc, M_SECKINDXALGO_BLK + index * 2, v); /* * Set the rx and tx default key (i < WSEC_MAX_DEFAULT_KEYS) * or set the per sta key (i >= WSEC_MAX_DEFAULT_KEYS). */ offset = index * D11_MAX_KEY_SIZE; if (key) { /* Tx default key */ if (index < WSEC_MAX_DEFAULT_KEYS) wlc_copyto_shm(wlc, wlc->seckeys + offset, key->data, D11_MAX_KEY_SIZE); /* otherwise, write the key */ wlc_copyto_shm(wlc, wlc->seckeys + WSEC_RXKEYOFF + offset, key->data, D11_MAX_KEY_SIZE); } else { /* zero out key data if no key */ /* Tx default key */ if (index < WSEC_MAX_DEFAULT_KEYS) wlc_set_shm(wlc, wlc->seckeys + offset, 0, D11_MAX_KEY_SIZE); /* Rx key */ wlc_set_shm(wlc, wlc->seckeys + WSEC_RXKEYOFF + offset, 0, D11_MAX_KEY_SIZE); } /* handle per station keys */ if (key && index >= WSEC_MAX_DEFAULT_KEYS) { /* update the MAC address match */ wlc_key_write_addr(wlc, index, &key->ea); } /* update ucode flag MHF_DEFKEYVALID */ /* * Need to check both soft keys and default WEP keys before * making decision to either set or clear it when updating a default key */ if (index < WSEC_MAX_DEFAULT_KEYS) { uint32 flag = wlc_key_defkeyflag(wlc); wlc_mhf(wlc, MHF_DEFKEYVALID, flag, TRUE); WL_WSEC(("wl%d: wlc_key_hw_init: %s default key %d, %s MHF_DEFKEYVALID\n", wlc->pub.unit, key ? "insert" : "delete", index, flag ? "set" : "clear")); }}/* update the pairwise key address for a hardware key */static voidwlc_key_write_addr(wlc_info_t *wlc, int i, const struct ether_addr *ea){ uint offset; WL_TRACE(("wl%d: wlc_key_write_addr key %d\n", wlc->pub.unit, i)); ASSERT(i < WLC_MAX_WSEC_HW_KEYS(wlc)); ASSERT(i >= WSEC_MAX_DEFAULT_KEYS); if (D11REV_LT(wlc->pub.corerev, 5)) { /* set 4 RXE match registers */ if (i < (WSEC_MAX_DEFAULT_KEYS + WSEC_MAX_RXE_KEYS)) { /* calculate register offset */ offset = (i - WSEC_MAX_DEFAULT_KEYS) * ETHER_ADDR_LEN / 2; /* write to RXE match register */ wlc_set_addrmatch(wlc, RCM_WEP_TA0_OFFSET + offset, ea); } else { /* set 8 PSM match registers */ /* calculate shared memory offset */ offset = (i - (WSEC_MAX_DEFAULT_KEYS + WSEC_MAX_RXE_KEYS)) * ETHER_ADDR_LEN; /* write to shared memory */ wlc_copyto_shm(wlc, M_SECPSMRXTAMCH_BLK + offset, ea->octet, ETHER_ADDR_LEN); } } else { wlc_set_rcmta(wlc, (i - WSEC_MAX_DEFAULT_KEYS), ea); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -