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 *, static int ath_keyset(struct ath_softc *, const struct ieee80211_key *,
struct ieee80211_node *); struct ieee80211_node *);
static int ath_key_alloc(struct ieee80211vap *, static int ath_key_alloc(struct ieee80211vap *,
const struct ieee80211_key *, struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *); ieee80211_keyix *, ieee80211_keyix *);
static int ath_key_delete(struct ieee80211vap *, static int ath_key_delete(struct ieee80211vap *,
const struct ieee80211_key *); const struct ieee80211_key *);
@ -2387,7 +2387,7 @@ key_alloc_single(struct ath_softc *sc,
* 64 entries. * 64 entries.
*/ */
static int 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) ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{ {
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; 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. * Default "null" key management routines.
*/ */
static int 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) ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{ {
if (!(&vap->iv_nw_keys[0] <= k && if (!(&vap->iv_nw_keys[0] <= k &&
@ -116,7 +116,7 @@ cipher_attach(struct ieee80211vap *vap, struct ieee80211_key *key)
*/ */
static __inline int static __inline int
dev_key_alloc(struct ieee80211vap *vap, dev_key_alloc(struct ieee80211vap *vap,
const struct ieee80211_key *key, struct ieee80211_key *key,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{ {
return vap->iv_key_alloc(vap, key, 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. * whether or not it needs to do the cipher work.
*/ */
if (key->wk_cipher != cip || key->wk_flags != flags) { if (key->wk_cipher != cip || key->wk_flags != flags) {
again:
/* /*
* Fillin the flags so cipher modules can see s/w * Fillin the flags so cipher modules can see s/w
* crypto requirements and potentially allocate * crypto requirements and potentially allocate
* different state and/or attach different method * different state and/or attach different method
* pointers. * pointers.
*
* XXX this is not right when s/w crypto fallback
* fails and we try to restore previous state.
*/ */
key->wk_flags = flags; key->wk_flags = flags;
keyctx = cip->ic_attach(vap, key); keyctx = cip->ic_attach(vap, key);
@ -372,36 +368,45 @@ again:
* cipher template. Note also that when using software * cipher template. Note also that when using software
* crypto we also call the driver to give us a key index. * 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)) { if (!dev_key_alloc(vap, key, &keyix, &rxkeyix)) {
/* /*
* Driver has no room; fallback to doing crypto * Unable to setup driver state.
* 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.
*/ */
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++; vap->iv_stats.is_crypto_keyfail++;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: unable to setup cipher %s\n", "%s: unable to setup cipher %s\n",
__func__, cip->ic_name); __func__, cip->ic_name);
return 0; 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_keyix = keyix;
key->wk_rxkeyix = rxkeyix; key->wk_rxkeyix = rxkeyix;
key->wk_flags |= IEEE80211_KEY_DEVKEY;
} }
return 1; return 1;
} }
@ -412,8 +417,6 @@ again:
static int static int
_ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key) _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
{ {
ieee80211_keyix keyix;
KASSERT(key->wk_cipher != NULL, ("No cipher!")); KASSERT(key->wk_cipher != NULL, ("No cipher!"));
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, 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_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
key->wk_keylen); key->wk_keylen);
keyix = key->wk_keyix; if (key->wk_flags & IEEE80211_KEY_DEVKEY) {
if (keyix != IEEE80211_KEYIX_NONE) {
/* /*
* Remove hardware entry. * Remove hardware entry.
*/ */
@ -432,7 +434,7 @@ _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
if (!dev_key_delete(vap, key)) { if (!dev_key_delete(vap, key)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
"%s: driver did not delete key index %u\n", "%s: driver did not delete key index %u\n",
__func__, keyix); __func__, key->wk_keyix);
vap->iv_stats.is_crypto_delkey++; vap->iv_stats.is_crypto_delkey++;
/* XXX recovery? */ /* 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_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
key->wk_keylen); 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. * Give cipher a chance to validate key contents.
* XXX should happen before modifying state. * 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++; vap->iv_stats.is_crypto_setkey_cipher++;
return 0; 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); 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) if (vap->iv_state != IEEE80211_S_RUN)
return; return;
k = &ni->ni_ucastkey; k = &ni->ni_ucastkey;
if (k->wk_keyix != IEEE80211_KEYIX_NONE) if (k->wk_flags & IEEE80211_KEY_DEVKEY)
dev_key_set(vap, k); dev_key_set(vap, k);
} }
@ -643,7 +646,7 @@ ieee80211_crypto_reload_keys(struct ieee80211com *ic)
continue; continue;
for (i = 0; i < IEEE80211_WEP_NKID; i++) { for (i = 0; i < IEEE80211_WEP_NKID; i++) {
const struct ieee80211_key *k = &vap->iv_nw_keys[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); 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_keylen; /* key length in bytes */
uint8_t wk_pad; uint8_t wk_pad;
uint16_t wk_flags; uint16_t wk_flags;
#define IEEE80211_KEY_XMIT 0x01 /* key used for xmit */ #define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */
#define IEEE80211_KEY_RECV 0x02 /* key used for recv */ #define IEEE80211_KEY_RECV 0x0002 /* key used for recv */
#define IEEE80211_KEY_GROUP 0x04 /* key used for WPA group operation */ #define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */
#define IEEE80211_KEY_SWENCRYPT 0x10 /* host-based encrypt */ #define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */
#define IEEE80211_KEY_SWDECRYPT 0x20 /* host-based decrypt */ #define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */
#define IEEE80211_KEY_SWENMIC 0x40 /* host-based enmic */ #define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */
#define IEEE80211_KEY_SWDEMIC 0x80 /* host-based demic */ #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_keyix; /* h/w key index */
ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */ ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */
uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE]; 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; const struct ieee80211_cipher *cip = wk->wk_cipher;
int keylen = wk->wk_keylen; int keylen = wk->wk_keylen;
if (wk->wk_keyix == IEEE80211_KEYIX_NONE) if ((wk->wk_flags & IEEE80211_KEY_DEVKEY) == 0)
return; return;
db_printf(tag, ix); db_printf(tag, ix);
switch (cip->ic_cipher) { switch (cip->ic_cipher) {

View File

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