Crypto api changes:

o don't use the key index to identify when the driver has been
  asked to allocate a key slot, use an explicit flag; allows
  drivers to force s/w fallback for entries in the global table
o change callback api to allocate driver resources for a crypto key:
  - de-const the key parameter so drivers can muck with the flags
  - on callback failure don't automatically try to setup s/w crypto;
    instead the driver must now mark the key entry for s/w crypto and
    the caller will re-attach the cipher module

NB: api change permits drivers more control over fallback to s/w
    crypto (e.g. based on a limited number of h/w key slots)
This commit is contained in:
Sam Leffler 2008-09-21 23:16:19 +00:00
parent 45f856e3ac
commit e6e547d57b
5 changed files with 56 additions and 50 deletions

View File

@ -141,7 +141,7 @@ static void ath_bmiss_proc(void *, int);
static int ath_keyset(struct ath_softc *, const struct ieee80211_key *,
struct ieee80211_node *);
static int ath_key_alloc(struct ieee80211vap *,
const struct ieee80211_key *,
struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
static int ath_key_delete(struct ieee80211vap *,
const struct ieee80211_key *);
@ -2387,7 +2387,7 @@ key_alloc_single(struct ath_softc *sc,
* 64 entries.
*/
static int
ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k,
ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;

View File

@ -59,7 +59,7 @@ static const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX];
* Default "null" key management routines.
*/
static int
null_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k,
null_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
if (!(&vap->iv_nw_keys[0] <= k &&
@ -116,7 +116,7 @@ cipher_attach(struct ieee80211vap *vap, struct ieee80211_key *key)
*/
static __inline int
dev_key_alloc(struct ieee80211vap *vap,
const struct ieee80211_key *key,
struct ieee80211_key *key,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
return vap->iv_key_alloc(vap, key, keyix, rxkeyix);
@ -335,15 +335,11 @@ ieee80211_crypto_newkey(struct ieee80211vap *vap,
* whether or not it needs to do the cipher work.
*/
if (key->wk_cipher != cip || key->wk_flags != flags) {
again:
/*
* Fillin the flags so cipher modules can see s/w
* crypto requirements and potentially allocate
* different state and/or attach different method
* pointers.
*
* XXX this is not right when s/w crypto fallback
* fails and we try to restore previous state.
*/
key->wk_flags = flags;
keyctx = cip->ic_attach(vap, key);
@ -372,36 +368,45 @@ again:
* cipher template. Note also that when using software
* crypto we also call the driver to give us a key index.
*/
if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) {
if (!dev_key_alloc(vap, key, &keyix, &rxkeyix)) {
/*
* Driver has no room; fallback to doing crypto
* in the host. We change the flags and start the
* procedure over. If we get back here then there's
* no hope and we bail. Note that this can leave
* the key in a inconsistent state if the caller
* continues to use it.
* Unable to setup driver state.
*/
if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
vap->iv_stats.is_crypto_swfallback++;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: no h/w resources for cipher %s, "
"falling back to s/w\n", __func__,
cip->ic_name);
oflags = key->wk_flags;
flags |= IEEE80211_KEY_SWCRYPT;
if (cipher == IEEE80211_CIPHER_TKIP)
flags |= IEEE80211_KEY_SWMIC;
goto again;
}
vap->iv_stats.is_crypto_keyfail++;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: unable to setup cipher %s\n",
__func__, cip->ic_name);
return 0;
}
if (key->wk_flags != flags) {
/*
* Driver overrode flags we setup; typically because
* resources were unavailable to handle _this_ key.
* Re-attach the cipher context to allow cipher
* modules to handle differing requirements.
*/
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: driver override for cipher %s, flags "
"0x%x -> 0x%x\n", __func__, cip->ic_name,
oflags, key->wk_flags);
keyctx = cip->ic_attach(vap, key);
if (keyctx == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: unable to attach cipher %s with "
"flags 0x%x\n", __func__, cip->ic_name,
key->wk_flags);
key->wk_flags = oflags; /* restore old flags */
vap->iv_stats.is_crypto_attachfail++;
return 0;
}
cipher_detach(key);
key->wk_cipher = cip; /* XXX refcnt? */
key->wk_private = keyctx;
}
key->wk_keyix = keyix;
key->wk_rxkeyix = rxkeyix;
key->wk_flags |= IEEE80211_KEY_DEVKEY;
}
return 1;
}
@ -412,8 +417,6 @@ again:
static int
_ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
{
ieee80211_keyix keyix;
KASSERT(key->wk_cipher != NULL, ("No cipher!"));
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
@ -423,8 +426,7 @@ _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
key->wk_keylen);
keyix = key->wk_keyix;
if (keyix != IEEE80211_KEYIX_NONE) {
if (key->wk_flags & IEEE80211_KEY_DEVKEY) {
/*
* Remove hardware entry.
*/
@ -432,7 +434,7 @@ _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
if (!dev_key_delete(vap, key)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: driver did not delete key index %u\n",
__func__, keyix);
__func__, key->wk_keyix);
vap->iv_stats.is_crypto_delkey++;
/* XXX recovery? */
}
@ -492,6 +494,14 @@ ieee80211_crypto_setkey(struct ieee80211vap *vap, struct ieee80211_key *key)
key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
key->wk_keylen);
if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) {
/* XXX nothing allocated, should not happen */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: no device key setup done; should not happen!\n",
__func__);
vap->iv_stats.is_crypto_setkey_nokey++;
return 0;
}
/*
* Give cipher a chance to validate key contents.
* XXX should happen before modifying state.
@ -504,13 +514,6 @@ ieee80211_crypto_setkey(struct ieee80211vap *vap, struct ieee80211_key *key)
vap->iv_stats.is_crypto_setkey_cipher++;
return 0;
}
if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
/* XXX nothing allocated, should not happen */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: no key index; should not happen!\n", __func__);
vap->iv_stats.is_crypto_setkey_nokey++;
return 0;
}
return dev_key_set(vap, key);
}
@ -619,7 +622,7 @@ load_ucastkey(void *arg, struct ieee80211_node *ni)
if (vap->iv_state != IEEE80211_S_RUN)
return;
k = &ni->ni_ucastkey;
if (k->wk_keyix != IEEE80211_KEYIX_NONE)
if (k->wk_flags & IEEE80211_KEY_DEVKEY)
dev_key_set(vap, k);
}
@ -643,7 +646,7 @@ ieee80211_crypto_reload_keys(struct ieee80211com *ic)
continue;
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
const struct ieee80211_key *k = &vap->iv_nw_keys[i];
if (k->wk_keyix != IEEE80211_KEYIX_NONE)
if (k->wk_flags & IEEE80211_KEY_DEVKEY)
dev_key_set(vap, k);
}
}

View File

@ -75,13 +75,16 @@ struct ieee80211_key {
uint8_t wk_keylen; /* key length in bytes */
uint8_t wk_pad;
uint16_t wk_flags;
#define IEEE80211_KEY_XMIT 0x01 /* key used for xmit */
#define IEEE80211_KEY_RECV 0x02 /* key used for recv */
#define IEEE80211_KEY_GROUP 0x04 /* key used for WPA group operation */
#define IEEE80211_KEY_SWENCRYPT 0x10 /* host-based encrypt */
#define IEEE80211_KEY_SWDECRYPT 0x20 /* host-based decrypt */
#define IEEE80211_KEY_SWENMIC 0x40 /* host-based enmic */
#define IEEE80211_KEY_SWDEMIC 0x80 /* host-based demic */
#define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */
#define IEEE80211_KEY_RECV 0x0002 /* key used for recv */
#define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */
#define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */
#define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */
#define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */
#define IEEE80211_KEY_SWDEMIC 0x0080 /* host-based demic */
#define IEEE80211_KEY_DEVKEY 0x0100 /* device key request completed */
#define IEEE80211_KEY_CIPHER0 0x1000 /* cipher-specific action 0 */
#define IEEE80211_KEY_CIPHER1 0x2000 /* cipher-specific action 1 */
ieee80211_keyix wk_keyix; /* h/w key index */
ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */
uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];

View File

@ -685,7 +685,7 @@ _db_show_key(const char *tag, int ix, const struct ieee80211_key *wk)
const struct ieee80211_cipher *cip = wk->wk_cipher;
int keylen = wk->wk_keylen;
if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
if ((wk->wk_flags & IEEE80211_KEY_DEVKEY) == 0)
return;
db_printf(tag, ix);
switch (cip->ic_cipher) {

View File

@ -370,7 +370,7 @@ struct ieee80211vap {
ieee80211_keyix iv_def_txkey; /* default/group tx key index */
struct ieee80211_key iv_nw_keys[IEEE80211_WEP_NKID];
int (*iv_key_alloc)(struct ieee80211vap *,
const struct ieee80211_key *,
struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
int (*iv_key_delete)(struct ieee80211vap *,
const struct ieee80211_key *);