Exemple #1
0
/*
 * 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;
}
Exemple #2
0
/*
 * 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
}