summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authoravatar <avatar@FreeBSD.org>2005-10-02 04:29:08 +0000
committeravatar <avatar@FreeBSD.org>2005-10-02 04:29:08 +0000
commit21345d1652e54640c8a244f7f75717f7078e5a01 (patch)
tree8cee6fb67928c9283242338c92e994b82976bae2 /sys/dev
parent4aac14991941450642bcd39207147b5502a195d1 (diff)
downloadFreeBSD-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/dev')
-rw-r--r--sys/dev/wi/if_wi.c70
-rw-r--r--sys/dev/wi/if_wivar.h4
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];
OpenPOWER on IntegriCloud