diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 5ea073290e2c..bb2a02471f54 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -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); diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index a5f97642bc54..1db66e039856 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -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); +} diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h index 0db2949081ba..3cbceec337d3 100644 --- a/sys/net80211/ieee80211_crypto.h +++ b/sys/net80211/ieee80211_crypto.h @@ -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 diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 3a797d8175af..c8d640d0670c 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -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; diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 358f2601188a..fa1d18e001c3 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -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);