[net80211] turn the default TX key configuration (for WEP) into a vap callback.

The ath10k firmware supports hardware WEP offload, and in native wifi mode
(or 802.3 ethernet mode, for that matter) the WEP key isn't actually included
in the TX payload from net80211.  Instead, a separate firmware command is issued
that sets the default TX key to be the specified key.

However, net80211 doesn't at all inform the driver layer that this is
occuring - it just "expects" to be inserting WEP header information
when doing WEP TX, even with hardware encryption.

So, to better support the newer world order, turn the default TX key assignment
into a VAP method that can be overridden by the driver and ensure its wrapped
in a crypto begin/end set.  That way it should be correctly atomic from the
point of view of keychanges (as long as the driver does the right thing.)

It'd be nice if we passed through to the key_set call a flag that says
"also make this the default key" - that's captured here by calling the
deftxkey method after the key_set method.  Maybe I can do that later.

Note: this is a net80211 ABI change, and will require a kernel+modules
recompile.  Happy Holidays, etc.

Tested:

* ath10k driver port
* rtwn_usb, WEP station
This commit is contained in:
adrian 2016-12-27 06:10:28 +00:00
parent 5e2d367430
commit 890beb4f2b
5 changed files with 69 additions and 2 deletions

View File

@ -432,6 +432,22 @@ default_reset(struct ieee80211vap *vap, u_long cmd)
return ENETRESET;
}
/*
* Default for updating the VAP default TX key index.
*
* Drivers that support TX offload as well as hardware encryption offload
* may need to be informed of key index changes separate from the key
* update.
*/
static void
default_update_deftxkey(struct ieee80211vap *vap, ieee80211_keyix kid)
{
/* XXX assert validity */
/* XXX assert we're in a key update block */
vap->iv_def_txkey = kid;
}
/*
* Add underlying device errors to vap errors.
*/
@ -561,6 +577,12 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
*/
vap->iv_reset = default_reset;
/*
* Install a default crypto key update method, the driver
* can override this.
*/
vap->iv_update_deftxkey = default_update_deftxkey;
ieee80211_sysctl_vattach(vap);
ieee80211_crypto_vattach(vap);
ieee80211_node_vattach(vap);

View File

@ -787,3 +787,18 @@ ieee80211_crypto_reload_keys(struct ieee80211com *ic)
*/
ieee80211_iterate_nodes(&ic->ic_sta, load_ucastkey, NULL);
}
/*
* Set the default key index for WEP, or KEYIX_NONE for no default TX key.
*
* This should be done as part of a key update block (iv_key_update_begin /
* iv_key_update_end.)
*/
void
ieee80211_crypto_set_deftxkey(struct ieee80211vap *vap, ieee80211_keyix kid)
{
/* XXX TODO: assert we're in a key update block */
vap->iv_update_deftxkey(vap, kid);
}

View File

@ -171,6 +171,8 @@ int ieee80211_crypto_delkey(struct ieee80211vap *,
int ieee80211_crypto_setkey(struct ieee80211vap *, struct ieee80211_key *);
void ieee80211_crypto_delglobalkeys(struct ieee80211vap *);
void ieee80211_crypto_reload_keys(struct ieee80211com *);
void ieee80211_crypto_set_deftxkey(struct ieee80211vap *,
ieee80211_keyix kid);
/*
* Template for a supported cipher. Ciphers register with the

View File

@ -855,6 +855,8 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
* Tx power limit is the min of max regulatory
* power, any user-set limit, and the max the
* radio can do.
*
* TODO: methodize this
*/
ireq->i_val = 2*ic->ic_curchan->ic_maxregpower;
if (ireq->i_val > ic->ic_txpowlimit)
@ -1013,6 +1015,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
ireq->i_val |= 2;
break;
case IEEE80211_IOC_AMPDU_LIMIT:
/* XXX TODO: make this a per-node thing; and leave this as global */
if (vap->iv_opmode == IEEE80211_M_HOSTAP)
ireq->i_val = vap->iv_ampdu_rxmax;
else if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)
@ -1026,6 +1029,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
ireq->i_val = vap->iv_ampdu_limit;
break;
case IEEE80211_IOC_AMPDU_DENSITY:
/* XXX TODO: make this a per-node thing; and leave this as global */
if (vap->iv_opmode == IEEE80211_M_STA &&
(vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP))
/*
@ -1204,7 +1208,15 @@ ieee80211_ioctl_setkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
if (!ieee80211_crypto_setkey(vap, wk))
error = EIO;
else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT))
vap->iv_def_txkey = kid;
/*
* Inform the driver that this is the default
* transmit key. Now, ideally we'd just set
* a flag in the key update that would
* say "yes, we're the default key", but
* that currently isn't the way the ioctl ->
* key interface works.
*/
ieee80211_crypto_set_deftxkey(vap, kid);
} else
error = ENXIO;
ieee80211_key_update_end(vap);
@ -2687,7 +2699,17 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
if (kid >= IEEE80211_WEP_NKID &&
(uint16_t) kid != IEEE80211_KEYIX_NONE)
return EINVAL;
vap->iv_def_txkey = kid;
/*
* Firmware devices may need to be told about an explicit
* key index here, versus just inferring it from the
* key set / change. Since we may also need to pause
* things like transmit before the key is updated,
* give the driver a chance to flush things by tying
* into key update begin/end.
*/
ieee80211_key_update_begin(vap);
ieee80211_crypto_set_deftxkey(vap, kid);
ieee80211_key_update_end(vap);
break;
case IEEE80211_IOC_AUTHMODE:
switch (ireq->i_val) {
@ -3094,6 +3116,7 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
error = ERESTART;
break;
case IEEE80211_IOC_AMPDU_LIMIT:
/* XXX TODO: figure out ampdu_limit versus ampdu_rxmax */
if (!(IEEE80211_HTCAP_MAXRXAMPDU_8K <= ireq->i_val &&
ireq->i_val <= IEEE80211_HTCAP_MAXRXAMPDU_64K))
return EINVAL;

View File

@ -470,6 +470,8 @@ struct ieee80211vap {
struct ieee80211_appie *iv_appie_wpa;
uint8_t *iv_wpa_ie;
uint8_t *iv_rsn_ie;
/* Key management */
uint16_t iv_max_keyix; /* max h/w key index */
ieee80211_keyix iv_def_txkey; /* default/group tx key index */
struct ieee80211_key iv_nw_keys[IEEE80211_WEP_NKID];
@ -482,6 +484,8 @@ struct ieee80211vap {
const struct ieee80211_key *);
void (*iv_key_update_begin)(struct ieee80211vap *);
void (*iv_key_update_end)(struct ieee80211vap *);
void (*iv_update_deftxkey)(struct ieee80211vap *,
ieee80211_keyix deftxkey);
const struct ieee80211_authenticator *iv_auth; /* authenticator glue */
void *iv_ec; /* private auth state */
@ -536,6 +540,7 @@ struct ieee80211vap {
/* 802.3 output method for raw frame xmit */
int (*iv_output)(struct ifnet *, struct mbuf *,
const struct sockaddr *, struct route *);
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);