diff options
author | avatar <avatar@FreeBSD.org> | 2005-10-02 04:29:08 +0000 |
---|---|---|
committer | avatar <avatar@FreeBSD.org> | 2005-10-02 04:29:08 +0000 |
commit | 21345d1652e54640c8a244f7f75717f7078e5a01 (patch) | |
tree | 8cee6fb67928c9283242338c92e994b82976bae2 /sys | |
parent | 4aac14991941450642bcd39207147b5502a195d1 (diff) | |
download | FreeBSD-src-21345d1652e54640c8a244f7f75717f7078e5a01.zip FreeBSD-src-21345d1652e54640c8a244f7f75717f7078e5a01.tar.gz |
Fixing WEP bustage in hostap mode since 5.2-RELEASE.
- WEP TX fix:
The original code called software crypto, ieee80211_crypto_encap(),
which never worked since IEEE80211_KEY_SWCRYPT was never flagged due to
ieee80211_crypto_newkey() assumes that wi always supports hardware based
crypto regardless of operational mode(by virtue of IEEE80211_C_WEP).
This fix works around that issue by adding wi_key_alloc() to force
the use of s/w crypto. Also if anyone ever decides to cleanup ioctl
handling where key changes wouldn't cause a call to wi_init() every time,
we'll need wi_key_alloc() to DTRT.
In addition to that, this fix also adds code to wi_write_wep() to force
existing keys to be switched between h/w and s/w crypto such that an
operation mode change(sta <-> hostap) will flag IEEE80211_KEY_SWCRYPT
properly.
- WEP RX fix:
Clear IEEE80211_F_DROPUNENC even in hostap mode. Quote from Sam:
"This is really gross but I don't see an easy way around it.
By doing it we lose the ability to independently drop unencode
frames (and support mixed wep/!wep use). We should really be
setting the EXCLUDE_UNENCRYPTED flag written in wi_write_wep
based on IEEE80211_F_DROPUNENC but with our clearing it we can't
depend on it being set properly."
Reported by: Holm Tiffe <holm at freibergnet dot de>
Submitted by: sam
MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/wi/if_wi.c | 70 | ||||
-rw-r--r-- | sys/dev/wi/if_wivar.h | 4 |
2 files changed, 59 insertions, 15 deletions
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index a2cb03b..43c9a5d 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -126,6 +126,9 @@ static void wi_tx_intr(struct wi_softc *); static void wi_tx_ex_intr(struct wi_softc *); static void wi_info_intr(struct wi_softc *); +static int wi_key_alloc(struct ieee80211com *, const struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); + static int wi_get_cfg(struct ifnet *, u_long, caddr_t); static int wi_set_cfg(struct ifnet *, u_long, caddr_t); static int wi_write_txrate(struct wi_softc *); @@ -485,6 +488,8 @@ wi_attach(device_t dev) ieee80211_ifattach(ic); /* override state transition method */ sc->sc_newstate = ic->ic_newstate; + sc->sc_key_alloc = ic->ic_crypto.cs_key_alloc; + ic->ic_crypto.cs_key_alloc = wi_key_alloc; ic->ic_newstate = wi_newstate; ieee80211_media_init(ic, wi_media_change, wi_media_status); @@ -764,7 +769,8 @@ wi_init(void *arg) if (ic->ic_caps & IEEE80211_C_WEP) { sc->sc_cnfauthmode = ic->ic_bss->ni_authmode; wi_write_wep(sc); - } + } else + sc->sc_encryption = 0; /* Set multicast filter. */ wi_write_multi(sc); @@ -965,8 +971,8 @@ wi_start(struct ifnet *ifp) #endif frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX); /* XXX check key for SWCRYPT instead of using operating mode */ - if (ic->ic_opmode == IEEE80211_M_HOSTAP && - (wh->i_fc[1] & IEEE80211_FC1_WEP)) { + if ((wh->i_fc[1] & IEEE80211_FC1_WEP) && + (sc->sc_encryption & HOST_ENCRYPT)) { struct ieee80211_key *k; k = ieee80211_crypto_encap(ic, ni, m0); @@ -2330,6 +2336,24 @@ wi_write_txrate(struct wi_softc *sc) } static int +wi_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct wi_softc *sc = ic->ic_ifp->if_softc; + + /* + * When doing host encryption of outbound frames fail requests + * for keys that are not marked w/ the SWCRYPT flag so the + * net80211 layer falls back to s/w crypto. Note that we also + * fixup existing keys below to handle mode changes. + */ + if ((sc->sc_encryption & HOST_ENCRYPT) && + (k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) + return 0; + return sc->sc_key_alloc(ic, k, keyix, rxkeyix); +} + +static int wi_write_wep(struct wi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -2358,6 +2382,7 @@ wi_write_wep(struct wi_softc *sc) } error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS, wkey, sizeof(wkey)); + sc->sc_encryption = 0; break; case WI_INTERSIL: @@ -2379,6 +2404,7 @@ wi_write_wep(struct wi_softc *sc) } wi_write_val(sc, WI_RID_CNFAUTHMODE, sc->sc_cnfauthmode); + /* XXX should honor IEEE80211_F_DROPUNENC */ val = PRIVACY_INVOKED | EXCLUDE_UNENCRYPTED; /* * Encryption firmware has a bug for HostAP mode. @@ -2394,6 +2420,7 @@ wi_write_wep(struct wi_softc *sc) error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val); if (error) break; + sc->sc_encryption = val; if ((val & PRIVACY_INVOKED) == 0) break; error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY, @@ -2424,6 +2451,19 @@ wi_write_wep(struct wi_softc *sc) } break; } + /* + * XXX horrible hack; insure pre-existing keys are + * setup properly to do s/w crypto. + */ + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + struct ieee80211_key *k = &ic->ic_nw_keys[i]; + if (k->wk_flags & IEEE80211_KEY_XMIT) { + if (sc->sc_encryption & HOST_ENCRYPT) + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + else + k->wk_flags &= ~IEEE80211_KEY_SWCRYPT; + } + } return error; } @@ -2741,19 +2781,19 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = htole16(ni->ni_chan->ic_flags); #endif + /* + * XXX hack; unceremoniously clear + * IEEE80211_F_DROPUNENC when operating with + * wep enabled so we don't drop unencoded frames + * at the 802.11 layer. This is necessary because + * we must strip the WEP bit from the 802.11 header + * before passing frames to ieee80211_input because + * the card has already stripped the WEP crypto + * header from the packet. + */ + if (ic->ic_flags & IEEE80211_F_PRIVACY) + ic->ic_flags &= ~IEEE80211_F_DROPUNENC; if (ic->ic_opmode != IEEE80211_M_HOSTAP) { - /* - * XXX hack; unceremoniously clear - * IEEE80211_F_DROPUNENC when operating with - * wep enabled so we don't drop unencoded frames - * at the 802.11 layer. This is necessary because - * we must strip the WEP bit from the 802.11 header - * before passing frames to ieee80211_input because - * the card has already stripped the WEP crypto - * header from the packet. - */ - if (ic->ic_flags & IEEE80211_F_PRIVACY) - ic->ic_flags &= ~IEEE80211_F_DROPUNENC; /* XXX check return value */ buflen = sizeof(ssid); wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen); diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index be90399..a00dd33 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -66,6 +66,9 @@ struct wi_softc { struct ieee80211com sc_ic; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); + int (*sc_key_alloc)(struct ieee80211com *, + const struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); device_t sc_dev; #if __FreeBSD_version >= 500000 struct mtx sc_mtx; @@ -121,6 +124,7 @@ struct wi_softc { u_int16_t sc_roaming_mode; u_int16_t sc_microwave_oven; u_int16_t sc_authtype; + u_int16_t sc_encryption; int sc_nodelen; char sc_nodename[IEEE80211_NWID_LEN]; |