/* * Establish a relationship between the specified key and cipher * and, if necessary, allocate a hardware index from the driver. * Note that when a fixed key index is required it must be specified. * * This must be the first call applied to a key; all the other key * routines assume wk_cipher is setup. * * Locking must be handled by the caller using: * ieee80211_key_update_begin(vap); * ieee80211_key_update_end(vap); */ int ieee80211_crypto_newkey(struct ieee80211vap *vap, int cipher, int flags, struct ieee80211_key *key) { struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_cipher *cip; ieee80211_keyix keyix, rxkeyix; void *keyctx; int oflags; IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: cipher %u flags 0x%x keyix %u\n", __func__, cipher, flags, key->wk_keyix); /* * Validate cipher and set reference to cipher routines. */ if (cipher >= IEEE80211_CIPHER_MAX) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: invalid cipher %u\n", __func__, cipher); vap->iv_stats.is_crypto_badcipher++; return 0; } cip = ciphers[cipher]; if (cip == NULL) { /* * Auto-load cipher module if we have a well-known name * for it. It might be better to use string names rather * than numbers and craft a module name based on the cipher * name; e.g. wlan_cipher_<cipher-name>. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: unregistered cipher %u, load module %s\n", __func__, cipher, cipher_modnames[cipher]); ieee80211_load_module(cipher_modnames[cipher]); /* * If cipher module loaded it should immediately * call ieee80211_crypto_register which will fill * in the entry in the ciphers array. */ cip = ciphers[cipher]; if (cip == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: unable to load cipher %u, module %s\n", __func__, cipher, cipher_modnames[cipher]); vap->iv_stats.is_crypto_nocipher++; return 0; } } oflags = key->wk_flags; flags &= IEEE80211_KEY_COMMON; /* NB: preserve device attributes */ flags |= (oflags & IEEE80211_KEY_DEVICE); /* * If the hardware does not support the cipher then * fallback to a host-based implementation. */ if ((ic->ic_cryptocaps & (1<<cipher)) == 0) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: no h/w support for cipher %s, falling back to s/w\n", __func__, cip->ic_name); flags |= IEEE80211_KEY_SWCRYPT; } /* * Hardware TKIP with software MIC is an important * combination; we handle it by flagging each key, * the cipher modules honor it. */ if (cipher == IEEE80211_CIPHER_TKIP && (ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIPMIC) == 0) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: no h/w support for TKIP MIC, falling back to s/w\n", __func__); flags |= IEEE80211_KEY_SWMIC; } /* * Bind cipher to key instance. Note we do this * after checking the device capabilities so the * cipher module can optimize space usage based on * whether or not it needs to do the cipher work. */ if (key->wk_cipher != cip || key->wk_flags != flags) { /* * Fillin the flags so cipher modules can see s/w * crypto requirements and potentially allocate * different state and/or attach different method * pointers. */ key->wk_flags = flags; keyctx = cip->ic_attach(vap, key); if (keyctx == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: unable to attach cipher %s\n", __func__, cip->ic_name); 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; } /* * Ask the driver for a key index if we don't have one. * Note that entries in the global key table always have * an index; this means it's safe to call this routine * for these entries just to setup the reference to the * cipher template. Note also that when using software * crypto we also call the driver to give us a key index. */ if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) { if (!dev_key_alloc(vap, key, &keyix, &rxkeyix)) { /* * Unable to setup driver state. */ 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; }
/* * Establish a relationship between the specified key and cipher * and, if necessary, allocate a hardware index from the driver. * Note that when a fixed key index is required it must be specified * and we blindly assign it w/o consulting the driver (XXX). * * This must be the first call applied to a key; all the other key * routines assume wk_cipher is setup. * * Locking must be handled by the caller using: * ieee80211_key_update_begin(ic); * ieee80211_key_update_end(ic); */ int ieee80211_crypto_newkey(struct ieee80211com *ic, int cipher, int flags, struct ieee80211_key *key) { #define N(a) (sizeof(a) / sizeof(a[0])) const struct ieee80211_cipher *cip; ieee80211_keyix keyix, rxkeyix; void *keyctx; int oflags; /* * Validate cipher and set reference to cipher routines. */ if (cipher >= IEEE80211_CIPHER_MAX) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: invalid cipher %u\n", __func__, cipher); ic->ic_stats.is_crypto_badcipher++; return 0; } cip = ciphers[cipher]; if (cip == NULL) { /* * Auto-load cipher module if we have a well-known name * for it. It might be better to use string names rather * than numbers and craft a module name based on the cipher * name; e.g. wlan_cipher_<cipher-name>. */ if (cipher < N(cipher_modnames)) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: unregistered cipher %u, load module %s\n", __func__, cipher, cipher_modnames[cipher]); ieee80211_load_module(cipher_modnames[cipher]); /* * If cipher module loaded it should immediately * call ieee80211_crypto_register which will fill * in the entry in the ciphers array. */ cip = ciphers[cipher]; } if (cip == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: unable to load cipher %u, module %s\n", __func__, cipher, cipher < N(cipher_modnames) ? cipher_modnames[cipher] : "<unknown>"); ic->ic_stats.is_crypto_nocipher++; return 0; } } oflags = key->wk_flags; flags &= IEEE80211_KEY_COMMON; /* * If the hardware does not support the cipher then * fallback to a host-based implementation. */ if ((ic->ic_caps & (1<<cipher)) == 0) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: no h/w support for cipher %s, falling back to s/w\n", __func__, cip->ic_name); flags |= IEEE80211_KEY_SWCRYPT; } /* * Hardware TKIP with software MIC is an important * combination; we handle it by flagging each key, * the cipher modules honor it. */ if (cipher == IEEE80211_CIPHER_TKIP && (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: no h/w support for TKIP MIC, falling back to s/w\n", __func__); flags |= IEEE80211_KEY_SWMIC; } /* * Bind cipher to key instance. Note we do this * after checking the device capabilities so the * cipher module can optimize space usage based on * 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(ic, key); if (keyctx == NULL) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: unable to attach cipher %s\n", __func__, cip->ic_name); key->wk_flags = oflags; /* restore old flags */ ic->ic_stats.is_crypto_attachfail++; return 0; } cipher_detach(key); key->wk_cipher = cip; /* XXX refcnt? */ key->wk_private = keyctx; } /* * Commit to requested usage so driver can see the flags. */ key->wk_flags = flags; /* * Ask the driver for a key index if we don't have one. * Note that entries in the global key table always have * an index; this means it's safe to call this routine * for these entries just to setup the reference to the * 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 (!dev_key_alloc(ic, 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. */ if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { ic->ic_stats.is_crypto_swfallback++; IEEE80211_DPRINTF(ic, 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; } ic->ic_stats.is_crypto_keyfail++; IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, "%s: unable to setup cipher %s\n", __func__, cip->ic_name); return 0; } key->wk_keyix = keyix; key->wk_rxkeyix = rxkeyix; } return 1; #undef N }