diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c --- a/sys/dev/ath/if_ath_keycache.c +++ b/sys/dev/ath/if_ath_keycache.c @@ -201,6 +201,16 @@ int ret; memset(&hk, 0, sizeof(hk)); + + /* + * If it's a IGTK key then just plain ignore it; + * it's already marked as handled in software and we don't + * need a keycache entry for it. + */ + if (ieee80211_is_key_igtk(vap, k)) { + return (1); + } + /* * Software crypto uses a "clear key" so non-crypto * state kept in the key cache are maintained and @@ -431,6 +441,19 @@ * multi-station operation. */ if (k->wk_keyix != IEEE80211_KEYIX_NONE) { + + /* + * Skip IGTK keys; they're global but not used + * in the normal hardware keyix slots. + */ + if (ieee80211_is_key_igtk(vap, k)) { + DPRINTF(sc, ATH_DEBUG_KEYCACHE, + "%s: iGTK key; skipping\n", __func__); + *keyix = *rxkeyix = + ieee80211_crypto_get_key_igtk_idx(vap, k); + return 1; + } + /* * Only global keys should have key index assigned. */ @@ -440,6 +463,9 @@ "%s: bogus group key\n", __func__); return 0; } + + /* TODO: bogus BIP key */ + if (vap->iv_opmode != IEEE80211_M_HOSTAP || !(k->wk_flags & IEEE80211_KEY_GROUP) || !sc->sc_mcastkey) { @@ -501,7 +527,17 @@ if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) ath_hal_keyreset(ah, keyix+32); /* RX key */ - if (keyix >= IEEE80211_WEP_NKID) { + + /* + * Skip BIP keys; key indexes 4 and 5 are valid non-global + * keycache entries + */ + if (ieee80211_is_key_igtk(vap, k)) { + DPRINTF(sc, ATH_DEBUG_KEYCACHE, + "%s: keyix=%d but igtk key; skipping\n", + __func__, + keyix); + } else if (keyix >= IEEE80211_WEP_NKID) { /* * Don't touch keymap entries for global keys so * they are never considered for dynamic allocation. diff --git a/sys/dev/rtwn/if_rtwn_cam.c b/sys/dev/rtwn/if_rtwn_cam.c --- a/sys/dev/rtwn/if_rtwn_cam.c +++ b/sys/dev/rtwn/if_rtwn_cam.c @@ -185,11 +185,34 @@ uint8_t algo, keyid; int i, error; + + /* + * TODO: what about IGTK keys (4, 5) ? Would they allocated + * as "real" keycache entries? + */ + + /* + * TODO: I likely need to clean up by introducing + * "are these WEP group keys" and "are these IGTK group keys" + * inline functions and use them here, not the wk_keyix thing). + */ + if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && - k->wk_keyix < IEEE80211_WEP_NKID) + k->wk_keyix < IEEE80211_WEP_NKID) { + keyid = k->wk_keyix; + } else if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && + k->wk_flags & IEEE80211_KEY_GROUP) { keyid = k->wk_keyix; - else + } else if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && + (k->wk_flags & (IEEE80211_KEY_GROUP | IEEE80211_KEY_IGTK)) && + (k->wk_keyix == 4 || k->wk_keyix == 5)) { + device_printf(sc->sc_dev, "%s: got group key idx 4/5? (%d) (flags=0x%08x)\n", + __func__, k->wk_keyix, k->wk_flags); keyid = 0; + } else { + keyid = 0; + } + /* Map net80211 cipher to HW crypto algorithm. */ switch (k->wk_cipher->ic_cipher) { diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h --- a/sys/net80211/ieee80211.h +++ b/sys/net80211/ieee80211.h @@ -1472,7 +1472,9 @@ #define IEEE80211_WEP_TOTLEN (IEEE80211_WEP_IVLEN + \ IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN) -#define IEEE80211_WEP_NKID 4 /* number of key ids */ +#define IEEE80211_WEP_NKID 4 /* number of WEP/global key ids */ +#define IEEE80211_MAX_NKID 6 /* number of WEP/global/iGTK key ids */ +#define IEEE80211_IGTK_NKID 2 /* number of iGTK key IDs */ /* * 802.11i defines an extended IV for use with non-WEP ciphers. diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -2693,6 +2693,7 @@ ieee80211_is_key_global(const struct ieee80211vap *vap, const struct ieee80211_key *key) { + return (&vap->iv_nw_keys[0] <= key && key < &vap->iv_nw_keys[IEEE80211_WEP_NKID]); } @@ -2705,7 +2706,9 @@ ieee80211_is_key_igtk(const struct ieee80211vap *vap, const struct ieee80211_key *key) { - return false; + + /* TODO: don't hard-code these two key indexes? */ + return (key == &vap->iv_nw_keys[4] || key == &vap->iv_nw_keys[5]); } /* @@ -2715,10 +2718,7 @@ ieee80211_is_key_unicast(const struct ieee80211vap *vap, const struct ieee80211_key *key) { - /* - * This is a short-cut for now; eventually we will need - * to support multiple unicast keys, IGTK, etc) so we - * will absolutely need to fix the key flags. - */ - return (!ieee80211_is_key_global(vap, key)); + + return (!(ieee80211_is_key_global(vap, key) + || ieee80211_is_key_igtk(vap, key))); } diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h --- a/sys/net80211/ieee80211_crypto.h +++ b/sys/net80211/ieee80211_crypto.h @@ -91,6 +91,7 @@ #define IEEE80211_KEY_NOIVMGT 0x00008000 /* don't insert IV/MIC for mgmt */ #define IEEE80211_KEY_NOMIC 0x00010000 /* don't insert MIC for !mgmt */ #define IEEE80211_KEY_NOMICMGT 0x00020000 /* don't insert MIC for mgmt */ +#define IEEE80211_KEY_IGTK 0x00040000 /* key is used for IGTK */ ieee80211_keyix wk_keyix; /* h/w key index */ ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */ @@ -106,7 +107,7 @@ }; #define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP | \ - IEEE80211_KEY_NOREPLAY) + IEEE80211_KEY_NOREPLAY | IEEE80211_KEY_IGTK) #define IEEE80211_KEY_SWCRYPT \ (IEEE80211_KEY_SWENCRYPT | IEEE80211_KEY_SWDECRYPT) @@ -231,6 +232,8 @@ int ieee80211_crypto_get_key_wepidx(const struct ieee80211vap *, const struct ieee80211_key *k); +int ieee80211_crypto_get_key_igtk_idx(const struct ieee80211vap *, + const struct ieee80211_key *k); uint8_t ieee80211_crypto_get_keyid(struct ieee80211vap *vap, struct ieee80211_key *k); struct ieee80211_key *ieee80211_crypto_get_txkey(struct ieee80211_node *, diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -41,6 +41,7 @@ #include #include +#include /* ic_printf */ #include /* XXX ETHER_HDR_LEN */ #include @@ -231,9 +232,11 @@ /* NB: we assume everything is pre-zero'd */ vap->iv_max_keyix = IEEE80211_WEP_NKID; vap->iv_def_txkey = IEEE80211_KEYIX_NONE; - for (i = 0; i < IEEE80211_WEP_NKID; i++) + + for (i = 0; i < IEEE80211_MAX_NKID; i++) ieee80211_crypto_resetkey(vap, &vap->iv_nw_keys[i], IEEE80211_KEYIX_NONE); + /* * Initialize the driver key support routines to noop entries. * This is useful especially for the cipher test modules. @@ -546,7 +549,7 @@ int i; ieee80211_key_update_begin(vap); - for (i = 0; i < IEEE80211_WEP_NKID; i++) + for (i = 0; i < IEEE80211_MAX_NKID; i++) (void) _ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[i]); ieee80211_key_update_end(vap); } @@ -613,6 +616,28 @@ } /* + * Return index if the key is an IGTK key (4..5); -1 otherwise. + * + * This is different to "get_keyid" which defaults to returning + * 0 for unicast keys; it assumes that it won't be used for WEP. + */ +int +ieee80211_crypto_get_key_igtk_idx(const struct ieee80211vap *vap, + const struct ieee80211_key *k) +{ + if (ieee80211_is_key_igtk(vap, k)) { + /* XXX TODO: i hate this */ + return (k - vap->iv_nw_keys); + } + + return (-1); +} + +/* + * Return the group or unicast key. + * + * Don't call this for IGTK keyx! + * * Note: only supports a single unicast key (0). */ uint8_t @@ -622,6 +647,16 @@ return (k - vap->iv_nw_keys); } + /* + * TODO: I wish this function could return an error, + * but then I'd have to audit all the places that called it + * and make sure THEY can handle the error! + */ + if (ieee80211_is_key_igtk(vap, k)) { + if_printf(vap->iv_ifp, "%s: IGTK key passed in! Invalid!\n", + __func__); + } + return (0); } @@ -857,11 +892,16 @@ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { if (vap->iv_state != IEEE80211_S_RUN) continue; + + /* Global/WEP keys */ for (i = 0; i < IEEE80211_WEP_NKID; i++) { const struct ieee80211_key *k = &vap->iv_nw_keys[i]; if (k->wk_flags & IEEE80211_KEY_DEVKEY) dev_key_set(vap, k); } + + /* TODO: do the two iGTK keys too if the driver supports it? */ + /* (The drivers will need to be made aware of the other two KIDs and ignore them if needed..) */ } /* * Unicast keys. diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c --- a/sys/net80211/ieee80211_ddb.c +++ b/sys/net80211/ieee80211_ddb.c @@ -604,7 +604,7 @@ db_printf("\tmax_keyix %u", vap->iv_max_keyix); db_printf(" def_txkey %d", vap->iv_def_txkey); db_printf("\n"); - for (i = 0; i < IEEE80211_WEP_NKID; i++) + for (i = 0; i < IEEE80211_MAX_NKID; i++) _db_show_key("\tnw_keys[%u]", i, &vap->iv_nw_keys[i]); db_printf("\tauth %p(%s)", vap->iv_auth, vap->iv_auth->ia_name); diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -93,7 +93,7 @@ return ENOENT; wk = &ni->ni_ucastkey; } else { - if (kid >= IEEE80211_WEP_NKID) + if (kid >= IEEE80211_MAX_NKID) return EINVAL; wk = &vap->iv_nw_keys[kid]; IEEE80211_ADDR_COPY(&ik.ik_macaddr, vap->iv_bss->ni_macaddr); @@ -1177,8 +1177,8 @@ case IEEE80211_MFP_PROTMODE_REQUIRED: ireq->i_val = IEEE80211_MFP_REQUIRED; break; - } - break; + } + break; case IEEE80211_IOC_VHTCONF: ireq->i_val = vap->iv_vht_flags & IEEE80211_FVHT_MASK; break; @@ -1227,7 +1227,7 @@ } wk = &ni->ni_ucastkey; } else { - if (kid >= IEEE80211_WEP_NKID) + if (kid >= IEEE80211_MAX_NKID) return EINVAL; wk = &vap->iv_nw_keys[kid]; /* @@ -1327,7 +1327,7 @@ ieee80211_node_delucastkey(ni); ieee80211_free_node(ni); } else { - if (kid >= IEEE80211_WEP_NKID) + if (kid >= IEEE80211_MAX_NKID) return EINVAL; /* XXX error return */ ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[kid]); diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -509,7 +509,7 @@ /* 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]; + struct ieee80211_key iv_nw_keys[IEEE80211_MAX_NKID]; int (*iv_key_alloc)(struct ieee80211vap *, struct ieee80211_key *, ieee80211_keyix *, ieee80211_keyix *);