summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files5
-rw-r--r--sys/dev/ic/acx.c9
-rw-r--r--sys/dev/ic/atw.c10
-rw-r--r--sys/dev/ic/bwi.c10
-rw-r--r--sys/dev/ic/malo.c19
-rw-r--r--sys/dev/ic/pgt.c6
-rw-r--r--sys/dev/ic/rt2560.c26
-rw-r--r--sys/dev/ic/rt2661.c28
-rw-r--r--sys/dev/ic/rt2860.c34
-rw-r--r--sys/dev/ic/rt2860reg.h5
-rw-r--r--sys/dev/ic/rtw.c20
-rw-r--r--sys/dev/pci/if_ipw.c111
-rw-r--r--sys/dev/pci/if_ipwvar.h4
-rw-r--r--sys/dev/pci/if_iwn.c35
-rw-r--r--sys/dev/pci/if_wpi.c33
-rw-r--r--sys/dev/usb/if_ral.c14
-rw-r--r--sys/dev/usb/if_rum.c14
-rw-r--r--sys/dev/usb/if_upgt.c17
-rw-r--r--sys/dev/usb/if_zyd.c13
-rw-r--r--sys/net80211/ieee80211.c15
-rw-r--r--sys/net80211/ieee80211.h20
-rw-r--r--sys/net80211/ieee80211_crypto.c636
-rw-r--r--sys/net80211/ieee80211_crypto.h65
-rw-r--r--sys/net80211/ieee80211_crypto_ccmp.c455
-rw-r--r--sys/net80211/ieee80211_crypto_tkip.c707
-rw-r--r--sys/net80211/ieee80211_crypto_wep.c305
-rw-r--r--sys/net80211/ieee80211_input.c1071
-rw-r--r--sys/net80211/ieee80211_ioctl.c311
-rw-r--r--sys/net80211/ieee80211_ioctl.h54
-rw-r--r--sys/net80211/ieee80211_node.c176
-rw-r--r--sys/net80211/ieee80211_node.h39
-rw-r--r--sys/net80211/ieee80211_output.c428
-rw-r--r--sys/net80211/ieee80211_proto.c82
-rw-r--r--sys/net80211/ieee80211_proto.h12
-rw-r--r--sys/net80211/ieee80211_var.h42
35 files changed, 3392 insertions, 1439 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 9c45d640adf..225e7fc8b25 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.427 2008/04/09 19:49:55 robert Exp $
+# $OpenBSD: files,v 1.428 2008/04/16 18:32:14 damien Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -783,6 +783,9 @@ file net/if_trunk.c trunk needs-count
file net80211/ieee80211.c wlan
file net80211/ieee80211_amrr.c wlan
file net80211/ieee80211_crypto.c wlan
+file net80211/ieee80211_crypto_ccmp.c wlan
+file net80211/ieee80211_crypto_tkip.c wlan
+file net80211/ieee80211_crypto_wep.c wlan
file net80211/ieee80211_input.c wlan
file net80211/ieee80211_ioctl.c wlan
file net80211/ieee80211_node.c wlan
diff --git a/sys/dev/ic/acx.c b/sys/dev/ic/acx.c
index 472ccf0f90c..f385eb55c7c 100644
--- a/sys/dev/ic/acx.c
+++ b/sys/dev/ic/acx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acx.c,v 1.81 2008/03/13 23:07:28 brad Exp $ */
+/* $OpenBSD: acx.c,v 1.82 2008/04/16 18:32:15 damien Exp $ */
/*
* Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
@@ -998,10 +998,11 @@ acx_start(struct ifnet *ifp)
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[1] & IEEE80211_FC1_WEP) && !sc->chip_hw_crypt) {
- m = ieee80211_wep_crypt(ifp, m, 1);
- if (m == NULL) {
+ struct ieee80211_key *k;
+
+ k = ieee80211_get_txkey(ic, wh, ni);
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL) {
ieee80211_release_node(ic, ni);
- m_freem(m);
ifp->if_oerrors++;
continue;
}
diff --git a/sys/dev/ic/atw.c b/sys/dev/ic/atw.c
index 3525221e361..56b9ae24c6a 100644
--- a/sys/dev/ic/atw.c
+++ b/sys/dev/ic/atw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atw.c,v 1.56 2008/03/13 23:07:29 brad Exp $ */
+/* $OpenBSD: atw.c,v 1.57 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: atw.c,v 1.69 2004/07/23 07:07:55 dyoung Exp $ */
/*-
@@ -3614,6 +3614,7 @@ atw_start(struct ifnet *ifp)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct atw_frame *hh;
struct mbuf *m0, *m;
struct atw_txsoft *txs, *last_txs;
@@ -3670,8 +3671,11 @@ atw_start(struct ifnet *ifp)
break;
}
- if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
- if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
+ if (ic->ic_flags & IEEE80211_F_WEPON) {
+ wh = mtod(m0, struct ieee80211_frame *);
+ k = ieee80211_get_txkey(ic, wh, ni);
+ m0 = ieee80211_encrypt(ic, m0, k);
+ if (m0 == NULL) {
ifp->if_oerrors++;
break;
}
diff --git a/sys/dev/ic/bwi.c b/sys/dev/ic/bwi.c
index 18f2da657e4..1be7833615a 100644
--- a/sys/dev/ic/bwi.c
+++ b/sys/dev/ic/bwi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwi.c,v 1.74 2008/02/25 21:13:30 mglocker Exp $ */
+/* $OpenBSD: bwi.c,v 1.75 2008/04/16 18:32:15 damien Exp $ */
/*
* Copyright (c) 2007 The DragonFly Project. All rights reserved.
@@ -864,6 +864,7 @@ bwi_attach(struct bwi_softc *sc)
ic->ic_caps = IEEE80211_C_SHSLOT |
IEEE80211_C_SHPREAMBLE |
IEEE80211_C_WEP |
+ IEEE80211_C_RSN |
IEEE80211_C_MONITOR;
ic->ic_state = IEEE80211_S_INIT;
ic->ic_opmode = IEEE80211_M_STA;
@@ -7196,6 +7197,7 @@ bwi_start(struct ifnet *ifp)
while (tbd->tbd_buf[idx].tb_mbuf == NULL) {
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
+ struct ieee80211_key *k;
struct mbuf *m;
int mgt_pkt = 0;
@@ -7249,9 +7251,9 @@ bwi_start(struct ifnet *ifp)
bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
#endif
wh = mtod(m, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m = ieee80211_wep_crypt(ifp, m, 1);
- if (m == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
return;
}
wh = NULL; /* Catch any invalid use */
diff --git a/sys/dev/ic/malo.c b/sys/dev/ic/malo.c
index a0a30abd071..e17cd6585cb 100644
--- a/sys/dev/ic/malo.c
+++ b/sys/dev/ic/malo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: malo.c,v 1.81 2007/11/10 14:20:15 mglocker Exp $ */
+/* $OpenBSD: malo.c,v 1.82 2008/04/16 18:32:15 damien Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -378,7 +378,8 @@ malo_attach(struct malo_softc *sc)
IEEE80211_C_MONITOR |
IEEE80211_C_SHPREAMBLE |
IEEE80211_C_SHSLOT |
- IEEE80211_C_WEP;
+ IEEE80211_C_WEP |
+ IEEE80211_C_RSN;
ic->ic_opmode = IEEE80211_M_STA;
ic->ic_state = IEEE80211_S_INIT;
ic->ic_max_rssi = 75;
@@ -1411,15 +1412,6 @@ malo_tx_mgt(struct malo_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
}
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
- return (ENOBUFS);
-
- /* packet header may have moved, reset our local pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- }
-
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct mbuf mb;
@@ -1506,6 +1498,7 @@ malo_tx_data(struct malo_softc *sc, struct mbuf *m0,
struct malo_tx_desc *desc;
struct malo_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *mnew;
int error;
@@ -1524,8 +1517,8 @@ malo_tx_data(struct malo_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ k = ieee80211_get_txkey(ic, wh, ni);
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return (ENOBUFS);
/* packet header may have moved, reset our local pointer */
diff --git a/sys/dev/ic/pgt.c b/sys/dev/ic/pgt.c
index 4b7c9ea9866..b3da4357569 100644
--- a/sys/dev/ic/pgt.c
+++ b/sys/dev/ic/pgt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pgt.c,v 1.47 2008/03/13 23:07:29 brad Exp $ */
+/* $OpenBSD: pgt.c,v 1.48 2008/04/16 18:32:15 damien Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -2978,10 +2978,6 @@ pgt_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
ic->ic_if.if_timer = 0;
ic->ic_mgt_timer = 0;
ic->ic_flags &= ~IEEE80211_F_SIBSS;
- if (ic->ic_wep_ctx != NULL) {
- free(ic->ic_wep_ctx, M_DEVBUF);
- ic->ic_wep_ctx = NULL;
- }
ieee80211_free_allnodes(ic);
break;
case IEEE80211_S_SCAN:
diff --git a/sys/dev/ic/rt2560.c b/sys/dev/ic/rt2560.c
index de3de628cb3..81bbb9f93f0 100644
--- a/sys/dev/ic/rt2560.c
+++ b/sys/dev/ic/rt2560.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2560.c,v 1.35 2007/11/17 14:29:11 damien Exp $ */
+/* $OpenBSD: rt2560.c,v 1.36 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2005, 2006
@@ -242,7 +242,8 @@ rt2560_attach(void *xsc, int id)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
/* set supported .11b and .11g rates */
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
@@ -1595,7 +1596,6 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0,
struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct ieee80211_frame *wh;
@@ -1606,17 +1606,6 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0,
desc = &sc->prioq.desc[sc->prioq.cur];
data = &sc->prioq.data[sc->prioq.cur];
- wh = mtod(m0, struct ieee80211_frame *);
-
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
- return ENOBUFS;
-
- /* packet header may have moved, reset our local pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- }
-
error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0,
BUS_DMA_NOWAIT);
if (error != 0) {
@@ -1691,11 +1680,11 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rt2560_tx_ring *txq = &sc->txq;
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *mnew;
uint16_t dur;
uint32_t flags = 0;
@@ -1703,9 +1692,10 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
diff --git a/sys/dev/ic/rt2661.c b/sys/dev/ic/rt2661.c
index 0cc21cd0910..04a98615465 100644
--- a/sys/dev/ic/rt2661.c
+++ b/sys/dev/ic/rt2661.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2661.c,v 1.40 2007/11/17 14:29:11 damien Exp $ */
+/* $OpenBSD: rt2661.c,v 1.41 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2006
@@ -252,7 +252,8 @@ rt2661_attach(void *xsc, int id)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
if (sc->rf_rev == RT2661_RF_5225 || sc->rf_rev == RT2661_RF_5325) {
/* set supported .11a rates */
@@ -1442,7 +1443,6 @@ rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0,
struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rt2661_tx_desc *desc;
struct rt2661_tx_data *data;
struct ieee80211_frame *wh;
@@ -1456,17 +1456,6 @@ rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0,
/* send mgt frames at the lowest available rate */
rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
- wh = mtod(m0, struct ieee80211_frame *);
-
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
- return ENOBUFS;
-
- /* packet header may have moved, reset our local pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- }
-
error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0,
BUS_DMA_NOWAIT);
if (error != 0) {
@@ -1499,6 +1488,8 @@ rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0,
data->m = m0;
data->ni = ni;
+ wh = mtod(m0, struct ieee80211_frame *);
+
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
flags |= RT2661_TX_NEED_ACK;
@@ -1539,11 +1530,11 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
struct ieee80211_node *ni, int ac)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rt2661_tx_ring *txq = &sc->txq[ac];
struct rt2661_tx_desc *desc;
struct rt2661_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *mnew;
uint16_t dur;
uint32_t flags = 0;
@@ -1551,9 +1542,10 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
diff --git a/sys/dev/ic/rt2860.c b/sys/dev/ic/rt2860.c
index 292dacacb70..82c085e6a4e 100644
--- a/sys/dev/ic/rt2860.c
+++ b/sys/dev/ic/rt2860.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860.c,v 1.11 2007/12/14 21:28:49 damien Exp $ */
+/* $OpenBSD: rt2860.c,v 1.12 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2007
@@ -127,9 +127,9 @@ void rt2860_updateslot(struct ieee80211com *);
void rt2860_updateprot(struct ieee80211com *);
void rt2860_updateedca(struct ieee80211com *);
int rt2860_set_key(struct ieee80211com *, struct ieee80211_node *,
- const struct ieee80211_key *);
+ struct ieee80211_key *);
void rt2860_delete_key(struct ieee80211com *,
- struct ieee80211_node *, int);
+ struct ieee80211_node *, struct ieee80211_key *);
int8_t rt2860_rssi2dbm(struct rt2860_softc *, uint8_t, uint8_t);
uint8_t rt2860_maxrssi_chain(struct rt2860_softc *,
const struct rt2860_rxwi *);
@@ -236,7 +236,8 @@ rt2860_attach(void *xsc, int id)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850) {
/* set supported .11a rates */
@@ -282,9 +283,10 @@ rt2860_attach(void *xsc, int id)
ic->ic_newassoc = rt2860_newassoc;
ic->ic_updateslot = rt2860_updateslot;
ic->ic_updateedca = rt2860_updateedca;
+#ifdef notyet
ic->ic_set_key = rt2860_set_key;
ic->ic_delete_key = rt2860_delete_key;
-
+#endif
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = rt2860_newstate;
@@ -1322,12 +1324,12 @@ rt2860_tx_data(struct rt2860_softc *sc, struct mbuf *m0,
struct ieee80211_node *ni, int qid)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rt2860_tx_ring *ring = &sc->txq[qid];
struct rt2860_tx_data *data;
struct rt2860_txd *txd;
struct rt2860_txwi *txwi;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
bus_dma_segment_t *seg;
u_int hdrlen;
uint16_t dur;
@@ -1356,8 +1358,9 @@ rt2860_tx_data(struct rt2860_softc *sc, struct mbuf *m0,
mcs = rt2860_rate2mcs(rate);
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
@@ -2098,7 +2101,7 @@ rt2860_updateedca(struct ieee80211com *ic)
int
rt2860_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
- const struct ieee80211_key *k)
+ struct ieee80211_key *k)
{
struct rt2860_softc *sc = ic->ic_softc;
bus_size_t base;
@@ -2127,8 +2130,7 @@ rt2860_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
/* install group key */
base = RT2860_SKEY(0, k->k_id);
RAL_WRITE_REGION_1(sc, base, k->k_key, k->k_len);
- RAL_WRITE_REGION_1(sc, base + 16, k->k_txmic, 8);
- RAL_WRITE_REGION_1(sc, base + 24, k->k_rxmic, 8);
+ /* XXX TKIP + HostAP: swap Tx/Rx MIC */
attr = RAL_READ(sc, RT2860_SKEY_MODE_0_7);
attr &= ~(0xf << (k->k_id * 4));
@@ -2139,8 +2141,7 @@ rt2860_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
wcid = RT2860_AID2WCID(ni->ni_associd);
base = RT2860_PKEY(wcid);
RAL_WRITE_REGION_1(sc, base, k->k_key, k->k_len);
- RAL_WRITE_REGION_1(sc, base + 16, k->k_txmic, 8);
- RAL_WRITE_REGION_1(sc, base + 24, k->k_rxmic, 8);
+ /* XXX TKIP + HostAP: swap Tx/Rx MIC */
attr = RAL_READ(sc, RT2860_WCID_ATTR(wcid));
attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
@@ -2150,16 +2151,17 @@ rt2860_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
}
void
-rt2860_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, int kid)
+rt2860_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
{
struct rt2860_softc *sc = ic->ic_softc;
uint32_t attr;
uint8_t wcid;
- if (ni == NULL) {
+ if (k->k_flags & IEEE80211_KEY_GROUP) {
/* remove group key */
attr = RAL_READ(sc, RT2860_SKEY_MODE_0_7);
- attr &= ~(0xf << (kid * 4));
+ attr &= ~(0xf << (k->k_id * 4));
RAL_WRITE(sc, RT2860_SKEY_MODE_0_7, attr);
} else {
diff --git a/sys/dev/ic/rt2860reg.h b/sys/dev/ic/rt2860reg.h
index 951abe93a1f..b82baccef67 100644
--- a/sys/dev/ic/rt2860reg.h
+++ b/sys/dev/ic/rt2860reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860reg.h,v 1.7 2007/12/14 21:28:49 damien Exp $ */
+/* $OpenBSD: rt2860reg.h,v 1.8 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2007
@@ -842,7 +842,8 @@ struct rt2860_rxwi {
{ RT2860_GF40_PROT_CFG, 0x03f44084 }, \
{ RT2860_MM20_PROT_CFG, 0x01744004 }, \
{ RT2860_MM40_PROT_CFG, 0x03f54084 }, \
- { RT2860_TXOP_CTRL_CFG, 0x0000243f }, \
+ { RT2860_TXOP_CTRL_CFG, 0x0000583f }, \
+ { RT2860_TXOP_HLDR_ET, 0x00000002 }, \
{ RT2860_TX_RTS_CFG, 0x00092b20 }, \
{ RT2860_EXP_ACK_TIME, 0x002400ca }
diff --git a/sys/dev/ic/rtw.c b/sys/dev/ic/rtw.c
index 9ccbdf20f2f..f0071a2be4e 100644
--- a/sys/dev/ic/rtw.c
+++ b/sys/dev/ic/rtw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtw.c,v 1.65 2007/11/21 15:58:22 blambert Exp $ */
+/* $OpenBSD: rtw.c,v 1.66 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: rtw.c,v 1.29 2004/12/27 19:49:16 dyoung Exp $ */
/*-
@@ -2718,18 +2718,22 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
struct rtw_txdesc_blk **tdbp, struct mbuf **mp,
struct ieee80211_node **nip)
{
+ struct ieee80211com *ic;
+ struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *m0;
struct rtw_softc *sc;
short *if_flagsp;
sc = (struct rtw_softc *)ifp->if_softc;
+ ic = &sc->sc_ic;
DPRINTF(sc, RTW_DEBUG_XMIT,
("%s: enter %s\n", sc->sc_dev.dv_xname, __func__));
if_flagsp = &ifp->if_flags;
- if (sc->sc_ic.ic_state == IEEE80211_S_RUN &&
+ if (ic->ic_state == IEEE80211_S_RUN &&
(*mp = rtw_80211_dequeue(sc, &sc->sc_beaconq, RTW_TXPRIBCN, tsbp,
tdbp, nip, if_flagsp)) != NULL) {
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue beacon frame\n",
@@ -2737,7 +2741,7 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
return 0;
}
- if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_mgtq, RTW_TXPRIMD, tsbp,
+ if ((*mp = rtw_80211_dequeue(sc, &ic->ic_mgtq, RTW_TXPRIMD, tsbp,
tdbp, nip, if_flagsp)) != NULL) {
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue mgt frame\n",
__func__));
@@ -2749,14 +2753,14 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
return 0;
}
- if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_pwrsaveq, RTW_TXPRIHI,
+ if ((*mp = rtw_80211_dequeue(sc, &ic->ic_pwrsaveq, RTW_TXPRIHI,
tsbp, tdbp, nip, if_flagsp)) != NULL) {
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue pwrsave frame\n",
__func__));
return 0;
}
- if (sc->sc_ic.ic_state != IEEE80211_S_RUN) {
+ if (ic->ic_state != IEEE80211_S_RUN) {
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n", __func__));
return 0;
}
@@ -2797,8 +2801,10 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
}
/* XXX should do WEP in hardware */
- if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
- if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL)
+ if (ic->ic_flags & IEEE80211_F_WEPON) {
+ wh = mtod(m0, struct ieee80211_frame *);
+ k = ieee80211_get_txkey(ic, wh, *nip);
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return -1;
}
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c
index 9810a9f77d6..b6ff2171dcd 100644
--- a/sys/dev/pci/if_ipw.c
+++ b/sys/dev/pci/if_ipw.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: if_ipw.c,v 1.71 2008/02/23 20:38:08 hshoexer Exp $ */
+/* $OpenBSD: if_ipw.c,v 1.72 2008/04/16 18:32:15 damien Exp $ */
/*-
- * Copyright (c) 2004-2006
+ * Copyright (c) 2004-2008
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -496,7 +496,6 @@ ipw_dma_alloc(struct ipw_softc *sc)
error = ENOMEM;
goto fail;
}
-
MCLGET(sbuf->m, M_DONTWAIT);
if (!(sbuf->m->m_flags & M_EXT)) {
m_freem(sbuf->m);
@@ -645,15 +644,12 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
break;
-
case IEEE80211_M_IBSS:
imr->ifm_active |= IFM_IEEE80211_IBSS;
break;
-
case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
break;
-
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
/* should not get there */
@@ -835,7 +831,6 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
ifp->if_ierrors++;
return;
}
-
MCLGET(mnew, M_DONTWAIT);
if (!(mnew->m_flags & M_EXT)) {
m_freem(mnew);
@@ -894,7 +889,6 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
#endif
wh = mtod(m, struct ieee80211_frame *);
-
ni = ieee80211_find_rxnode(ic, wh);
/* send the frame to the upper layer */
@@ -1101,7 +1095,7 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
bus_dmamap_sync(sc->sc_dmat, sc->cmd_map, 0, sizeof (struct ipw_cmd),
BUS_DMASYNC_PREWRITE);
-
+
bus_dmamap_sync(sc->sc_dmat, sc->tbd_map,
sc->txcur * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
BUS_DMASYNC_PREWRITE);
@@ -1122,6 +1116,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct ipw_soft_bd *sbd;
struct ipw_soft_hdr *shdr;
struct ipw_soft_buf *sbuf;
@@ -1130,9 +1125,10 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
wh = mtod(m, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m = ieee80211_wep_crypt(ifp, m, 1);
- if (m == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
@@ -1163,7 +1159,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
shdr->hdr.type = htole32(IPW_HDR_TYPE_SEND);
shdr->hdr.subtype = htole32(0);
- shdr->hdr.encrypted = (wh->i_fc[1] & IEEE80211_FC1_WEP) ? 1 : 0;
+ shdr->hdr.encrypted = (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) ? 1 : 0;
shdr->hdr.encrypt = 0;
shdr->hdr.keyidx = 0;
shdr->hdr.keysz = 0;
@@ -1192,7 +1188,6 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
m_freem(m);
return ENOMEM;
}
-
M_DUP_PKTHDR(mnew, m);
if (m->m_pkthdr.len > MHLEN) {
MCLGET(mnew, M_DONTWAIT);
@@ -1202,7 +1197,6 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
return ENOMEM;
}
}
-
m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
m_freem(m);
mnew->m_len = mnew->m_pkthdr.len;
@@ -1297,8 +1291,8 @@ ipw_start(struct ifnet *ifp)
{
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- struct mbuf *m;
struct ieee80211_node *ni;
+ struct mbuf *m;
if (ic->ic_state != IEEE80211_S_RUN)
return;
@@ -1317,16 +1311,13 @@ ipw_start(struct ifnet *ifp)
if (ifp->if_bpf != NULL)
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
-
m = ieee80211_encap(ifp, m, &ni);
if (m == NULL)
continue;
-
#if NBPFILTER > 0
if (ic->ic_rawbpf != NULL)
bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
#endif
-
if (ipw_tx_start(ifp, m, ni) != 0) {
if (ni != NULL)
ieee80211_release_node(ic, ni);
@@ -1452,14 +1443,13 @@ ipw_read_table2(struct ipw_softc *sc, uint32_t off, void *buf, uint32_t *len)
info = MEM_READ_4(sc, sc->table2_base + off + 4);
count = info >> 16;
- size = info & 0xffff;
+ size = info & 0xffff;
total = count * size;
if (total > *len) {
*len = total;
return EINVAL;
}
-
*len = total;
ipw_read_mem_1(sc, addr, buf, total);
@@ -1469,6 +1459,7 @@ ipw_read_table2(struct ipw_softc *sc, uint32_t off, void *buf, uint32_t *len)
void
ipw_stop_master(struct ipw_softc *sc)
{
+ uint32_t tmp;
int ntries;
/* disable interrupts */
@@ -1484,8 +1475,8 @@ ipw_stop_master(struct ipw_softc *sc)
printf("%s: timeout waiting for master\n",
sc->sc_dev.dv_xname);
- CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
- IPW_RST_PRINCETON_RESET);
+ tmp = CSR_READ_4(sc, IPW_CSR_RST);
+ CSR_WRITE_4(sc, IPW_CSR_RST, tmp | IPW_RST_PRINCETON_RESET);
sc->flags &= ~IPW_FLAG_FW_INITED;
}
@@ -1493,13 +1484,14 @@ ipw_stop_master(struct ipw_softc *sc)
int
ipw_reset(struct ipw_softc *sc)
{
+ uint32_t tmp;
int ntries;
ipw_stop_master(sc);
/* move adapter to D0 state */
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_INIT);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_INIT);
/* wait for clock stabilization */
for (ntries = 0; ntries < 1000; ntries++) {
@@ -1510,13 +1502,13 @@ ipw_reset(struct ipw_softc *sc)
if (ntries == 1000)
return EIO;
- CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
- IPW_RST_SW_RESET);
+ tmp = CSR_READ_4(sc, IPW_CSR_RST);
+ CSR_WRITE_4(sc, IPW_CSR_RST, tmp | IPW_RST_SW_RESET);
DELAY(10);
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_INIT);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_INIT);
return 0;
}
@@ -1526,6 +1518,7 @@ ipw_load_ucode(struct ipw_softc *sc, u_char *uc, int size)
{
int ntries;
+ /* voodoo from the Intel Linux driver */
MEM_WRITE_4(sc, 0x3000e0, 0x80000000);
CSR_WRITE_4(sc, IPW_CSR_RST, 0);
@@ -1577,7 +1570,7 @@ int
ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
{
u_char *p, *end;
- uint32_t dst;
+ uint32_t tmp, dst;
uint16_t len;
int error;
@@ -1605,8 +1598,8 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
/* tell the adapter to initialize the firmware */
CSR_WRITE_4(sc, IPW_CSR_RST, 0);
- CSR_WRITE_4(sc, IPW_CSR_CTL, CSR_READ_4(sc, IPW_CSR_CTL) |
- IPW_CTL_ALLOW_STANDBY);
+ tmp = CSR_READ_4(sc, IPW_CSR_CTL);
+ CSR_WRITE_4(sc, IPW_CSR_CTL, tmp | IPW_CTL_ALLOW_STANDBY);
/* wait at most one second for firmware initialization to complete */
if ((error = tsleep(sc, 0, "ipwinit", hz)) != 0) {
@@ -1615,8 +1608,9 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
return error;
}
- CSR_WRITE_4(sc, IPW_CSR_IO, CSR_READ_4(sc, IPW_CSR_IO) |
- IPW_IO_GPIO1_MASK | IPW_IO_GPIO3_MASK);
+ tmp = CSR_READ_4(sc, IPW_CSR_IO);
+ CSR_WRITE_4(sc, IPW_CSR_IO, tmp | IPW_IO_GPIO1_MASK |
+ IPW_IO_GPIO3_MASK);
return 0;
}
@@ -1624,52 +1618,42 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
int
ipw_read_firmware(struct ipw_softc *sc, struct ipw_firmware *fw)
{
- struct ipw_firmware_hdr *hdr;
+ const struct ipw_firmware_hdr *hdr;
const char *name;
- u_char *p;
size_t size;
int error;
switch (sc->sc_ic.ic_opmode) {
case IEEE80211_M_STA:
- case IEEE80211_M_HOSTAP:
name = "ipw-bss";
break;
-
case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
name = "ipw-ibss";
break;
-
case IEEE80211_M_MONITOR:
name = "ipw-monitor";
break;
+ default:
+ /* should not get there */
+ return ENODEV;
}
-
if ((error = loadfirmware(name, &fw->data, &size)) != 0)
return error;
- if (size < sizeof (struct ipw_firmware_hdr)) {
+ if (size < sizeof (*hdr)) {
error = EINVAL;
goto fail;
}
-
- p = fw->data;
- hdr = (struct ipw_firmware_hdr *)p;
- fw->main_size = letoh32(hdr->main_size);
+ hdr = (const struct ipw_firmware_hdr *)fw->data;
+ fw->main_size = letoh32(hdr->main_size);
fw->ucode_size = letoh32(hdr->ucode_size);
- p += sizeof (struct ipw_firmware_hdr);
- size -= sizeof (struct ipw_firmware_hdr);
-
- if (size < fw->main_size + fw->ucode_size) {
+ if (size < sizeof (*hdr) + fw->main_size + fw->ucode_size) {
error = EINVAL;
goto fail;
}
-
- fw->main = p;
- fw->ucode = p + fw->main_size;
- sc->fw_data = fw->data;
+ fw->main = fw->data + sizeof (*hdr);
+ fw->ucode = fw->main + fw->main_size;
return 0;
@@ -1692,18 +1676,17 @@ ipw_config(struct ipw_softc *sc)
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
- case IEEE80211_M_HOSTAP:
data = htole32(IPW_MODE_BSS);
break;
-
case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
data = htole32(IPW_MODE_IBSS);
break;
-
case IEEE80211_M_MONITOR:
data = htole32(IPW_MODE_MONITOR);
break;
+ default:
+ /* should not get there */
+ return ENODEV;
}
DPRINTF(("Setting mode to %u\n", letoh32(data)));
error = ipw_cmd(sc, IPW_CMD_SET_MODE, &data, sizeof data);
@@ -1892,7 +1875,6 @@ ipw_init(struct ifnet *ifp)
sc->sc_dev.dv_xname, error);
goto fail1;
}
-
if ((error = ipw_load_ucode(sc, fw.ucode, fw.ucode_size)) != 0) {
printf("%s: could not load microcode\n", sc->sc_dev.dv_xname);
goto fail2;
@@ -1924,8 +1906,8 @@ ipw_init(struct ifnet *ifp)
printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
goto fail2;
}
-
sc->flags |= IPW_FLAG_FW_INITED;
+ free(fw.data, M_DEVBUF);
/* retrieve information tables base addresses */
sc->table1_base = CSR_READ_4(sc, IPW_CSR_TABLE1_BASE);
@@ -1938,7 +1920,6 @@ ipw_init(struct ifnet *ifp)
sc->sc_dev.dv_xname);
goto fail2;
}
-
ifp->if_flags &= ~IFF_OACTIVE;
ifp->if_flags |= IFF_RUNNING;
@@ -1969,14 +1950,6 @@ ipw_stop(struct ifnet *ifp, int disable)
for (i = 0; i < IPW_NTBD; i++)
ipw_release_sbd(sc, &sc->stbd_list[i]);
- /*
- * Free memory claimed by firmware.
- */
- if (sc->fw_data) {
- free(sc->fw_data, M_DEVBUF);
- sc->fw_data = NULL;
- }
-
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
}
diff --git a/sys/dev/pci/if_ipwvar.h b/sys/dev/pci/if_ipwvar.h
index 56348ad2f92..ca0d5b73a4d 100644
--- a/sys/dev/pci/if_ipwvar.h
+++ b/sys/dev/pci/if_ipwvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ipwvar.h,v 1.15 2008/02/23 21:35:41 hshoexer Exp $ */
+/* $OpenBSD: if_ipwvar.h,v 1.16 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2004-2006
@@ -158,6 +158,4 @@ struct ipw_softc {
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
#endif
-
- void *fw_data;
};
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c
index 71f793a9bac..11eb562932e 100644
--- a/sys/dev/pci/if_iwn.c
+++ b/sys/dev/pci/if_iwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwn.c,v 1.17 2008/03/08 16:24:44 espie Exp $ */
+/* $OpenBSD: if_iwn.c,v 1.18 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2007
@@ -135,7 +135,7 @@ int iwn_ioctl(struct ifnet *, u_long, caddr_t);
int iwn_cmd(struct iwn_softc *, int, const void *, int, int);
int iwn_setup_node_mrr(struct iwn_softc *, uint8_t, int);
int iwn_set_key(struct ieee80211com *, struct ieee80211_node *,
- const struct ieee80211_key *);
+ struct ieee80211_key *);
void iwn_updateedca(struct ieee80211com *);
void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
int iwn_set_critical_temp(struct iwn_softc *);
@@ -293,6 +293,7 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
/* set device capabilities */
ic->ic_caps =
IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN | /* WPA/RSN */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHSLOT | /* short slot time supported */
@@ -322,7 +323,9 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
ieee80211_ifattach(ifp);
ic->ic_node_alloc = iwn_node_alloc;
ic->ic_newassoc = iwn_newassoc;
+#ifdef notyet
ic->ic_set_key = iwn_set_key;
+#endif
ic->ic_updateedca = iwn_updateedca;
/* override state transition machine */
@@ -1457,7 +1460,7 @@ iwn_notif_intr(struct iwn_softc *sc)
DPRINTFN(4,("rx notification qid=%x idx=%d flags=%x type=%d "
"len=%d\n", desc->qid, desc->idx, desc->flags, desc->type,
- letoh32(desc->len)));
+ letoh16(desc->len)));
if (!(desc->qid & 0x80)) /* reply to a command */
iwn_cmd_intr(sc, desc);
@@ -1674,12 +1677,13 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
struct iwn_tx_cmd *cmd;
struct iwn_cmd_data *tx;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *mnew;
bus_addr_t paddr;
uint32_t flags;
uint8_t type;
u_int hdrlen;
- int i, rate, error, pad, ovhd = 0;
+ int i, rate, error, pad;
desc = &ring->desc[ring->cur];
data = &ring->data[ring->cur];
@@ -1733,18 +1737,13 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
/* no need to bzero tx, all fields are reinitialized here */
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
- const struct ieee80211_key *key =
- &ic->ic_nw_keys[ic->ic_wep_txkey];
- if (key->k_cipher == IEEE80211_CIPHER_WEP40)
- tx->security = IWN_CIPHER_WEP40;
- else
- tx->security = IWN_CIPHER_WEP104;
- tx->security |= ic->ic_wep_txkey << 6;
- memcpy(&tx->key[3], key->k_key, key->k_len);
- /* compute crypto overhead */
- ovhd = IEEE80211_WEP_TOTLEN;
- } else
- tx->security = 0;
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
+ return ENOBUFS;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
flags = IWN_TX_AUTO_SEQ;
if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
@@ -1759,7 +1758,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
/* check if RTS/CTS or CTS-to-self protection must be used */
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
/* multicast frames are not sent at OFDM rates in 802.11b/g */
- if (m0->m_pkthdr.len + ovhd + IEEE80211_CRC_LEN >
+ if (m0->m_pkthdr.len + IEEE80211_CRC_LEN >
ic->ic_rtsthreshold) {
flags |= IWN_TX_NEED_RTS | IWN_TX_FULL_TXOP;
} else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
@@ -2256,7 +2255,7 @@ iwn_setup_node_mrr(struct iwn_softc *sc, uint8_t id, int async)
*/
int
iwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
- const struct ieee80211_key *k)
+ struct ieee80211_key *k)
{
struct iwn_softc *sc = ic->ic_softc;
struct iwn_node_info node;
diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c
index f0cd31a8a1e..0549b16de86 100644
--- a/sys/dev/pci/if_wpi.c
+++ b/sys/dev/pci/if_wpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wpi.c,v 1.59 2008/03/08 16:24:45 espie Exp $ */
+/* $OpenBSD: if_wpi.c,v 1.60 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2006, 2007
@@ -130,7 +130,7 @@ int wpi_ioctl(struct ifnet *, u_long, caddr_t);
int wpi_cmd(struct wpi_softc *, int, const void *, int, int);
int wpi_mrr_setup(struct wpi_softc *);
int wpi_set_key(struct ieee80211com *, struct ieee80211_node *,
- const struct ieee80211_key *);
+ struct ieee80211_key *);
void wpi_updateedca(struct ieee80211com *);
void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t);
void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *);
@@ -270,6 +270,7 @@ wpi_attach(struct device *parent, struct device *self, void *aux)
/* set device capabilities */
ic->ic_caps =
IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN | /* WPA/RSN */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHSLOT | /* short slot time supported */
@@ -299,7 +300,9 @@ wpi_attach(struct device *parent, struct device *self, void *aux)
ieee80211_ifattach(ifp);
ic->ic_node_alloc = wpi_node_alloc;
ic->ic_newassoc = wpi_newassoc;
+#ifdef notyet
ic->ic_set_key = wpi_set_key;
+#endif
ic->ic_updateedca = wpi_updateedca;
/* override state transition machine */
@@ -1569,9 +1572,10 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
struct wpi_tx_cmd *cmd;
struct wpi_cmd_data *tx;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct mbuf *mnew;
u_int hdrlen;
- int i, rate, error, ovhd = 0;
+ int i, rate, error;
desc = &ring->desc[ring->cur];
data = &ring->data[ring->cur];
@@ -1626,18 +1630,13 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
tx->flags = 0;
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
- const struct ieee80211_key *key =
- &ic->ic_nw_keys[ic->ic_wep_txkey];
- if (key->k_cipher == IEEE80211_CIPHER_WEP40)
- tx->security = WPI_CIPHER_WEP40;
- else
- tx->security = WPI_CIPHER_WEP104;
- tx->security |= ic->ic_wep_txkey << 6;
- memcpy(&tx->key[3], key->k_key, key->k_len);
- /* compute crypto overhead */
- ovhd = IEEE80211_WEP_TOTLEN;
- } else
- tx->security = 0;
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
+ return ENOBUFS;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
tx->id = WPI_ID_BSS;
@@ -1648,7 +1647,7 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
/* check if RTS/CTS or CTS-to-self protection must be used */
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
/* multicast frames are not sent at OFDM rates in 802.11b/g */
- if (m0->m_pkthdr.len + ovhd + IEEE80211_CRC_LEN >
+ if (m0->m_pkthdr.len + IEEE80211_CRC_LEN >
ic->ic_rtsthreshold) {
tx->flags |= htole32(WPI_TX_NEED_RTS |
WPI_TX_FULL_TXOP);
@@ -2118,7 +2117,7 @@ wpi_mrr_setup(struct wpi_softc *sc)
*/
int
wpi_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
- const struct ieee80211_key *k)
+ struct ieee80211_key *k)
{
struct wpi_softc *sc = ic->ic_softc;
struct wpi_node_info node;
diff --git a/sys/dev/usb/if_ral.c b/sys/dev/usb/if_ral.c
index d1ebf3024e6..f125f66eb12 100644
--- a/sys/dev/usb/if_ral.c
+++ b/sys/dev/usb/if_ral.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ral.c,v 1.102 2007/10/11 18:33:14 deraadt Exp $ */
+/* $OpenBSD: if_ral.c,v 1.103 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2005, 2006
@@ -301,7 +301,8 @@ ural_attach(struct device *parent, struct device *self, void *aux)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
/* set supported .11b and .11g rates */
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
@@ -1034,10 +1035,10 @@ int
ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct ural_tx_desc *desc;
struct ural_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
uint32_t flags = RAL_TX_NEWSEQ;
uint16_t dur;
usbd_status error;
@@ -1045,9 +1046,10 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
diff --git a/sys/dev/usb/if_rum.c b/sys/dev/usb/if_rum.c
index 8864c54f7c7..ae18d4ee606 100644
--- a/sys/dev/usb/if_rum.c
+++ b/sys/dev/usb/if_rum.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_rum.c,v 1.70 2008/04/01 13:43:53 jsg Exp $ */
+/* $OpenBSD: if_rum.c,v 1.71 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2005-2007 Damien Bergamini <damien.bergamini@free.fr>
@@ -362,7 +362,8 @@ rum_attach(struct device *parent, struct device *self, void *aux)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) {
/* set supported .11a rates */
@@ -1048,10 +1049,10 @@ int
rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct rum_tx_desc *desc;
struct rum_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
uint32_t flags = 0;
uint16_t dur;
usbd_status error;
@@ -1059,9 +1060,10 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
diff --git a/sys/dev/usb/if_upgt.c b/sys/dev/usb/if_upgt.c
index 3ae7fe44d3e..e2f368a9ba2 100644
--- a/sys/dev/usb/if_upgt.c
+++ b/sys/dev/usb/if_upgt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_upgt.c,v 1.34 2008/02/16 21:56:43 mglocker Exp $ */
+/* $OpenBSD: if_upgt.c,v 1.35 2008/04/16 18:32:15 damien Exp $ */
/*
* Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
@@ -401,7 +401,8 @@ upgt_attach_hook(void *arg)
IEEE80211_C_MONITOR |
IEEE80211_C_SHPREAMBLE |
IEEE80211_C_SHSLOT |
- IEEE80211_C_WEP;
+ IEEE80211_C_WEP |
+ IEEE80211_C_RSN;
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
@@ -1507,8 +1508,8 @@ upgt_tx_task(void *arg)
{
struct upgt_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
struct upgt_lmac_mem *mem;
struct upgt_lmac_tx_desc *txdesc;
struct mbuf *m;
@@ -1533,14 +1534,16 @@ upgt_tx_task(void *arg)
addr = data_tx->addr + UPGT_MEMSIZE_FRAME_HEAD;
/*
- * Software WEP.
+ * Software crypto.
*/
wh = mtod(m, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m = ieee80211_wep_crypt(ifp, m, 1);
- if (m == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ic->ic_bss);
+
+ if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
return;
+
/* in case packet header moved, reset pointer */
wh = mtod(m, struct ieee80211_frame *);
}
diff --git a/sys/dev/usb/if_zyd.c b/sys/dev/usb/if_zyd.c
index a01057d99f3..9b9fb3a758f 100644
--- a/sys/dev/usb/if_zyd.c
+++ b/sys/dev/usb/if_zyd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_zyd.c,v 1.66 2007/12/07 05:05:02 deraadt Exp $ */
+/* $OpenBSD: if_zyd.c,v 1.67 2008/04/16 18:32:15 damien Exp $ */
/*-
* Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
@@ -369,7 +369,8 @@ zyd_complete_attach(struct zyd_softc *sc)
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
- IEEE80211_C_WEP; /* s/w WEP */
+ IEEE80211_C_WEP | /* s/w WEP */
+ IEEE80211_C_RSN; /* WPA/RSN */
/* set supported .11b and .11g rates */
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
@@ -2093,15 +2094,17 @@ zyd_tx_data(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
struct zyd_tx_desc *desc;
struct zyd_tx_data *data;
struct ieee80211_frame *wh;
+ struct ieee80211_key *k;
int xferlen, totlen, rate;
uint16_t pktlen;
usbd_status error;
wh = mtod(m0, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_get_txkey(ic, wh, ni);
+
+ if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL)
return ENOBUFS;
/* packet header may have moved, reset our local pointer */
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index c61325065b0..5218138a16d 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.c,v 1.29 2007/11/17 14:05:01 damien Exp $ */
+/* $OpenBSD: ieee80211.c,v 1.30 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */
/*-
@@ -148,6 +148,18 @@ ieee80211_ifattach(struct ifnet *ifp)
ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
+ if (ic->ic_caps & IEEE80211_C_RSN) {
+ ic->ic_rsnprotos =
+ IEEE80211_PROTO_WPA | IEEE80211_PROTO_RSN;
+ ic->ic_rsnakms =
+ IEEE80211_AKM_PSK | IEEE80211_AKM_IEEE8021X;
+ ic->ic_rsnciphers =
+ IEEE80211_CIPHER_TKIP | IEEE80211_CIPHER_CCMP;
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
+ }
+ ic->ic_set_key = ieee80211_set_key;
+ ic->ic_delete_key = ieee80211_delete_key;
+
LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
ieee80211_node_attach(ifp);
ieee80211_proto_attach(ifp);
@@ -993,4 +1005,3 @@ ieee80211_plcp2rate(u_int8_t plcp, enum ieee80211_phymode mode)
return 0;
}
-
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 3ed7d8ff17b..8914594ed74 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.h,v 1.34 2007/08/29 19:57:17 damien Exp $ */
+/* $OpenBSD: ieee80211.h,v 1.35 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */
/*-
@@ -466,14 +466,16 @@ enum {
IEEE80211_REASON_IE_INVALID = 13,
IEEE80211_REASON_MIC_FAILURE = 14,
-
+ IEEE80211_REASON_4WAY_TIMEOUT = 15,
+ IEEE80211_REASON_GROUP_TIMEOUT = 16,
+ IEEE80211_REASON_RSN_DIFFERENT_IE = 17,
IEEE80211_REASON_BAD_GROUP_CIPHER = 18,
IEEE80211_REASON_BAD_PAIRWISE_CIPHER = 19,
IEEE80211_REASON_BAD_AKMP = 20,
IEEE80211_REASON_RSN_IE_VER_UNSUP = 21,
IEEE80211_REASON_RSN_IE_BAD_CAP = 22,
- IEEE80211_REASON_CIPHER_REJ = 24
+ IEEE80211_REASON_CIPHER_REJ_POLICY = 24
};
/*
@@ -497,7 +499,15 @@ enum {
IEEE80211_STATUS_TOO_MANY_STATIONS = 22,
IEEE80211_STATUS_RATES = 23,
IEEE80211_STATUS_SHORTSLOT_REQUIRED = 25,
- IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26
+ IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26,
+
+ IEEE80211_STATUS_IE_INVALID = 40,
+ IEEE80211_STATUS_BAD_GROUP_CIPHER = 41,
+ IEEE80211_STATUS_BAD_PAIRWISE_CIPHER = 42,
+ IEEE80211_STATUS_BAD_AKMP = 43,
+ IEEE80211_STATUS_RSN_IE_VER_UNSUP = 44,
+
+ IEEE80211_STATUS_CIPHER_REJ_POLICY = 46,
};
#define IEEE80211_WEP_KEYLEN 5 /* 40bit */
@@ -630,7 +640,7 @@ struct ieee80211_eapol_key {
/* IEEE Std 802.1X-2004, 7.6.1 */
#define EAPOL_KEY_DESC_RC4 1 /* deprecated */
#define EAPOL_KEY_DESC_IEEE80211 2
-#define EAPOL_KEY_DESC_WPA1 254 /* non-standard WPA1 */
+#define EAPOL_KEY_DESC_WPA 254 /* non-standard WPA */
u_int8_t info[2];
#define EAPOL_KEY_VERSION_MASK 0x7
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c
index 219bc7b6411..7147980a019 100644
--- a/sys/net80211/ieee80211_crypto.c
+++ b/sys/net80211/ieee80211_crypto.c
@@ -1,37 +1,21 @@
-/* $OpenBSD: ieee80211_crypto.c,v 1.36 2007/09/11 19:03:33 damien Exp $ */
-/* $NetBSD: ieee80211_crypto.c,v 1.5 2003/12/14 09:56:53 dyoung Exp $ */
+/* $OpenBSD: ieee80211_crypto.c,v 1.37 2008/04/16 18:32:15 damien Exp $ */
/*-
- * Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
- * Copyright (c) 2007 Damien Bergamini
- * All rights reserved.
+ * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "bpfilter.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -50,10 +34,6 @@
#include <net/if_arp.h>
#include <net/if_llc.h>
-#if NBPFILTER > 0
-#include <net/bpf.h>
-#endif
-
#ifdef INET
#include <netinet/in.h>
#include <netinet/if_ether.h>
@@ -67,33 +47,13 @@
#include <crypto/sha1.h>
#include <crypto/rijndael.h>
+/* similar to iovec except that it accepts const pointers */
struct vector {
const void *base;
size_t len;
};
void ieee80211_crc_init(void);
-u_int32_t ieee80211_crc_update(u_int32_t, const u_int8_t *, int);
-struct mbuf *ieee80211_ccmp_encrypt(struct ieee80211com *, struct mbuf *,
- struct ieee80211_key *);
-struct mbuf *ieee80211_ccmp_decrypt(struct ieee80211com *, struct mbuf *,
- struct ieee80211_key *);
-struct mbuf *ieee80211_tkip_encrypt(struct ieee80211com *, struct mbuf *,
- struct ieee80211_key *);
-struct mbuf *ieee80211_tkip_decrypt(struct ieee80211com *, struct mbuf *,
- struct ieee80211_key *);
-void ieee80211_aes_key_wrap(const u_int8_t *, size_t, const u_int8_t *,
- size_t, u_int8_t *);
-int ieee80211_aes_key_unwrap(const u_int8_t *, size_t, const u_int8_t *,
- u_int8_t *, size_t);
-void ieee80211_hmac_md5_v(const struct vector *, int, const u_int8_t *,
- size_t, u_int8_t digest[]);
-void ieee80211_hmac_md5(const u_int8_t *, size_t, const u_int8_t *, size_t,
- u_int8_t digest[]);
-void ieee80211_hmac_sha1_v(const struct vector *, int, const u_int8_t *,
- size_t, u_int8_t digest[]);
-void ieee80211_hmac_sha1(const u_int8_t *, size_t, const u_int8_t *, size_t,
- u_int8_t digest[]);
void ieee80211_prf(const u_int8_t *, size_t, struct vector *, int,
u_int8_t *, size_t);
void ieee80211_derive_pmkid(const u_int8_t *, size_t, const u_int8_t *,
@@ -104,31 +64,94 @@ void ieee80211_derive_gtk(const u_int8_t *, size_t, const u_int8_t *,
void
ieee80211_crypto_attach(struct ifnet *ifp)
{
- struct ieee80211com *ic = (void *)ifp;
-
- ieee80211_crc_init();
-
- /* initialize 256-bit global key counter to a random value */
- get_random_bytes(ic->ic_globalcnt, EAPOL_KEY_NONCE_LEN);
+ ieee80211_crc_init(); /* XXX only once? */
}
void
ieee80211_crypto_detach(struct ifnet *ifp)
{
struct ieee80211com *ic = (void *)ifp;
+ int i;
+
+ /* clear all keys from memory */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (ic->ic_nw_keys[i].k_cipher != IEEE80211_CIPHER_NONE)
+ (*ic->ic_delete_key)(ic, NULL, &ic->ic_nw_keys[i]);
+ memset(&ic->ic_nw_keys[i], 0, sizeof(struct ieee80211_key));
+ }
+ memset(ic->ic_psk, 0, IEEE80211_PMK_LEN);
+}
+
+int
+ieee80211_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ int error;
+
+ switch (k->k_cipher) {
+ case IEEE80211_CIPHER_WEP40:
+ case IEEE80211_CIPHER_WEP104:
+ error = ieee80211_wep_set_key(ic, k);
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ error = ieee80211_tkip_set_key(ic, k);
+ break;
+ case IEEE80211_CIPHER_CCMP:
+ error = ieee80211_ccmp_set_key(ic, k);
+ break;
+ default:
+ /* should not get there */
+ error = EINVAL;
+ }
+ return error;
+}
- if (ic->ic_wep_ctx != NULL) {
- free(ic->ic_wep_ctx, M_DEVBUF);
- ic->ic_wep_ctx = NULL;
+void
+ieee80211_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ switch (k->k_cipher) {
+ case IEEE80211_CIPHER_WEP40:
+ case IEEE80211_CIPHER_WEP104:
+ ieee80211_wep_delete_key(ic, k);
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ ieee80211_tkip_delete_key(ic, k);
+ break;
+ case IEEE80211_CIPHER_CCMP:
+ ieee80211_ccmp_delete_key(ic, k);
+ break;
+ default:
+ /* should not get there */
+ break;
}
+ memset(k, 0, sizeof(*k)); /* XXX */
+}
+
+/*
+ * Retrieve the pairwise master key configured for a given node.
+ * When PSK AKMP is in use, the pairwise master key is the pre-shared key
+ * and the node is not used.
+ */
+const u_int8_t *
+ieee80211_get_pmk(struct ieee80211com *ic, struct ieee80211_node *ni,
+ const u_int8_t *pmkid)
+{
+ if (ni->ni_rsnakms == IEEE80211_AKM_PSK)
+ return ic->ic_psk; /* the PMK is the PSK */
+
+ /* XXX find the PMK in the PMKSA cache using the PMKID */
+
+ return NULL; /* not yet supported */
}
struct ieee80211_key *
ieee80211_get_txkey(struct ieee80211com *ic, const struct ieee80211_frame *wh,
struct ieee80211_node *ni)
{
- if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
- ni->ni_pairwise_cipher == IEEE80211_CIPHER_USEGROUP)
+ if (!(ic->ic_flags & IEEE80211_F_RSNON) ||
+ IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
return &ic->ic_nw_keys[ic->ic_wep_txkey];
return &ni->ni_pairwise_key;
}
@@ -140,7 +163,7 @@ ieee80211_encrypt(struct ieee80211com *ic, struct mbuf *m0,
switch (k->k_cipher) {
case IEEE80211_CIPHER_WEP40:
case IEEE80211_CIPHER_WEP104:
- m0 = ieee80211_wep_crypt(&ic->ic_if, m0, 1);
+ m0 = ieee80211_wep_encrypt(ic, m0, k);
break;
case IEEE80211_CIPHER_TKIP:
m0 = ieee80211_tkip_encrypt(ic, m0, k);
@@ -165,10 +188,12 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
/* select the key for decryption */
wh = mtod(m0, struct ieee80211_frame *);
- if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
- ni->ni_pairwise_cipher == IEEE80211_CIPHER_USEGROUP) {
+ if (!(ic->ic_flags & IEEE80211_F_RSNON) ||
+ IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP) {
+ /* XXX check length! */
int hdrlen = ieee80211_get_hdrlen(wh);
- u_int8_t *ivp = (u_int8_t *)wh + hdrlen;
+ const u_int8_t *ivp = (u_int8_t *)wh + hdrlen;
/* key identifier is always located at the same index */
int kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
k = &ic->ic_nw_keys[kid];
@@ -178,7 +203,7 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
switch (k->k_cipher) {
case IEEE80211_CIPHER_WEP40:
case IEEE80211_CIPHER_WEP104:
- m0 = ieee80211_wep_crypt(&ic->ic_if, m0, 0);
+ m0 = ieee80211_wep_decrypt(ic, m0, k);
break;
case IEEE80211_CIPHER_TKIP:
m0 = ieee80211_tkip_decrypt(ic, m0, k);
@@ -187,368 +212,13 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
m0 = ieee80211_ccmp_decrypt(ic, m0, k);
break;
default:
- /* should not get there */
+ /* key not defined */
m_freem(m0);
m0 = NULL;
}
return m0;
}
-struct mbuf *
-ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_key *k)
-{
- struct ieee80211_frame *wh;
- u_int8_t *ivp;
- int hdrlen;
-
- wh = mtod(m0, struct ieee80211_frame *);
- hdrlen = ieee80211_get_hdrlen(wh);
- M_PREPEND(m0, IEEE80211_CCMP_HDRLEN, M_NOWAIT);
- if (m0 == NULL)
- return m0;
- wh = mtod(m0, struct ieee80211_frame *);
- ovbcopy(mtod(m0, u_int8_t *) + IEEE80211_CCMP_HDRLEN, wh, hdrlen);
- ivp = (u_int8_t *)wh + hdrlen;
-
- k->k_tsc++; /* increment the 48-bit PN */
- ivp[0] = k->k_tsc; /* PN0 */
- ivp[1] = k->k_tsc >> 8; /* PN1 */
- ivp[2] = 0; /* Rsvd */
- ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
- ivp[4] = k->k_tsc >> 16; /* PN2 */
- ivp[5] = k->k_tsc >> 24; /* PN3 */
- ivp[6] = k->k_tsc >> 32; /* PN4 */
- ivp[7] = k->k_tsc >> 40; /* PN5 */
-
- /* XXX encrypt payload if HW encryption not supported */
-
- return m0;
-}
-
-struct mbuf *
-ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_key *k)
-{
- struct ieee80211_frame *wh;
- u_int64_t pn;
- u_int8_t *ivp;
- int hdrlen;
-
- wh = mtod(m0, struct ieee80211_frame *);
- hdrlen = ieee80211_get_hdrlen(wh);
- ivp = (u_int8_t *)wh + hdrlen;
-
- /* check that ExtIV bit is be set */
- if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
- m_freem(m0);
- return NULL;
- }
- /* extract the 48-bit PN from the CCMP header */
- pn = (u_int64_t)ivp[0] |
- (u_int64_t)ivp[1] << 8 |
- (u_int64_t)ivp[4] << 16 |
- (u_int64_t)ivp[5] << 24 |
- (u_int64_t)ivp[6] << 32 |
- (u_int64_t)ivp[7] << 40;
- /* NB: the keys are refreshed, we'll never overflow the 48 bits */
- if (pn <= k->k_rsc) {
- /* replayed frame, discard */
- /* XXX statistics */
- m_freem(m0);
- return NULL;
- }
-
- /* XXX decrypt payload if HW encryption not supported */
-
- ovbcopy(mtod(m0, u_int8_t *),
- mtod(m0, u_int8_t *) + IEEE80211_CCMP_HDRLEN, hdrlen);
- m_adj(m0, IEEE80211_CCMP_HDRLEN);
- m_adj(m0, -IEEE80211_CCMP_MICLEN);
-
- /* update last seen packet number */
- k->k_rsc = pn;
-
- return m0;
-}
-
-struct mbuf *
-ieee80211_tkip_encrypt(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_key *k)
-{
- struct ieee80211_frame *wh;
- u_int8_t *ivp;
- int hdrlen;
-
- wh = mtod(m0, struct ieee80211_frame *);
- hdrlen = ieee80211_get_hdrlen(wh);
- M_PREPEND(m0, IEEE80211_TKIP_HDRLEN, M_NOWAIT);
- if (m0 == NULL)
- return m0;
- wh = mtod(m0, struct ieee80211_frame *);
- ovbcopy(mtod(m0, u_int8_t *) + IEEE80211_TKIP_HDRLEN, wh, hdrlen);
- ivp = (u_int8_t *)wh + hdrlen;
-
- ivp[0] = k->k_tsc >> 8; /* TSC1 */
- /* WEP Seed = (TSC1 | 0x20) & 0x7f (see 8.3.2.2) */
- ivp[1] = (ivp[0] | 0x20) & 0x7f;
- ivp[2] = k->k_tsc; /* TSC0 */
- ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
- ivp[4] = k->k_tsc >> 16; /* TSC2 */
- ivp[5] = k->k_tsc >> 24; /* TSC3 */
- ivp[6] = k->k_tsc >> 32; /* TSC4 */
- ivp[7] = k->k_tsc >> 40; /* TSC5 */
-
- /* XXX encrypt payload if HW encryption not supported */
-
- k->k_tsc++; /* increment the 48-bit TSC */
-
- return m0;
-}
-
-struct mbuf *
-ieee80211_tkip_decrypt(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_key *k)
-{
- struct ieee80211_frame *wh;
- u_int64_t tsc;
- u_int8_t *ivp;
- int hdrlen;
-
- wh = mtod(m0, struct ieee80211_frame *);
- hdrlen = ieee80211_get_hdrlen(wh);
- ivp = (u_int8_t *)wh + hdrlen;
-
- /* check that ExtIV bit is be set */
- if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
- m_freem(m0);
- return NULL;
- }
- /* extract the 48-bit TSC from the TKIP header */
- tsc = (u_int64_t)ivp[2] |
- (u_int64_t)ivp[0] << 8 |
- (u_int64_t)ivp[4] << 16 |
- (u_int64_t)ivp[5] << 24 |
- (u_int64_t)ivp[6] << 32 |
- (u_int64_t)ivp[7] << 40;
- /* NB: the keys are refreshed, we'll never overflow the 48 bits */
- if (tsc <= k->k_rsc) {
- /* replayed frame, discard */
- /* XXX statistics */
- m_freem(m0);
- return NULL;
- }
-
- /* XXX decrypt payload if HW encryption not supported */
-
- ovbcopy(mtod(m0, u_int8_t *),
- mtod(m0, u_int8_t *) + IEEE80211_TKIP_HDRLEN, hdrlen);
- m_adj(m0, IEEE80211_TKIP_HDRLEN);
- m_adj(m0, -IEEE80211_TKIP_ICVLEN);
-
- /* update last seen packet number */
- k->k_rsc = tsc;
-
- return m0;
-}
-
-/* Round up to a multiple of IEEE80211_WEP_KEYLEN + IEEE80211_WEP_IVLEN */
-#define klen_round(x) \
- (((x) + (IEEE80211_WEP_KEYLEN + IEEE80211_WEP_IVLEN - 1)) & \
- ~(IEEE80211_WEP_KEYLEN + IEEE80211_WEP_IVLEN - 1))
-
-struct mbuf *
-ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag)
-{
- struct ieee80211com *ic = (void *)ifp;
- struct mbuf *m, *n, *n0;
- struct ieee80211_frame *wh;
- int i, left, len, moff, noff, kid;
- u_int32_t iv, crc;
- u_int8_t *ivp;
- void *ctx;
- u_int8_t keybuf[klen_round(IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE)];
- u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
-
- n0 = NULL;
- if ((ctx = ic->ic_wep_ctx) == NULL) {
- ctx = malloc(sizeof(struct rc4_ctx), M_DEVBUF, M_NOWAIT);
- if (ctx == NULL) {
- ic->ic_stats.is_crypto_nomem++;
- goto fail;
- }
- ic->ic_wep_ctx = ctx;
- }
- m = m0;
- left = m->m_pkthdr.len;
- MGET(n, M_DONTWAIT, m->m_type);
- n0 = n;
- if (n == NULL) {
- if (txflag)
- ic->ic_stats.is_tx_nombuf++;
- else
- ic->ic_stats.is_rx_nombuf++;
- goto fail;
- }
- M_DUP_PKTHDR(n, m);
- len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
- if (txflag) {
- n->m_pkthdr.len += len;
- } else {
- n->m_pkthdr.len -= len;
- left -= len;
- }
- n->m_len = MHLEN;
- if (n->m_pkthdr.len >= MINCLSIZE) {
- MCLGET(n, M_DONTWAIT);
- if (n->m_flags & M_EXT)
- n->m_len = n->m_ext.ext_size;
- }
- wh = mtod(m, struct ieee80211_frame *);
- len = ieee80211_get_hdrlen(wh);
- memcpy(mtod(n, caddr_t), wh, len);
- wh = mtod(n, struct ieee80211_frame *);
- left -= len;
- moff = len;
- noff = len;
- if (txflag) {
- kid = ic->ic_wep_txkey;
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
- iv = ic->ic_iv ? ic->ic_iv : arc4random();
- /*
- * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
- * (B, 255, N) with 3 <= B < 8
- */
- if (iv >= 0x03ff00 &&
- (iv & 0xf8ff00) == 0x00ff00)
- iv += 0x000100;
- ic->ic_iv = iv + 1;
- /* put iv in little endian to prepare 802.11i */
- ivp = mtod(n, u_int8_t *) + noff;
- for (i = 0; i < IEEE80211_WEP_IVLEN; i++) {
- ivp[i] = iv & 0xff;
- iv >>= 8;
- }
- ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */
- noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
- } else {
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
- ivp = mtod(m, u_int8_t *) + moff;
- kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
- moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
- }
-
- /*
- * Copy the IV and the key material. The input key has been padded
- * with zeros by the ioctl. The output key buffer length is rounded
- * to a multiple of 64bit to allow variable length keys padded by
- * zeros.
- */
- bzero(&keybuf, sizeof(keybuf));
- memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN);
- memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].k_key,
- ic->ic_nw_keys[kid].k_len);
- len = klen_round(IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].k_len);
- rc4_keysetup(ctx, keybuf, len);
-
- /* encrypt with calculating CRC */
- crc = ~0;
- while (left > 0) {
- len = m->m_len - moff;
- if (len == 0) {
- m = m->m_next;
- moff = 0;
- continue;
- }
- if (len > n->m_len - noff) {
- len = n->m_len - noff;
- if (len == 0) {
- MGET(n->m_next, M_DONTWAIT, n->m_type);
- if (n->m_next == NULL) {
- if (txflag)
- ic->ic_stats.is_tx_nombuf++;
- else
- ic->ic_stats.is_rx_nombuf++;
- goto fail;
- }
- n = n->m_next;
- n->m_len = MLEN;
- if (left >= MINCLSIZE) {
- MCLGET(n, M_DONTWAIT);
- if (n->m_flags & M_EXT)
- n->m_len = n->m_ext.ext_size;
- }
- noff = 0;
- continue;
- }
- }
- if (len > left)
- len = left;
- rc4_crypt(ctx, mtod(m, caddr_t) + moff,
- mtod(n, caddr_t) + noff, len);
- if (txflag)
- crc = ieee80211_crc_update(crc,
- mtod(m, u_int8_t *) + moff, len);
- else
- crc = ieee80211_crc_update(crc,
- mtod(n, u_int8_t *) + noff, len);
- left -= len;
- moff += len;
- noff += len;
- }
- crc = ~crc;
- if (txflag) {
- *(u_int32_t *)crcbuf = htole32(crc);
- if (n->m_len >= noff + sizeof(crcbuf))
- n->m_len = noff + sizeof(crcbuf);
- else {
- n->m_len = noff;
- MGET(n->m_next, M_DONTWAIT, n->m_type);
- if (n->m_next == NULL) {
- ic->ic_stats.is_tx_nombuf++;
- goto fail;
- }
- n = n->m_next;
- n->m_len = sizeof(crcbuf);
- noff = 0;
- }
- rc4_crypt(ctx, crcbuf, mtod(n, caddr_t) + noff,
- sizeof(crcbuf));
- } else {
- n->m_len = noff;
- for (noff = 0; noff < sizeof(crcbuf); noff += len) {
- len = sizeof(crcbuf) - noff;
- if (len > m->m_len - moff)
- len = m->m_len - moff;
- if (len > 0)
- rc4_crypt(ctx, mtod(m, caddr_t) + moff,
- crcbuf + noff, len);
- m = m->m_next;
- moff = 0;
- }
- if (crc != letoh32(*(u_int32_t *)crcbuf)) {
-#ifdef IEEE80211_DEBUG
- if (ieee80211_debug) {
- printf("%s: decrypt CRC error\n",
- ifp->if_xname);
- if (ieee80211_debug > 1)
- ieee80211_dump_pkt(n0->m_data,
- n0->m_len, -1, -1);
- }
-#endif
- ic->ic_stats.is_rx_decryptcrc++;
- goto fail;
- }
- }
- m_freem(m0);
- return n0;
-
- fail:
- m_freem(m0);
- m_freem(n0);
- return NULL;
-}
-
/*
* CRC 32 -- routine from RFC 2083
*/
@@ -591,13 +261,13 @@ ieee80211_crc_update(u_int32_t crc, const u_int8_t *buf, int len)
}
/*
- * AES Key Wrap Algorithm (see RFC 3394).
+ * AES Key Wrap (see RFC 3394).
*/
static const u_int8_t aes_key_wrap_iv[8] =
{ 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
-void
-ieee80211_aes_key_wrap(const u_int8_t *kek, size_t kek_len, const u_int8_t *pt,
+static void
+aes_key_wrap(const u_int8_t *kek, size_t kek_len, const u_int8_t *pt,
size_t len, u_int8_t *ct)
{
rijndael_ctx ctx;
@@ -628,9 +298,9 @@ ieee80211_aes_key_wrap(const u_int8_t *kek, size_t kek_len, const u_int8_t *pt,
}
}
-int
-ieee80211_aes_key_unwrap(const u_int8_t *kek, size_t kek_len,
- const u_int8_t *ct, u_int8_t *pt, size_t len)
+static int
+aes_key_unwrap(const u_int8_t *kek, size_t kek_len, const u_int8_t *ct,
+ u_int8_t *pt, size_t len)
{
rijndael_ctx ctx;
u_int8_t a[8], *r, b[16];
@@ -660,8 +330,11 @@ ieee80211_aes_key_unwrap(const u_int8_t *kek, size_t kek_len,
return memcmp(a, aes_key_wrap_iv, 8) != 0;
}
-void
-ieee80211_hmac_md5_v(const struct vector *vec, int vcnt, const u_int8_t *key,
+/*
+ * HMAC-MD5 (see RFC 2104).
+ */
+static void
+hmac_md5(const struct vector *vec, int vcnt, const u_int8_t *key,
size_t key_len, u_int8_t digest[MD5_DIGEST_LENGTH])
{
MD5_CTX ctx;
@@ -671,7 +344,7 @@ ieee80211_hmac_md5_v(const struct vector *vec, int vcnt, const u_int8_t *key,
if (key_len > MD5_BLOCK_LENGTH) {
MD5Init(&ctx);
- MD5Update(&ctx, (u_int8_t *)key, key_len);
+ MD5Update(&ctx, key, key_len);
MD5Final(tk, &ctx);
key = tk;
@@ -686,7 +359,7 @@ ieee80211_hmac_md5_v(const struct vector *vec, int vcnt, const u_int8_t *key,
MD5Init(&ctx);
MD5Update(&ctx, k_pad, MD5_BLOCK_LENGTH);
for (i = 0; i < vcnt; i++)
- MD5Update(&ctx, (u_int8_t *)vec[i].base, vec[i].len);
+ MD5Update(&ctx, vec[i].base, vec[i].len);
MD5Final(digest, &ctx);
bzero(k_pad, sizeof k_pad);
@@ -700,18 +373,11 @@ ieee80211_hmac_md5_v(const struct vector *vec, int vcnt, const u_int8_t *key,
MD5Final(digest, &ctx);
}
-void
-ieee80211_hmac_md5(const u_int8_t *text, size_t text_len, const u_int8_t *key,
- size_t key_len, u_int8_t digest[MD5_DIGEST_LENGTH])
-{
- struct vector vec;
- vec.base = text;
- vec.len = text_len;
- ieee80211_hmac_md5_v(&vec, 1, key, key_len, digest);
-}
-
-void
-ieee80211_hmac_sha1_v(const struct vector *vec, int vcnt, const u_int8_t *key,
+/*
+ * HMAC-SHA1 (see RFC 2104).
+ */
+static void
+hmac_sha1(const struct vector *vec, int vcnt, const u_int8_t *key,
size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH])
{
SHA1_CTX ctx;
@@ -750,16 +416,6 @@ ieee80211_hmac_sha1_v(const struct vector *vec, int vcnt, const u_int8_t *key,
SHA1Final(digest, &ctx);
}
-void
-ieee80211_hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key,
- size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH])
-{
- struct vector vec;
- vec.base = text;
- vec.len = text_len;
- ieee80211_hmac_sha1_v(&vec, 1, key, key_len, digest);
-}
-
/*
* SHA1-based Pseudo-Random Function (see 8.5.1.1).
*/
@@ -775,15 +431,15 @@ ieee80211_prf(const u_int8_t *key, size_t key_len, struct vector *vec,
vec[vcnt].len = 1;
vcnt++;
- while (len > SHA1_DIGEST_LENGTH) {
- ieee80211_hmac_sha1_v(vec, vcnt, key, key_len, output);
+ while (len >= SHA1_DIGEST_LENGTH) {
+ hmac_sha1(vec, vcnt, key, key_len, output);
count++;
output += SHA1_DIGEST_LENGTH;
len -= SHA1_DIGEST_LENGTH;
}
if (len > 0) {
- ieee80211_hmac_sha1_v(vec, vcnt, key, key_len, hash);
+ hmac_sha1(vec, vcnt, key, key_len, hash);
/* truncate HMAC-SHA1 to len bytes */
memcpy(output, hash, len);
}
@@ -839,30 +495,11 @@ ieee80211_derive_pmkid(const u_int8_t *pmk, size_t pmk_len, const u_int8_t *aa,
vec[2].base = spa;
vec[2].len = IEEE80211_ADDR_LEN;
- ieee80211_hmac_sha1_v(vec, 3, pmk, pmk_len, hash);
+ hmac_sha1(vec, 3, pmk, pmk_len, hash);
/* use the first 128 bits of the HMAC-SHA1 */
memcpy(pmkid, hash, IEEE80211_PMKID_LEN);
}
-/*
- * Derive Group Temporal Key (GTK) (see 8.5.1.3).
- */
-void
-ieee80211_derive_gtk(const u_int8_t *gmk, size_t gmk_len, const u_int8_t *aa,
- const u_int8_t *gnonce, u_int8_t *gtk, size_t gtk_len)
-{
- struct vector vec[4]; /* +1 for PRF */
-
- vec[0].base = "Group key expansion";
- vec[0].len = 20; /* include trailing '\0' */
- vec[1].base = aa;
- vec[1].len = IEEE80211_ADDR_LEN;
- vec[2].base = gnonce;
- vec[2].len = EAPOL_KEY_NONCE_LEN;
-
- ieee80211_prf(gmk, gmk_len, vec, 3, gtk, gtk_len);
-}
-
/* unaligned big endian access */
#define BE_READ_2(p) \
((u_int16_t) \
@@ -883,17 +520,17 @@ void
ieee80211_eapol_key_mic(struct ieee80211_eapol_key *key, const u_int8_t *kck)
{
u_int8_t hash[SHA1_DIGEST_LENGTH];
- u_int16_t len, info;
+ struct vector vec;
- len = BE_READ_2(key->len) + 4;
- info = BE_READ_2(key->info);
+ vec.base = key;
+ vec.len = BE_READ_2(key->len) + 4;
- switch (info & EAPOL_KEY_VERSION_MASK) {
+ switch (BE_READ_2(key->info) & EAPOL_KEY_VERSION_MASK) {
case EAPOL_KEY_DESC_V1:
- ieee80211_hmac_md5((u_int8_t *)key, len, kck, 16, key->mic);
+ hmac_md5(&vec, 1, kck, 16, key->mic);
break;
case EAPOL_KEY_DESC_V2:
- ieee80211_hmac_sha1((u_int8_t *)key, len, kck, 16, hash);
+ hmac_sha1(&vec, 1, kck, 16, hash);
/* truncate HMAC-SHA1 to its 128 MSBs */
memcpy(key->mic, hash, EAPOL_KEY_MIC_LEN);
break;
@@ -960,7 +597,7 @@ ieee80211_eapol_key_encrypt(struct ieee80211com *ic,
memset(&data[len], 0, n - 1);
len += n - 1;
}
- ieee80211_aes_key_wrap(kek, 16, data, len / 8, data);
+ aes_key_wrap(kek, 16, data, len / 8, data);
len += 8; /* AES Key Wrap adds 8 bytes */
/* update key data length */
BE_WRITE_2(key->paylen, len);
@@ -1004,7 +641,7 @@ ieee80211_eapol_key_decrypt(struct ieee80211_eapol_key *key,
if (len < 16 + 8 || (len & 7) != 0)
return 1;
len -= 8; /* AES Key Wrap adds 8 bytes */
- return ieee80211_aes_key_unwrap(kek, 16, data, data, len / 8);
+ return aes_key_unwrap(kek, 16, data, data, len / 8);
}
return 1; /* unknown Key Descriptor Version */
@@ -1035,20 +672,14 @@ ieee80211_cipher_keylen(enum ieee80211_cipher cipher)
*/
void
ieee80211_map_ptk(const struct ieee80211_ptk *ptk,
- enum ieee80211_cipher cipher, struct ieee80211_key *k)
+ enum ieee80211_cipher cipher, u_int64_t rsc, struct ieee80211_key *k)
{
memset(k, 0, sizeof(*k));
k->k_cipher = cipher;
k->k_flags = IEEE80211_KEY_TX;
k->k_len = ieee80211_cipher_keylen(cipher);
- if (cipher == IEEE80211_CIPHER_TKIP) {
- memcpy(k->k_key, ptk->tk, 16);
- /* use bits 128-191 as the Michael key for AA->SPA */
- memcpy(k->k_rxmic, &ptk->tk[16], 8);
- /* use bits 192-255 as the Michael key for SPA->AA */
- memcpy(k->k_txmic, &ptk->tk[24], 8);
- } else
- memcpy(k->k_key, ptk->tk, k->k_len);
+ k->k_rsc[0] = rsc;
+ memcpy(k->k_key, ptk->tk, k->k_len);
}
/*
@@ -1065,13 +696,6 @@ ieee80211_map_gtk(const u_int8_t *gtk, enum ieee80211_cipher cipher, int kid,
if (txflag)
k->k_flags |= IEEE80211_KEY_TX;
k->k_len = ieee80211_cipher_keylen(cipher);
- k->k_rsc = rsc;
- if (cipher == IEEE80211_CIPHER_TKIP) {
- memcpy(k->k_key, gtk, 16);
- /* use bits 128-191 as the Michael key for AA->SPA */
- memcpy(k->k_rxmic, &gtk[16], 8);
- /* use bits 192-255 as the Michael key for SPA->AA */
- memcpy(k->k_txmic, &gtk[24], 8);
- } else
- memcpy(k->k_key, gtk, k->k_len);
+ k->k_rsc[0] = rsc;
+ memcpy(k->k_key, gtk, k->k_len);
}
diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h
index fa47ab8f313..3447da8c0f5 100644
--- a/sys/net80211/ieee80211_crypto.h
+++ b/sys/net80211/ieee80211_crypto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_crypto.h,v 1.9 2007/08/23 16:50:30 damien Exp $ */
+/* $OpenBSD: ieee80211_crypto.h,v 1.10 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_crypto.h,v 1.2 2003/09/14 01:14:55 dyoung Exp $ */
/*-
@@ -50,7 +50,7 @@ enum ieee80211_cipher {
};
/*
- * 802.11i Authentication and Key Management.
+ * 802.11i Authentication and Key Management Protocols.
*/
enum ieee80211_akm {
IEEE80211_AKM_NONE = 0x00000000,
@@ -75,42 +75,73 @@ struct ieee80211_key {
#define IEEE80211_KEY_GROUP 0x00000001 /* group key */
#define IEEE80211_KEY_TX 0x00000002 /* Tx+Rx */
- u_int64_t k_rsc;
+ u_int k_len;
+ u_int64_t k_rsc[IEEE80211_NUM_TID];
u_int64_t k_tsc;
- int k_len;
- u_int8_t k_key[IEEE80211_KEYBUF_SIZE];
- u_int8_t k_rxmic[IEEE80211_TKIP_MICLEN];
- u_int8_t k_txmic[IEEE80211_TKIP_MICLEN];
+ u_int8_t k_key[32];
+ void *k_priv;
};
-/* pseudo-header used for TKIP MIC computation */
-struct ieee80211_tkip_frame {
- u_int8_t i_da[IEEE80211_ADDR_LEN];
- u_int8_t i_sa[IEEE80211_ADDR_LEN];
- u_int8_t i_pri;
- u_int8_t i_pad[3];
-} __packed;
-
/* forward references */
struct ieee80211com;
struct ieee80211_node;
extern void ieee80211_crypto_attach(struct ifnet *);
extern void ieee80211_crypto_detach(struct ifnet *);
+
+extern const u_int8_t *ieee80211_get_pmk(struct ieee80211com *,
+ struct ieee80211_node *, const u_int8_t *);
+
+
extern struct ieee80211_key *ieee80211_get_txkey(struct ieee80211com *,
const struct ieee80211_frame *, struct ieee80211_node *);
extern struct mbuf *ieee80211_encrypt(struct ieee80211com *, struct mbuf *,
struct ieee80211_key *);
extern struct mbuf *ieee80211_decrypt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
-extern struct mbuf *ieee80211_wep_crypt(struct ifnet *, struct mbuf *, int);
+
+u_int32_t ieee80211_crc_update(u_int32_t, const u_int8_t *, int);
+
+int ieee80211_set_key(struct ieee80211com *, struct ieee80211_node *,
+ struct ieee80211_key *);
+void ieee80211_delete_key(struct ieee80211com *, struct ieee80211_node *,
+ struct ieee80211_key *);
+
+int ieee80211_wep_set_key(struct ieee80211com *, struct ieee80211_key *);
+void ieee80211_wep_delete_key(struct ieee80211com *, struct ieee80211_key *);
+struct mbuf *
+ieee80211_wep_encrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+struct mbuf *
+ieee80211_wep_decrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+
+int ieee80211_tkip_set_key(struct ieee80211com *, struct ieee80211_key *);
+void ieee80211_tkip_delete_key(struct ieee80211com *, struct ieee80211_key *);
+struct mbuf *ieee80211_tkip_encrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+struct mbuf *ieee80211_tkip_decrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+
+int ieee80211_ccmp_set_key(struct ieee80211com *, struct ieee80211_key *);
+void ieee80211_ccmp_delete_key(struct ieee80211com *, struct ieee80211_key *);
+struct mbuf *ieee80211_ccmp_encrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+struct mbuf *ieee80211_ccmp_decrypt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_key *);
+
+extern void ieee80211_tkip_mic(struct mbuf *, int, const u_int8_t *,
+ u_int8_t[IEEE80211_TKIP_MICLEN]);
+extern void ieee80211_michael_mic_failure(struct ieee80211com *, u_int64_t);
+
extern void ieee80211_derive_ptk(const u_int8_t *, size_t, const u_int8_t *,
const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *,
size_t);
extern int ieee80211_cipher_keylen(enum ieee80211_cipher);
extern void ieee80211_map_ptk(const struct ieee80211_ptk *,
- enum ieee80211_cipher, struct ieee80211_key *);
+ enum ieee80211_cipher, u_int64_t, struct ieee80211_key *);
extern void ieee80211_map_gtk(const u_int8_t *, enum ieee80211_cipher, int,
int, u_int64_t, struct ieee80211_key *);
+
#endif /* _NET80211_IEEE80211_CRYPTO_H_ */
diff --git a/sys/net80211/ieee80211_crypto_ccmp.c b/sys/net80211/ieee80211_crypto_ccmp.c
new file mode 100644
index 00000000000..c55e8928f35
--- /dev/null
+++ b/sys/net80211/ieee80211_crypto_ccmp.c
@@ -0,0 +1,455 @@
+/* $OpenBSD: ieee80211_crypto_ccmp.c,v 1.1 2008/04/16 18:32:15 damien Exp $ */
+
+/*-
+ * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/if_llc.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_crypto.h>
+
+#include <crypto/rijndael.h>
+
+/* CCMP software crypto context */
+struct ieee80211_ccmp_ctx {
+ rijndael_ctx rijndael;
+};
+
+/*
+ * Initialize software crypto context. This function can be overridden
+ * by drivers doing hardware crypto.
+ */
+int
+ieee80211_ccmp_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ struct ieee80211_ccmp_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctx == NULL)
+ return ENOMEM;
+ rijndael_set_key_enc_only(&ctx->rijndael, k->k_key, 128);
+ k->k_priv = ctx;
+ return 0;
+}
+
+void
+ieee80211_ccmp_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ if (k->k_priv != NULL)
+ free(k->k_priv, M_DEVBUF);
+ k->k_priv = NULL;
+}
+
+/*
+ * Counter with CBC-MAC (CCM) - see RFC3610.
+ * CCMP uses the following CCM parameters: M = 8, L = 2
+ */
+static void
+ieee80211_ccmp_phase1(rijndael_ctx *ctx, const struct ieee80211_frame *wh,
+ u_int64_t pn, int lm, u_int8_t b[16], u_int8_t a[16], u_int8_t s0[16])
+{
+ u_int8_t auth[32], nonce[13];
+ u_int8_t *aad;
+ u_int8_t tid = 0;
+ int la, i;
+
+ /* construct AAD (additional authentication data) */
+ aad = &auth[2]; /* skip l(a), will be filled later */
+ *aad++ = wh->i_fc[0] & ~IEEE80211_FC0_SUBTYPE_MASK;
+ /* NB: 'Protected' bit is already set in wh->i_fc[1] */
+ /* 'Order' bit was added as part of 802.11n-Draft 2.0 */
+ *aad++ = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_ORDER |
+ IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA);
+ IEEE80211_ADDR_COPY(aad, wh->i_addr1); aad += IEEE80211_ADDR_LEN;
+ IEEE80211_ADDR_COPY(aad, wh->i_addr2); aad += IEEE80211_ADDR_LEN;
+ IEEE80211_ADDR_COPY(aad, wh->i_addr3); aad += IEEE80211_ADDR_LEN;
+ *aad++ = wh->i_seq[0] & ~0xf0;
+ *aad++ = 0;
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
+ IEEE80211_FC1_DIR_DSTODS) {
+ const struct ieee80211_frame_addr4 *wh4 =
+ (const struct ieee80211_frame_addr4 *)wh;
+ IEEE80211_ADDR_COPY(aad, wh4->i_addr4);
+ aad += IEEE80211_ADDR_LEN;
+ if ((wh->i_fc[0] &
+ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
+ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) {
+ const struct ieee80211_qosframe_addr4 *qwh4 =
+ (const struct ieee80211_qosframe_addr4 *)wh;
+ *aad++ = tid = qwh4->i_qos[0] & 0x0f;
+ *aad++ = 0;
+ }
+ } else if ((wh->i_fc[0] &
+ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
+ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) {
+ const struct ieee80211_qosframe *qwh =
+ (const struct ieee80211_qosframe *)wh;
+ *aad++ = tid = qwh->i_qos[0] & 0x0f;
+ *aad++ = 0;
+ }
+
+ /* construct CCM nonce */
+ nonce[0] = tid;
+ IEEE80211_ADDR_COPY(&nonce[1], wh->i_addr2);
+ nonce[7] = pn >> 40; /* PN5 */
+ nonce[8] = pn >> 32; /* PN4 */
+ nonce[9] = pn >> 24; /* PN3 */
+ nonce[10] = pn >> 16; /* PN2 */
+ nonce[11] = pn >> 8; /* PN1 */
+ nonce[12] = pn; /* PN0 */
+
+ /* add 2 authentication blocks (including l(a) and padded AAD) */
+ la = aad - &auth[2]; /* fill l(a) */
+ auth[0] = la >> 8;
+ auth[1] = la & 0xff;
+ memset(aad, 0, 30 - la); /* pad AAD with zeros */
+
+ /* construct first block B_0 */
+ b[0] = 89; /* Flags = 64*Adata + 8*((M-2)/2) + (L-1) */
+ memcpy(&b[1], nonce, 13);
+ b[14] = lm >> 8;
+ b[15] = lm & 0xff;
+ rijndael_encrypt(ctx, b, b);
+
+ for (i = 0; i < 16; i++)
+ b[i] ^= auth[i];
+ rijndael_encrypt(ctx, b, b);
+ for (i = 0; i < 16; i++)
+ b[i] ^= auth[16 + i];
+ rijndael_encrypt(ctx, b, b);
+
+ /* construct S_0 */
+ a[0] = 1; /* Flags = L' = (L-1) */
+ memcpy(&a[1], nonce, 13);
+ a[14] = a[15] = 0;
+ rijndael_encrypt(ctx, a, s0);
+}
+
+struct mbuf *
+ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_ccmp_ctx *ctx = k->k_priv;
+ const struct ieee80211_frame *wh;
+ const u_int8_t *src;
+ u_int8_t *ivp, *mic, *dst;
+ u_int8_t a[16], b[16], s0[16], s[16];
+ struct mbuf *n0, *m, *n;
+ int hdrlen, left, moff, noff, len;
+ u_int16_t ctr;
+ int i, j;
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len += IEEE80211_CCMP_HDRLEN;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_CCMP_MICLEN) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* copy 802.11 header */
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+
+ k->k_tsc++; /* increment the 48-bit PN */
+
+ /* construct CCMP header */
+ ivp = mtod(n0, u_int8_t *) + hdrlen;
+ ivp[0] = k->k_tsc; /* PN0 */
+ ivp[1] = k->k_tsc >> 8; /* PN1 */
+ ivp[2] = 0; /* Rsvd */
+ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
+ ivp[4] = k->k_tsc >> 16; /* PN2 */
+ ivp[5] = k->k_tsc >> 24; /* PN3 */
+ ivp[6] = k->k_tsc >> 32; /* PN4 */
+ ivp[7] = k->k_tsc >> 40; /* PN5 */
+
+ /* construct initial B, A and S_0 blocks */
+ ieee80211_ccmp_phase1(&ctx->rijndael, wh, k->k_tsc,
+ m0->m_pkthdr.len - hdrlen, b, a, s0);
+
+ /* construct S_1 */
+ ctr = 1;
+ a[14] = ctr >> 8;
+ a[15] = ctr & 0xff;
+ rijndael_encrypt(&ctx->rijndael, a, s);
+
+ /* encrypt frame body and compute MIC */
+ j = 0;
+ m = m0;
+ n = n0;
+ moff = hdrlen;
+ noff = hdrlen + IEEE80211_CCMP_HDRLEN;
+ left = m0->m_pkthdr.len - moff;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN - IEEE80211_CCMP_MICLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ src = mtod(m, u_int8_t *) + moff;
+ dst = mtod(n, u_int8_t *) + noff;
+ for (i = 0; i < len; i++) {
+ /* update MIC with clear text */
+ b[j] ^= src[i];
+ /* encrypt message */
+ dst[i] = src[i] ^ s[j];
+ if (++j < 16)
+ continue;
+ /* we have a full block, encrypt MIC */
+ rijndael_encrypt(&ctx->rijndael, b, b);
+ /* construct a new S_ctr block */
+ ctr++;
+ a[14] = ctr >> 8;
+ a[15] = ctr & 0xff;
+ rijndael_encrypt(&ctx->rijndael, a, s);
+ j = 0;
+ }
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+ if (j != 0) /* partial block, encrypt MIC */
+ rijndael_encrypt(&ctx->rijndael, b, b);
+
+ /* reserve trailing space for MIC */
+ if (M_TRAILINGSPACE(n) < IEEE80211_CCMP_MICLEN) {
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = 0;
+ }
+ /* finalize MIC, U := T XOR first-M-bytes( S_O ) */
+ mic = mtod(n, u_int8_t *) + n->m_len;
+ for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
+ mic[i] = b[i] ^ s0[i];
+ n->m_len += IEEE80211_CCMP_MICLEN;
+ n0->m_pkthdr.len += IEEE80211_CCMP_MICLEN;
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_tx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
+
+struct mbuf *
+ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_ccmp_ctx *ctx = k->k_priv;
+ struct ieee80211_frame *wh;
+ u_int64_t pn;
+ const u_int8_t *ivp, *src;
+ u_int8_t *dst;
+ u_int8_t mic0[IEEE80211_CCMP_MICLEN];
+ u_int8_t a[16], b[16], s0[16], s[16];
+ struct mbuf *n0, *m, *n;
+ int hdrlen, left, moff, noff, len;
+ u_int16_t ctr;
+ int i, j;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ ivp = (u_int8_t *)wh + hdrlen;
+
+ if (m0->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN +
+ IEEE80211_CCMP_MICLEN) {
+ m_freem(m0);
+ return NULL;
+ }
+ /* check that ExtIV bit is be set */
+ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
+ m_freem(m0);
+ return NULL;
+ }
+ /* extract the 48-bit PN from the CCMP header */
+ pn = (u_int64_t)ivp[0] |
+ (u_int64_t)ivp[1] << 8 |
+ (u_int64_t)ivp[4] << 16 |
+ (u_int64_t)ivp[5] << 24 |
+ (u_int64_t)ivp[6] << 32 |
+ (u_int64_t)ivp[7] << 40;
+ if (pn <= k->k_rsc[0]) {
+ /* replayed frame, discard */
+ m_freem(m0);
+ return NULL;
+ }
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len -= IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* construct initial B, A and S_0 blocks */
+ ieee80211_ccmp_phase1(&ctx->rijndael, wh, pn,
+ n0->m_pkthdr.len - hdrlen, b, a, s0);
+
+ /* copy 802.11 header and clear protected bit */
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+ wh = mtod(n0, struct ieee80211_frame *);
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ /* construct S_1 */
+ ctr = 1;
+ a[14] = ctr >> 8;
+ a[15] = ctr & 0xff;
+ rijndael_encrypt(&ctx->rijndael, a, s);
+
+ /* decrypt frame body and compute MIC */
+ j = 0;
+ m = m0;
+ n = n0;
+ moff = hdrlen + IEEE80211_CCMP_HDRLEN;
+ noff = hdrlen;
+ left = n0->m_pkthdr.len - noff;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ src = mtod(m, u_int8_t *) + moff;
+ dst = mtod(n, u_int8_t *) + noff;
+ for (i = 0; i < len; i++) {
+ /* decrypt message */
+ dst[i] = src[i] ^ s[j];
+ /* update MIC with clear text */
+ b[j] ^= dst[i];
+ if (++j < 16)
+ continue;
+ /* we have a full block, encrypt MIC */
+ rijndael_encrypt(&ctx->rijndael, b, b);
+ /* construct a new S_ctr block */
+ ctr++;
+ a[14] = ctr >> 8;
+ a[15] = ctr & 0xff;
+ rijndael_encrypt(&ctx->rijndael, a, s);
+ j = 0;
+ }
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+ if (j != 0) /* partial block, encrypt MIC */
+ rijndael_encrypt(&ctx->rijndael, b, b);
+
+ /* finalize MIC, U := T XOR first-M-bytes( S_O ) */
+ for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
+ b[i] ^= s0[i];
+
+ /* check that it matches the MIC in received frame */
+ m_copydata(m, moff, IEEE80211_CCMP_MICLEN, mic0);
+ if (memcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0) {
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+ }
+
+ /*
+ * Update last seen packet number (note that it must be done
+ * after MIC is validated.)
+ */
+ k->k_rsc[0] = pn;
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_rx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
diff --git a/sys/net80211/ieee80211_crypto_tkip.c b/sys/net80211/ieee80211_crypto_tkip.c
new file mode 100644
index 00000000000..53af48dca29
--- /dev/null
+++ b/sys/net80211/ieee80211_crypto_tkip.c
@@ -0,0 +1,707 @@
+/* $OpenBSD: ieee80211_crypto_tkip.c,v 1.1 2008/04/16 18:32:15 damien Exp $ */
+
+/*-
+ * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/if_llc.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_crypto.h>
+
+#include <crypto/arc4.h>
+#include <crypto/michael.h>
+
+typedef u_int8_t byte; /* 8-bit byte (octet) */
+typedef u_int16_t u16b; /* 16-bit unsigned word */
+typedef u_int32_t u32b; /* 32-bit unsigned word */
+
+static void Phase1(u16b *, const byte *, const byte *, u32b);
+static void Phase2(byte *, const byte *, const u16b *, u16b);
+
+/* TKIP software crypto context */
+struct ieee80211_tkip_ctx {
+ struct rc4_ctx rc4;
+ const u_int8_t *txmic;
+ const u_int8_t *rxmic;
+ u_int16_t TTAK1[5];
+ u_int16_t TTAK2[5];
+};
+
+/*
+ * Initialize software crypto context. This function can be overridden
+ * by drivers doing hardware crypto.
+ */
+int
+ieee80211_tkip_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ struct ieee80211_tkip_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctx == NULL)
+ return ENOMEM;
+ /*
+ * Use bits 128-191 as the Michael key for AA->SPA and bits
+ * 192-255 as the Michael key for SPA->AA.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ ctx->txmic = &k->k_key[16];
+ ctx->rxmic = &k->k_key[24];
+ } else {
+ ctx->rxmic = &k->k_key[16];
+ ctx->txmic = &k->k_key[24];
+ }
+ k->k_priv = ctx;
+ return 0;
+}
+
+void
+ieee80211_tkip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ if (k->k_priv != NULL)
+ free(k->k_priv, M_DEVBUF);
+ k->k_priv = NULL;
+}
+
+/* pseudo-header used for TKIP MIC computation */
+struct ieee80211_tkip_frame {
+ u_int8_t i_da[IEEE80211_ADDR_LEN];
+ u_int8_t i_sa[IEEE80211_ADDR_LEN];
+ u_int8_t i_pri;
+ u_int8_t i_pad[3];
+} __packed;
+
+/*
+ * Compute TKIP MIC over an mbuf chain starting "off" bytes from the
+ * beginning. This function should be kept independant from the software
+ * TKIP crypto code so that drivers doing hardware crypto but not MIC can
+ * call it without a software crypto context.
+ */
+void
+ieee80211_tkip_mic(struct mbuf *m0, int off, const u_int8_t *key,
+ u_int8_t mic[IEEE80211_TKIP_MICLEN])
+{
+ const struct ieee80211_frame *wh;
+ struct ieee80211_tkip_frame wht;
+ MICHAEL_CTX ctx; /* small enough */
+ struct mbuf *m;
+ caddr_t pos;
+ int len;
+
+ /* assumes 802.11 header is contiguous */
+ wh = mtod(m0, struct ieee80211_frame *);
+
+ /* construct pseudo-header for TKIP MIC computation */
+ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
+ case IEEE80211_FC1_DIR_NODS:
+ IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1);
+ IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2);
+ break;
+ case IEEE80211_FC1_DIR_TODS:
+ IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr3);
+ IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2);
+ break;
+ case IEEE80211_FC1_DIR_FROMDS:
+ IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1);
+ IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr3);
+ break;
+ case IEEE80211_FC1_DIR_DSTODS:
+ /* not yet supported */
+ break;
+ }
+ if ((wh->i_fc[0] &
+ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
+ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) {
+ const struct ieee80211_qosframe *qwh =
+ (const struct ieee80211_qosframe *)wh;
+ wht.i_pri = qwh->i_qos[0] & 0xf;
+ } else
+ wht.i_pri = 0;
+ wht.i_pad[0] = wht.i_pad[1] = wht.i_pad[2] = 0;
+
+ michael_init(&ctx);
+ michael_key(key, &ctx);
+
+ michael_update(&ctx, (caddr_t)&wht, sizeof(wht));
+
+ m = m0;
+ /* assumes the first "off" bytes are contiguous */
+ pos = mtod(m, caddr_t) + off;
+ len = m->m_len - off;
+ for (;;) {
+ michael_update(&ctx, pos, len);
+ if ((m = m->m_next) == NULL)
+ break;
+ pos = mtod(m, caddr_t);
+ len = m->m_len;
+ }
+
+ michael_final(mic, &ctx);
+}
+
+/* shortcuts */
+#define IEEE80211_TKIP_TAILLEN \
+ (IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN)
+#define IEEE80211_TKIP_OVHD \
+ (IEEE80211_TKIP_HDRLEN + IEEE80211_TKIP_TAILLEN)
+
+struct mbuf *
+ieee80211_tkip_encrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_tkip_ctx *ctx = k->k_priv;
+ u_int8_t wepseed[16];
+ const struct ieee80211_frame *wh;
+ u_int8_t *ivp, *mic, *icvp;
+ struct mbuf *n0, *m, *n;
+ u_int32_t crc;
+ int left, moff, noff, len, hdrlen;
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len += IEEE80211_TKIP_HDRLEN;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_TKIP_TAILLEN) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* copy 802.11 header */
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+
+ /* construct TKIP header */
+ ivp = mtod(n0, u_int8_t *) + hdrlen;
+ ivp[0] = k->k_tsc >> 8; /* TSC1 */
+ /* WEP Seed = (TSC1 | 0x20) & 0x7f (see 8.3.2.2) */
+ ivp[1] = (ivp[0] | 0x20) & 0x7f;
+ ivp[2] = k->k_tsc; /* TSC0 */
+ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
+ ivp[4] = k->k_tsc >> 16; /* TSC2 */
+ ivp[5] = k->k_tsc >> 24; /* TSC3 */
+ ivp[6] = k->k_tsc >> 32; /* TSC4 */
+ ivp[7] = k->k_tsc >> 40; /* TSC5 */
+
+ /* compute WEP seed */
+#ifdef notyet
+ if ((k->k_tsc & 0xffff) == 0)
+#endif
+ Phase1(ctx->TTAK1, k->k_key, wh->i_addr2, k->k_tsc >> 16);
+ Phase2(wepseed, k->k_key, ctx->TTAK1, k->k_tsc & 0xffff);
+ rc4_keysetup(&ctx->rc4, wepseed, 16);
+
+ /* encrypt frame body and compute WEP ICV */
+ m = m0;
+ n = n0;
+ moff = hdrlen;
+ noff = hdrlen + IEEE80211_TKIP_HDRLEN;
+ left = m0->m_pkthdr.len - moff;
+ crc = ~0;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN - IEEE80211_TKIP_TAILLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ crc = ieee80211_crc_update(crc, mtod(m, caddr_t) + moff, len);
+ rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
+ mtod(n, caddr_t) + noff, len);
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+
+ /* reserve trailing space for TKIP MIC and WEP ICV */
+ if (M_TRAILINGSPACE(n) < IEEE80211_TKIP_TAILLEN) {
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = 0;
+ }
+
+ /* compute TKIP MIC over clear text */
+ mic = mtod(n, caddr_t) + n->m_len;
+ ieee80211_tkip_mic(m0, hdrlen, ctx->txmic, mic);
+ crc = ieee80211_crc_update(crc, mic, IEEE80211_TKIP_MICLEN);
+ rc4_crypt(&ctx->rc4, mic, mic, IEEE80211_TKIP_MICLEN);
+ n->m_len += IEEE80211_TKIP_MICLEN;
+
+ /* finalize WEP ICV */
+ icvp = mtod(n, caddr_t) + n->m_len;
+ crc = ~crc;
+ icvp[0] = crc;
+ icvp[1] = crc >> 8;
+ icvp[2] = crc >> 16;
+ icvp[3] = crc >> 24;
+ rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
+ n->m_len += IEEE80211_WEP_CRCLEN;
+
+ n0->m_pkthdr.len += IEEE80211_TKIP_TAILLEN;
+
+ k->k_tsc++; /* increment the 48-bit TSC */
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_tx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
+
+struct mbuf *
+ieee80211_tkip_decrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_tkip_ctx *ctx = k->k_priv;
+ struct ieee80211_frame *wh;
+ u_int8_t wepseed[16];
+ u_int8_t buf[IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN];
+ u_int8_t mic[IEEE80211_TKIP_MICLEN];
+ u_int64_t tsc;
+ u_int32_t crc, crc0;
+ u_int8_t *ivp, *mic0;
+ struct mbuf *n0, *m, *n;
+ int hdrlen, left, moff, noff, len;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+
+ if (m0->m_pkthdr.len < hdrlen + IEEE80211_TKIP_OVHD) {
+ m_freem(m0);
+ return NULL;
+ }
+
+ ivp = (u_int8_t *)wh + hdrlen;
+ /* check that ExtIV bit is be set */
+ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
+ m_freem(m0);
+ return NULL;
+ }
+ /* extract the 48-bit TSC from the TKIP header */
+ tsc = (u_int64_t)ivp[2] |
+ (u_int64_t)ivp[0] << 8 |
+ (u_int64_t)ivp[4] << 16 |
+ (u_int64_t)ivp[5] << 24 |
+ (u_int64_t)ivp[6] << 32 |
+ (u_int64_t)ivp[7] << 40;
+ /* NB: the keys are refreshed, we'll never overflow the 48 bits */
+ if (tsc <= k->k_rsc[0]) {
+ /* replayed frame, discard */
+ m_freem(m0);
+ return NULL;
+ }
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len -= IEEE80211_TKIP_OVHD;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* copy 802.11 header and clear protected bit */
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+ wh = mtod(n0, struct ieee80211_frame *);
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ /* compute WEP seed */
+#ifdef notyet
+ if (k->k_rsc[0] == 0 || ((tsc >> 16) != (k->k_rsc[0] >> 16)))
+#endif
+ Phase1(ctx->TTAK2, k->k_key, wh->i_addr2, tsc >> 16);
+ Phase2(wepseed, k->k_key, ctx->TTAK2, tsc & 0xffff);
+ rc4_keysetup(&ctx->rc4, wepseed, 16);
+
+ /* decrypt frame body and compute WEP ICV */
+ m = m0;
+ n = n0;
+ moff = hdrlen + IEEE80211_TKIP_HDRLEN;
+ noff = hdrlen;
+ left = n0->m_pkthdr.len - noff;
+ crc = ~0;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
+ mtod(n, caddr_t) + noff, len);
+ crc = ieee80211_crc_update(crc, mtod(n, caddr_t) + noff, len);
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+
+ /* extract and decrypt TKIP MIC and WEP ICV from m0's tail */
+ m_copydata(m, moff, IEEE80211_TKIP_TAILLEN, buf);
+ rc4_crypt(&ctx->rc4, buf, buf, IEEE80211_TKIP_TAILLEN);
+
+ /* include TKIP MIC in WEP ICV */
+ mic0 = buf;
+ crc = ieee80211_crc_update(crc, mic0, IEEE80211_TKIP_MICLEN);
+ crc = ~crc;
+
+ /* decrypt ICV and compare it with calculated ICV */
+ crc0 = *(u_int32_t *)(buf + IEEE80211_TKIP_MICLEN);
+ if (crc != letoh32(crc0)) {
+ ic->ic_stats.is_rx_decryptcrc++;
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+ }
+
+ /* compute TKIP MIC over decrypted message */
+ ieee80211_tkip_mic(n0, hdrlen, ctx->rxmic, mic);
+ /* check that it matches the MIC in received frame */
+ if (memcmp(mic0, mic, IEEE80211_TKIP_MICLEN) != 0) {
+ m_freem(m0);
+ m_freem(n0);
+ ic->ic_stats.is_rx_locmicfail++;
+ ieee80211_michael_mic_failure(ic, tsc);
+ return NULL;
+ }
+
+ /*
+ * Update last seen packet number (note that it must be done
+ * after MIC is validated.)
+ */
+ k->k_rsc[0] = tsc;
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_rx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
+
+/*
+ * This function is called in HostAP mode to deauthenticate all STAs using
+ * TKIP as their pairwise or group cipher (as part of TKIP countermeasures).
+ */
+static void
+ieee80211_tkip_deauth(void *arg, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = arg;
+
+ if (ni->ni_state == IEEE80211_STA_ASSOC &&
+ (ic->ic_bss->ni_rsngroupcipher == IEEE80211_CIPHER_TKIP ||
+ ni->ni_rsncipher == IEEE80211_CIPHER_TKIP)) {
+ /* deauthenticate STA */
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_MIC_FAILURE);
+ ieee80211_node_leave(ic, ni);
+ }
+}
+
+/*
+ * This function can be called by the software TKIP crypto code or by the
+ * drivers when their hardware crypto engines detect a Michael MIC failure.
+ */
+void
+ieee80211_michael_mic_failure(struct ieee80211com *ic, u_int64_t tsc)
+{
+ extern int ticks;
+
+ if (ic->ic_flags & IEEE80211_F_COUNTERM)
+ return; /* countermeasures already active */
+
+ log(LOG_WARNING, "%s: Michael MIC failure", ic->ic_if.if_xname);
+
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ /* send a Michael MIC Failure Report frame to the AP */
+ (void)ieee80211_send_eapol_key_req(ic, ic->ic_bss,
+ EAPOL_KEY_KEYMIC | EAPOL_KEY_ERROR | EAPOL_KEY_SECURE,
+ tsc);
+ }
+ /*
+ * Activate TKIP countermeasures (see 8.3.2.4) if less than 60
+ * seconds have passed since the most recent previous MIC failure.
+ */
+ if (ic->ic_tkip_micfail == 0 ||
+ ticks >= ic->ic_tkip_micfail + 60 * hz) {
+ ic->ic_tkip_micfail = ticks;
+ return;
+ }
+ ic->ic_tkip_micfail = ticks;
+
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ /* refuse new TKIP associations for the next 60 seconds */
+ ic->ic_flags |= IEEE80211_F_COUNTERM;
+
+ /* deauthenticate all currently associated STAs using TKIP */
+ ieee80211_iterate_nodes(ic, ieee80211_tkip_deauth, ic);
+
+ } else if (ic->ic_opmode == IEEE80211_M_STA) {
+ /* deauthenticate from the AP.. */
+ IEEE80211_SEND_MGMT(ic, ic->ic_bss,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_MIC_FAILURE);
+ /* ..and find another one */
+ (void)ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ }
+}
+
+/***********************************************************************
+ Contents: Generate IEEE 802.11 per-frame RC4 key hash test vectors
+ Date: April 19, 2002
+ Notes:
+ This code is written for pedagogical purposes, NOT for performance.
+************************************************************************/
+
+/* macros for extraction/creation of byte/u16b values */
+#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
+#define Lo8(v16) ((byte)( (v16) & 0x00FF))
+#define Hi8(v16) ((byte)(((v16) >> 8) & 0x00FF))
+#define Lo16(v32) ((u16b)( (v32) & 0xFFFF))
+#define Hi16(v32) ((u16b)(((v32) >>16) & 0xFFFF))
+#define Mk16(hi,lo) ((lo) ^ (((u16b)(hi)) << 8))
+
+/* select the Nth 16-bit word of the Temporal Key byte array TK[] */
+#define TK16(N) Mk16(TK[2 * (N) + 1], TK[2 * (N)])
+
+/* S-box lookup: 16 bits --> 16 bits */
+#define _S_(v16) (Sbox[Lo8(v16)] ^ swap16(Sbox[Hi8(v16)]))
+
+/* fixed algorithm "parameters" */
+#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */
+#define TA_SIZE 6 /* 48-bit transmitter address */
+#define TK_SIZE 16 /* 128-bit Temporal Key */
+#define P1K_SIZE 10 /* 80-bit Phase1 key */
+#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */
+
+/* 2-byte by 2-byte subset of the full AES S-box table */
+static const u16b Sbox[256]= /* Sbox for hash */
+{
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A
+};
+
+/*
+ **********************************************************************
+ * Routine: Phase 1 -- generate P1K, given TA, TK, IV32
+ *
+ * Inputs:
+ * TK[] = Temporal Key [128 bits]
+ * TA[] = transmitter's MAC address [ 48 bits]
+ * IV32 = upper 32 bits of IV [ 32 bits]
+ * Output:
+ * P1K[] = Phase 1 key [ 80 bits]
+ *
+ * Note:
+ * This function only needs to be called every 2**16 frames,
+ * although in theory it could be called every frame.
+ *
+ **********************************************************************
+ */
+static void
+Phase1(u16b *P1K, const byte *TK, const byte *TA, u32b IV32)
+{
+ int i;
+
+ /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */
+ P1K[0] = Lo16(IV32);
+ P1K[1] = Hi16(IV32);
+ P1K[2] = Mk16(TA[1], TA[0]); /* use TA[] as little-endian */
+ P1K[3] = Mk16(TA[3], TA[2]);
+ P1K[4] = Mk16(TA[5], TA[4]);
+
+ /* Now compute an unbalanced Feistel cipher with 80-bit block */
+ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */
+ for (i = 0; i < PHASE1_LOOP_CNT; i++) {
+ /* Each add operation here is mod 2**16 */
+ P1K[0] += _S_(P1K[4] ^ TK16((i & 1) + 0));
+ P1K[1] += _S_(P1K[0] ^ TK16((i & 1) + 2));
+ P1K[2] += _S_(P1K[1] ^ TK16((i & 1) + 4));
+ P1K[3] += _S_(P1K[2] ^ TK16((i & 1) + 6));
+ P1K[4] += _S_(P1K[3] ^ TK16((i & 1) + 0));
+ P1K[4] += i; /* avoid "slide attacks" */
+ }
+}
+
+/*
+ **********************************************************************
+ * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
+ *
+ * Inputs:
+ * TK[] = Temporal Key [128 bits]
+ * P1K[] = Phase 1 output key [ 80 bits]
+ * IV16 = low 16 bits of IV counter [ 16 bits]
+ * Output:
+ * RC4KEY[] = the key used to encrypt the frame [128 bits]
+ *
+ * Note:
+ * The value {TA,IV32,IV16} for Phase1/Phase2 must be unique
+ * across all frames using the same key TK value. Then, for a
+ * given value of TK[], this TKIP48 construction guarantees that
+ * the final RC4KEY value is unique across all frames.
+ *
+ * Suggested implementation optimization: if PPK[] is "overlaid"
+ * appropriately on RC4KEY[], there is no need for the final
+ * for loop below that copies the PPK[] result into RC4KEY[].
+ *
+ **********************************************************************
+ */
+static void
+Phase2(byte *RC4KEY, const byte *TK, const u16b *P1K, u16b IV16)
+{
+ u16b PPK[6]; /* temporary key for mixing */
+ int i;
+
+ /* all adds in the PPK[] equations below are mod 2**16 */
+ for (i = 0; i < 5; i++)
+ PPK[i] = P1K[i]; /* first, copy P1K to PPK */
+ PPK[5] = P1K[4] + IV16; /* next, add in IV16 */
+
+ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */
+ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */
+ PPK[1] += _S_(PPK[0] ^ TK16(1));
+ PPK[2] += _S_(PPK[1] ^ TK16(2));
+ PPK[3] += _S_(PPK[2] ^ TK16(3));
+ PPK[4] += _S_(PPK[3] ^ TK16(4));
+ PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */
+
+ /* Final sweep: bijective, linear. Rotates kill LSB correlations */
+ PPK[0] += RotR1(PPK[5] ^ TK16(6));
+ PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */
+ PPK[2] += RotR1(PPK[1]);
+ PPK[3] += RotR1(PPK[2]);
+ PPK[4] += RotR1(PPK[3]);
+ PPK[5] += RotR1(PPK[4]);
+
+ /* At this point, for a given key TK[0..15], the 96-bit output */
+ /* value PPK[0..5] is guaranteed to be unique, as a function */
+ /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */
+ /* is now a keyed permutation of {TA,IV32,IV16}. */
+ /* Set RC4KEY[0..3], which includes cleartext portion of RC4 key */
+ RC4KEY[0] = Hi8(IV16); /* RC4KEY[0..2] is the WEP IV */
+ RC4KEY[1] =(Hi8(IV16) | 0x20) & 0x7F; /* Help avoid FMS weak keys */
+ RC4KEY[2] = Lo8(IV16);
+ RC4KEY[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
+
+ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */
+ for (i = 0; i < 6; i++) {
+ RC4KEY[4 + 2 * i] = Lo8(PPK[i]);
+ RC4KEY[5 + 2 * i] = Hi8(PPK[i]);
+ }
+}
diff --git a/sys/net80211/ieee80211_crypto_wep.c b/sys/net80211/ieee80211_crypto_wep.c
new file mode 100644
index 00000000000..0e639558b70
--- /dev/null
+++ b/sys/net80211/ieee80211_crypto_wep.c
@@ -0,0 +1,305 @@
+/* $OpenBSD: ieee80211_crypto_wep.c,v 1.1 2008/04/16 18:32:15 damien Exp $ */
+
+/*-
+ * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/if_llc.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_crypto.h>
+
+#include <dev/rndvar.h>
+#include <crypto/arc4.h>
+
+/* WEP software crypto context */
+struct ieee80211_wep_ctx {
+ struct rc4_ctx rc4;
+ u_int32_t iv;
+};
+
+/*
+ * Initialize software crypto context. This function can be overridden
+ * by drivers doing hardware crypto.
+ */
+int
+ieee80211_wep_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ struct ieee80211_wep_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctx == NULL)
+ return ENOMEM;
+ k->k_priv = ctx;
+ return 0;
+}
+
+void
+ieee80211_wep_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+ if (k->k_priv != NULL)
+ free(k->k_priv, M_DEVBUF);
+ k->k_priv = NULL;
+}
+
+/* shortcut */
+#define IEEE80211_WEP_HDRLEN \
+ (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
+
+struct mbuf *
+ieee80211_wep_encrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_wep_ctx *ctx = k->k_priv;
+ u_int8_t wepseed[16];
+ const struct ieee80211_frame *wh;
+ struct mbuf *n0, *m, *n;
+ u_int8_t *ivp, *icvp;
+ u_int32_t iv, crc;
+ int left, moff, noff, len, hdrlen;
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len += IEEE80211_WEP_HDRLEN;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* copy 802.11 header */
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+
+ /* select a new IV for every MPDU */
+ iv = (ctx->iv != 0) ? ctx->iv : arc4random();
+ /* skip weak IVs from Fluhrer/Mantin/Shamir */
+ if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00)
+ iv += 0x000100;
+ ctx->iv = iv + 1;
+ ivp = mtod(n0, u_int8_t *) + hdrlen;
+ ivp[0] = iv;
+ ivp[1] = iv >> 8;
+ ivp[2] = iv >> 16;
+ ivp[3] = k->k_id << 6;
+
+ /* compute WEP seed: concatenate IV and WEP Key */
+ memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
+ memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
+ rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
+
+ /* encrypt frame body and compute WEP ICV */
+ m = m0;
+ n = n0;
+ moff = hdrlen;
+ noff = hdrlen + IEEE80211_WEP_HDRLEN;
+ left = m0->m_pkthdr.len - moff;
+ crc = ~0;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN - IEEE80211_WEP_CRCLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ crc = ieee80211_crc_update(crc, mtod(m, caddr_t) + moff, len);
+ rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
+ mtod(n, caddr_t) + noff, len);
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+
+ /* reserve trailing space for WEP ICV */
+ if (M_TRAILINGSPACE(n) < IEEE80211_WEP_CRCLEN) {
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = 0;
+ }
+
+ /* finalize WEP ICV */
+ icvp = mtod(n, caddr_t) + n->m_len;
+ crc = ~crc;
+ icvp[0] = crc;
+ icvp[1] = crc >> 8;
+ icvp[2] = crc >> 16;
+ icvp[3] = crc >> 24;
+ rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
+ n->m_len += IEEE80211_WEP_CRCLEN;
+ n0->m_pkthdr.len += IEEE80211_WEP_CRCLEN;
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_tx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
+
+struct mbuf *
+ieee80211_wep_decrypt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_key *k)
+{
+ struct ieee80211_wep_ctx *ctx = k->k_priv;
+ struct ieee80211_frame *wh;
+ u_int8_t wepseed[16];
+ u_int32_t crc, crc0;
+ u_int8_t *ivp;
+ struct mbuf *n0, *m, *n;
+ int hdrlen, left, moff, noff, len;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+
+ if (m0->m_pkthdr.len < hdrlen + IEEE80211_WEP_TOTLEN) {
+ m_freem(m0);
+ return NULL;
+ }
+
+ /* concatenate IV and WEP Key */
+ ivp = (u_int8_t *)wh + hdrlen;
+ memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
+ memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
+ rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
+
+ MGET(n0, M_DONTWAIT, m0->m_type);
+ if (n0 == NULL)
+ goto nospace;
+ M_DUP_PKTHDR(n0, m0);
+ n0->m_pkthdr.len -= IEEE80211_WEP_TOTLEN;
+ n0->m_len = MHLEN;
+ if (n0->m_pkthdr.len >= MINCLSIZE) {
+ MCLGET(n0, M_DONTWAIT);
+ if (n0->m_flags & M_EXT)
+ n0->m_len = n0->m_ext.ext_size;
+ }
+ if (n0->m_len > n0->m_pkthdr.len)
+ n0->m_len = n0->m_pkthdr.len;
+
+ /* copy 802.11 header and clear protected bit */
+ memcpy(mtod(n0, caddr_t), wh, hdrlen);
+ wh = mtod(n0, struct ieee80211_frame *);
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ /* decrypt frame body and compute WEP ICV */
+ m = m0;
+ n = n0;
+ moff = hdrlen + IEEE80211_WEP_HDRLEN;
+ noff = hdrlen;
+ left = n0->m_pkthdr.len - noff;
+ crc = ~0;
+ while (left > 0) {
+ if (moff == m->m_len) {
+ /* nothing left to copy from m */
+ m = m->m_next;
+ moff = 0;
+ }
+ if (noff == n->m_len) {
+ /* n is full and there's more data to copy */
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto nospace;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left > MLEN) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n->m_len > left)
+ n->m_len = left;
+ noff = 0;
+ }
+ len = min(m->m_len - moff, n->m_len - noff);
+
+ rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
+ mtod(n, caddr_t) + noff, len);
+ crc = ieee80211_crc_update(crc, mtod(n, caddr_t) + noff, len);
+
+ moff += len;
+ noff += len;
+ left -= len;
+ }
+
+ /* decrypt ICV and compare it with calculated ICV */
+ m_copydata(m, moff, IEEE80211_WEP_CRCLEN, (caddr_t)&crc0);
+ rc4_crypt(&ctx->rc4, (caddr_t)&crc0, (caddr_t)&crc0,
+ IEEE80211_WEP_CRCLEN);
+ crc = ~crc;
+ if (crc != letoh32(crc0)) {
+ ic->ic_stats.is_rx_decryptcrc++;
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+ }
+
+ m_freem(m0);
+ return n0;
+ nospace:
+ ic->ic_stats.is_rx_nombuf++;
+ m_freem(m0);
+ if (n0 != NULL)
+ m_freem(n0);
+ return NULL;
+}
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index f9b8d6dcc22..5e1228dfd7b 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,9 +1,10 @@
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
-/* $OpenBSD: ieee80211_input.c,v 1.72 2007/10/29 15:40:23 chl Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.73 2008/04/16 18:32:15 damien Exp $ */
+
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
- * Copyright (c) 2007 Damien Bergamini
+ * Copyright (c) 2007, 2008 Damien Bergamini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,7 +64,6 @@
#include <dev/rndvar.h>
-
int ieee80211_setup_rates(struct ieee80211com *, struct ieee80211_node *,
const u_int8_t *, const u_int8_t *, int);
void ieee80211_auth_open(struct ieee80211com *,
@@ -75,30 +75,30 @@ int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
int ieee80211_parse_wmm_params(struct ieee80211com *, const u_int8_t *);
enum ieee80211_cipher ieee80211_parse_rsn_cipher(const u_int8_t[]);
enum ieee80211_akm ieee80211_parse_rsn_akm(const u_int8_t[]);
-int ieee80211_parse_rsn_body(struct ieee80211com *,
- struct ieee80211_node *, const u_int8_t *, u_int);
-int ieee80211_parse_rsn(struct ieee80211com *, struct ieee80211_node *,
- const u_int8_t *);
-int ieee80211_parse_wpa1(struct ieee80211com *, struct ieee80211_node *,
- const u_int8_t *);
+int ieee80211_parse_rsn_body(struct ieee80211com *, const u_int8_t *,
+ u_int, struct ieee80211_rsnparams *);
+int ieee80211_parse_rsn(struct ieee80211com *, const u_int8_t *,
+ struct ieee80211_rsnparams *);
+int ieee80211_parse_wpa(struct ieee80211com *, const u_int8_t *,
+ struct ieee80211_rsnparams *);
int ieee80211_save_ie(const u_int8_t *, u_int8_t **);
void ieee80211_recv_pspoll(struct ieee80211com *, struct mbuf *, int,
u_int32_t);
int ieee80211_do_slow_print(struct ieee80211com *, int *);
void ieee80211_recv_probe_resp(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, u_int32_t);
+ struct ieee80211_node *, int, u_int32_t, int);
void ieee80211_recv_probe_req(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, u_int32_t);
void ieee80211_recv_auth(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, u_int32_t);
void ieee80211_recv_assoc_req(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, u_int32_t);
+ struct ieee80211_node *, int, u_int32_t, int);
void ieee80211_recv_assoc_resp(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, u_int32_t);
+ struct ieee80211_node *, int);
void ieee80211_recv_deauth(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, u_int32_t);
+ struct ieee80211_node *);
void ieee80211_recv_disassoc(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, u_int32_t);
+ struct ieee80211_node *);
void ieee80211_recv_4way_msg1(struct ieee80211com *,
struct ieee80211_eapol_key *, struct ieee80211_node *);
void ieee80211_recv_4way_msg2(struct ieee80211com *,
@@ -156,7 +156,7 @@ ieee80211_get_hdrlen(const void *data)
*/
void
ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
- int rssi, u_int32_t rstamp)
+ int rssi, u_int32_t rstamp)
{
struct ieee80211com *ic = (void *)ifp;
struct ieee80211_frame *wh;
@@ -167,7 +167,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
u_int16_t orxseq, nrxseq;
if (ni == NULL)
- panic("null mode");
+ panic("null node");
/* trim CRC here so WEP can find its own CRC at the end of packet. */
if (m->m_flags & M_HASFCS) {
@@ -241,34 +241,35 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
ni->ni_inact = 0;
}
- if (ic->ic_set_tim != NULL &&
- (wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) &&
- ni->ni_pwrsave == 0) {
- /* turn on power save mode */
+ if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_IBSS) && ic->ic_set_tim != NULL) {
+ if ((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) &&
+ ni->ni_pwrsave == 0) {
+ /* turn on power save mode */
- if (ifp->if_flags & IFF_DEBUG)
- printf("%s: power save mode on for %s\n",
- ifp->if_xname, ether_sprintf(wh->i_addr2));
-
- ni->ni_pwrsave = IEEE80211_PS_SLEEP;
- }
- if (ic->ic_set_tim != NULL &&
- !(wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) &&
- ni->ni_pwrsave != 0) {
- /* turn off power save mode, dequeue stored packets */
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: power save mode on for %s\n",
+ ifp->if_xname, ether_sprintf(wh->i_addr2));
- ni->ni_pwrsave = 0;
- (*ic->ic_set_tim)(ic, ni->ni_associd, 0);
+ ni->ni_pwrsave = IEEE80211_PS_SLEEP;
+ }
+ if (!(wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) &&
+ ni->ni_pwrsave != 0) {
+ /* turn off power save mode, dequeue stored packets */
- if (ifp->if_flags & IFF_DEBUG)
- printf("%s: power save mode off for %s\n",
- ifp->if_xname, ether_sprintf(wh->i_addr2));
+ ni->ni_pwrsave = 0;
+ (*ic->ic_set_tim)(ic, ni->ni_associd, 0);
- while (!IF_IS_EMPTY(&ni->ni_savedq)) {
- struct mbuf *m;
- IF_DEQUEUE(&ni->ni_savedq, m);
- IF_ENQUEUE(&ic->ic_pwrsaveq, m);
- (*ifp->if_start)(ifp);
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: power save mode off for %s\n",
+ ifp->if_xname, ether_sprintf(wh->i_addr2));
+
+ while (!IF_IS_EMPTY(&ni->ni_savedq)) {
+ struct mbuf *m;
+ IF_DEQUEUE(&ni->ni_savedq, m);
+ IF_ENQUEUE(&ic->ic_pwrsaveq, m);
+ (*ifp->if_start)(ifp);
+ }
}
}
@@ -371,9 +372,10 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
hdrlen = ieee80211_get_hdrlen(wh);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- m = ieee80211_wep_crypt(ifp, m, 0);
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ if (ic->ic_flags &
+ (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
+ m = ieee80211_decrypt(ic, m, ni);
if (m == NULL) {
ic->ic_stats.is_rx_wepfail++;
goto err;
@@ -384,6 +386,10 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
goto out;
}
}
+ /*
+ * XXX else: drivers should pass a flag to indicate if the
+ * frame was successfully decrypted or not.
+ */
#if NBPFILTER > 0
/* copy to listener after decrypt */
if (ic->ic_rawbpf)
@@ -398,21 +404,24 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
goto err;
}
eh = mtod(m, struct ether_header *);
-#if 0
- if (!ni->ni_port_valid &&
+
+ if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid &&
eh->ether_type != htons(ETHERTYPE_PAE)) {
IEEE80211_DPRINTF(("%s: port not valid: %s\n",
__func__, ether_sprintf(wh->i_addr2)));
ic->ic_stats.is_rx_unauth++;
goto err;
}
-#endif
ifp->if_ipackets++;
- /* perform as a bridge within the AP */
+ /*
+ * Perform as a bridge within the AP. XXX we do not bridge
+ * 802.1X frames as suggested in C.1.1 of IEEE Std 802.1X.
+ */
m1 = NULL;
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
- (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
+ !(ic->ic_flags & IEEE80211_F_NOBRIDGE) &&
+ eh->ether_type != htons(ETHERTYPE_PAE)) {
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
if (m1 == NULL)
@@ -420,6 +429,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
else
m1->m_flags |= M_MCAST;
} else {
+ struct ieee80211_node *ni;
ni = ieee80211_find_node(ic, eh->ether_dhost);
if (ni != NULL) {
if (ni->ni_associd != 0) {
@@ -449,7 +459,11 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
if (ifp->if_bpf && m1 == NULL)
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif
- ether_input_mbuf(ifp, m);
+ if (eh->ether_type == htons(ETHERTYPE_PAE)) {
+ (*ic->ic_recv_eapol)(ic, m, ni);
+ m_freem(m);
+ } else
+ ether_input_mbuf(ifp, m);
}
return;
@@ -823,6 +837,13 @@ ieee80211_auth_open(struct ieee80211com *ic, const struct ieee80211_frame *wh,
ic->ic_state, seq));
return;
}
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ /* XXX not here! */
+ ic->ic_bss->ni_port_valid = 0;
+ ic->ic_bss->ni_replaycnt_ok = 0;
+ (*ic->ic_delete_key)(ic, ic->ic_bss,
+ &ic->ic_bss->ni_pairwise_key);
+ }
if (status != 0) {
if (ifp->if_flags & IFF_DEBUG)
printf("%s: open authentication failed "
@@ -923,8 +944,8 @@ enum ieee80211_cipher
ieee80211_parse_rsn_cipher(const u_int8_t selector[4])
{
/* from IEEE Std 802.11i-2004 - Table 20da */
- if (memcmp(selector, MICROSOFT_OUI, 3) == 0 || /* WPA1 */
- memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN (aka WPA2) */
+ if (memcmp(selector, MICROSOFT_OUI, 3) == 0 || /* WPA */
+ memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN */
switch (selector[3]) {
case 0: /* use group cipher suite */
return IEEE80211_CIPHER_USEGROUP;
@@ -945,8 +966,8 @@ enum ieee80211_akm
ieee80211_parse_rsn_akm(const u_int8_t selector[4])
{
/* from IEEE Std 802.11i-2004 - Table 20dc */
- if (memcmp(selector, MICROSOFT_OUI, 3) == 0 || /* WPA1 */
- memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN (aka WPA2) */
+ if (memcmp(selector, MICROSOFT_OUI, 3) == 0 || /* WPA */
+ memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN */
switch (selector[3]) {
case 1: /* IEEE 802.1X (RSNA default) */
return IEEE80211_AKM_IEEE8021X;
@@ -961,78 +982,79 @@ ieee80211_parse_rsn_akm(const u_int8_t selector[4])
* Parse an RSN element (see 7.3.2.25).
*/
int
-ieee80211_parse_rsn_body(struct ieee80211com *ic, struct ieee80211_node *ni,
- const u_int8_t *frm, u_int len)
+ieee80211_parse_rsn_body(struct ieee80211com *ic, const u_int8_t *frm,
+ u_int len, struct ieee80211_rsnparams *rsn)
{
const u_int8_t *efrm;
u_int16_t m, n, s;
- u_int16_t rsncaps;
- enum ieee80211_cipher group_cipher;
- u_int akmset, pairwise_cipherset;
efrm = frm + len;
/* check Version field */
if (LE_READ_2(frm) != 1)
- return IEEE80211_REASON_RSN_IE_VER_UNSUP;
+ return IEEE80211_STATUS_RSN_IE_VER_UNSUP;
frm += 2;
/* all fields after the Version field are optional */
/* if Cipher Suite missing, default to CCMP */
- ni->ni_group_cipher = IEEE80211_CIPHER_CCMP;
- ni->ni_pairwise_cipherset = IEEE80211_CIPHER_CCMP;
+ rsn->rsn_groupcipher = IEEE80211_CIPHER_CCMP;
+ rsn->rsn_nciphers = 1;
+ rsn->rsn_ciphers = IEEE80211_CIPHER_CCMP;
/* if AKM Suite missing, default to 802.1X */
- ni->ni_akmset = IEEE80211_AKM_IEEE8021X;
+ rsn->rsn_nakms = 1;
+ rsn->rsn_akms = IEEE80211_AKM_IEEE8021X;
+ /* if RSN capabilities missing, default to 0 */
+ rsn->rsn_caps = 0;
/* read Group Cipher Suite field */
if (frm + 4 > efrm)
return 0;
- group_cipher = ieee80211_parse_rsn_cipher(frm);
- if (group_cipher == IEEE80211_CIPHER_USEGROUP)
- return IEEE80211_REASON_BAD_GROUP_CIPHER;
+ rsn->rsn_groupcipher = ieee80211_parse_rsn_cipher(frm);
+ if (rsn->rsn_groupcipher == IEEE80211_CIPHER_USEGROUP)
+ return IEEE80211_STATUS_BAD_GROUP_CIPHER;
frm += 4;
/* read Pairwise Cipher Suite Count field */
if (frm + 2 > efrm)
return 0;
- m = LE_READ_2(frm);
+ m = rsn->rsn_nciphers = LE_READ_2(frm);
frm += 2;
/* read Pairwise Cipher Suite List */
if (frm + m * 4 > efrm)
- return IEEE80211_REASON_IE_INVALID;
- pairwise_cipherset = IEEE80211_CIPHER_NONE;
+ return IEEE80211_STATUS_IE_INVALID;
+ rsn->rsn_ciphers = IEEE80211_CIPHER_NONE;
while (m-- > 0) {
- pairwise_cipherset |= ieee80211_parse_rsn_cipher(frm);
+ rsn->rsn_ciphers |= ieee80211_parse_rsn_cipher(frm);
frm += 4;
}
- if (pairwise_cipherset & IEEE80211_CIPHER_USEGROUP) {
- if (pairwise_cipherset != IEEE80211_CIPHER_USEGROUP)
- return IEEE80211_REASON_BAD_PAIRWISE_CIPHER;
- if (group_cipher == IEEE80211_CIPHER_CCMP)
- return IEEE80211_REASON_BAD_PAIRWISE_CIPHER;
+ if (rsn->rsn_ciphers & IEEE80211_CIPHER_USEGROUP) {
+ if (rsn->rsn_ciphers != IEEE80211_CIPHER_USEGROUP)
+ return IEEE80211_STATUS_BAD_PAIRWISE_CIPHER;
+ if (rsn->rsn_groupcipher == IEEE80211_CIPHER_CCMP)
+ return IEEE80211_STATUS_BAD_PAIRWISE_CIPHER;
}
/* read AKM Suite List Count field */
if (frm + 2 > efrm)
return 0;
- n = LE_READ_2(frm);
+ n = rsn->rsn_nakms = LE_READ_2(frm);
frm += 2;
/* read AKM Suite List */
if (frm + n * 4 > efrm)
- return IEEE80211_REASON_IE_INVALID;
- akmset = IEEE80211_AKM_NONE;
+ return IEEE80211_STATUS_IE_INVALID;
+ rsn->rsn_akms = IEEE80211_AKM_NONE;
while (n-- > 0) {
- akmset |= ieee80211_parse_rsn_akm(frm);
+ rsn->rsn_akms |= ieee80211_parse_rsn_akm(frm);
frm += 4;
}
/* read RSN Capabilities field */
if (frm + 2 > efrm)
return 0;
- rsncaps = LE_READ_2(frm);
+ rsn->rsn_caps = LE_READ_2(frm);
frm += 2;
/* read PMKID Count field */
@@ -1043,50 +1065,45 @@ ieee80211_parse_rsn_body(struct ieee80211com *ic, struct ieee80211_node *ni,
/* read PMKID List */
if (frm + s * IEEE80211_PMKID_LEN > efrm)
- return IEEE80211_REASON_IE_INVALID;
+ return IEEE80211_STATUS_IE_INVALID;
while (s-- > 0) {
/* ignore PMKIDs for now */
frm += IEEE80211_PMKID_LEN;
}
- ni->ni_group_cipher = group_cipher;
- ni->ni_pairwise_cipherset = pairwise_cipherset;
- ni->ni_akmset = akmset;
- ni->ni_rsncaps = rsncaps;
-
- return 0;
+ return IEEE80211_STATUS_SUCCESS;
}
int
-ieee80211_parse_rsn(struct ieee80211com *ic, struct ieee80211_node *ni,
- const u_int8_t *frm)
+ieee80211_parse_rsn(struct ieee80211com *ic, const u_int8_t *frm,
+ struct ieee80211_rsnparams *rsn)
{
/* check IE length */
if (frm[1] < 2) {
IEEE80211_DPRINTF(("%s: invalid RSN/WPA2 IE;"
" length %u, expecting at least 2\n", __func__, frm[1]));
ic->ic_stats.is_rx_elem_toosmall++;
- return IEEE80211_REASON_IE_INVALID;
+ return IEEE80211_STATUS_IE_INVALID;
}
- return ieee80211_parse_rsn_body(ic, ni, frm + 2, frm[1]);
+ return ieee80211_parse_rsn_body(ic, frm + 2, frm[1], rsn);
}
int
-ieee80211_parse_wpa1(struct ieee80211com *ic, struct ieee80211_node *ni,
- const u_int8_t *frm)
+ieee80211_parse_wpa(struct ieee80211com *ic, const u_int8_t *frm,
+ struct ieee80211_rsnparams *rsn)
{
/* check IE length */
if (frm[1] < 6) {
- IEEE80211_DPRINTF(("%s: invalid WPA1 IE;"
+ IEEE80211_DPRINTF(("%s: invalid WPA IE;"
" length %u, expecting at least 6\n", __func__, frm[1]));
ic->ic_stats.is_rx_elem_toosmall++;
- return IEEE80211_REASON_IE_INVALID;
+ return IEEE80211_STATUS_IE_INVALID;
}
- return ieee80211_parse_rsn_body(ic, ni, frm + 6, frm[1] - 4);
+ return ieee80211_parse_rsn_body(ic, frm + 6, frm[1] - 4, rsn);
}
/*
- * Create a copy of an information element.
+ * Create (or update) a copy of an information element.
*/
int
ieee80211_save_ie(const u_int8_t *frm, u_int8_t **ie)
@@ -1119,15 +1136,12 @@ ieee80211_save_ie(const u_int8_t *frm, u_int8_t **ie)
*/
void
ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni, int rssi, u_int32_t rstamp, int isprobe)
{
-#define ISPROBE(_wh) (((_wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
- IEEE80211_FC0_SUBTYPE_PROBE_RESP)
-
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
- const u_int8_t *tstamp, *ssid, *rates, *xrates, *edca, *wmm;
- const u_int8_t *rsn, *wpa;
+ const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie;
+ const u_int8_t *rsnie, *wpaie;
u_int16_t capinfo, bintval, fhdwell;
u_int8_t chan, bchan, fhindex, erp;
int is_new;
@@ -1160,7 +1174,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
tstamp = frm; frm += 8;
bintval = LE_READ_2(frm); frm += 2;
capinfo = LE_READ_2(frm); frm += 2;
- ssid = rates = xrates = edca = wmm = rsn = wpa = NULL;
+ ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = NULL;
bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
chan = bchan;
fhdwell = 0;
@@ -1213,10 +1227,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
erp = frm[2];
break;
case IEEE80211_ELEMID_RSN:
- rsn = frm;
+ rsnie = frm;
break;
case IEEE80211_ELEMID_EDCAPARMS:
- edca = frm;
+ edcaie = frm;
break;
case IEEE80211_ELEMID_QOS_CAP:
break;
@@ -1227,10 +1241,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
}
if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) {
if (frm[5] == 1)
- wpa = frm;
+ wpaie = frm;
else if (frm[1] >= 5 &&
frm[5] == 2 && frm[6] == 1)
- wmm = frm;
+ wmmie = frm;
}
break;
default:
@@ -1250,7 +1264,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
#endif
isclr(ic->ic_chan_active, chan)) {
IEEE80211_DPRINTF(("%s: ignore %s with invalid channel "
- "%u\n", __func__, ISPROBE(wh) ?
+ "%u\n", __func__, isprobe ?
"probe response" : "beacon", chan));
ic->ic_stats.is_rx_badchan++;
return;
@@ -1268,7 +1282,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
* different hop pattern in FH.
*/
IEEE80211_DPRINTF(("%s: ignore %s on channel %u marked "
- "for channel %u\n", __func__, ISPROBE(wh) ?
+ "for channel %u\n", __func__, isprobe ?
"probe response" : "beacon", bchan, chan));
ic->ic_stats.is_rx_chanmismatch++;
return;
@@ -1290,7 +1304,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
(ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) {
printf("%s: %s%s on chan %u (bss chan %u) ",
__func__, (ni == NULL ? "new " : ""),
- ISPROBE(wh) ? "probe response" : "beacon",
+ isprobe ? "probe response" : "beacon",
chan, bchan);
ieee80211_print_essid(ssid + 2, ssid[1]);
printf(" from %s\n", ether_sprintf((u_int8_t *)wh->i_addr2));
@@ -1313,11 +1327,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
* now.
*/
if (ic->ic_opmode == IEEE80211_M_STA &&
- ic->ic_state == IEEE80211_S_ASSOC &&
+ ic->ic_state == IEEE80211_S_RUN &&
ni->ni_state == IEEE80211_STA_BSS) {
/*
- * Check if protection mode has changed since last
- * beacon.
+ * Check if protection mode has changed since last beacon.
*/
if (ni->ni_erp != erp) {
IEEE80211_DPRINTF((
@@ -1343,12 +1356,50 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
(capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
}
}
+ /*
+ * We do not try to update EDCA parameters if QoS was not negotiated
+ * with the AP at association time.
+ */
if (ni->ni_flags & IEEE80211_NODE_QOS) {
- if (edca != NULL)
- ieee80211_parse_edca_params(ic, edca);
- else if (wmm != NULL)
- ieee80211_parse_wmm_params(ic, edca);
+ /* always prefer EDCA IE over Wi-Fi Alliance WMM IE */
+ if (edcaie != NULL)
+ ieee80211_parse_edca_params(ic, edcaie);
+ else if (wmmie != NULL)
+ ieee80211_parse_wmm_params(ic, wmmie);
}
+
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ struct ieee80211_rsnparams rsn;
+ const u_int8_t *saveie = NULL;
+ /*
+ * If the AP advertises both RSN and WPA IEs (WPA1+WPA2),
+ * we only store the parameters of the highest protocol
+ * version we support.
+ */
+ if (rsnie != NULL &&
+ (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)) {
+ if (ieee80211_parse_rsn(ic, rsnie, &rsn) == 0) {
+ ni->ni_rsnprotos = IEEE80211_PROTO_RSN;
+ saveie = rsnie;
+ }
+ } else if (wpaie != NULL &&
+ (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)) {
+ if (ieee80211_parse_wpa(ic, wpaie, &rsn) == 0) {
+ ni->ni_rsnprotos = IEEE80211_PROTO_WPA;
+ saveie = wpaie;
+ }
+ }
+ if (saveie != NULL &&
+ ieee80211_save_ie(saveie, &ni->ni_rsnie) == 0) {
+ ni->ni_rsnakms = rsn.rsn_akms;
+ ni->ni_rsnciphers = rsn.rsn_ciphers;
+ ni->ni_rsngroupcipher = rsn.rsn_groupcipher;
+ ni->ni_rsncaps = rsn.rsn_caps;
+ } else
+ ni->ni_rsnprotos = IEEE80211_PROTO_NONE;
+ } else
+ ni->ni_rsnprotos = IEEE80211_PROTO_NONE;
+
if (ssid[1] != 0 && ni->ni_esslen == 0) {
/*
* Update ESSID at probe response to adopt hidden AP by
@@ -1379,7 +1430,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
* Anything else can be discarded (XXX and should be handled
* above so we don't do so much work).
*/
- if (ic->ic_opmode == IEEE80211_M_IBSS || (is_new && ISPROBE(wh))) {
+ if (ic->ic_opmode == IEEE80211_M_IBSS || (is_new && isprobe)) {
/*
* Fake an association so the driver can setup it's
* private state. The rate set has been setup above;
@@ -1388,7 +1439,6 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
if (ic->ic_newassoc)
(*ic->ic_newassoc)(ic, ni, 1);
}
-#undef ISPROBE
}
/*-
@@ -1458,10 +1508,9 @@ ieee80211_recv_probe_req(struct ieee80211com *ic, struct mbuf *m0,
if (rate & IEEE80211_RATE_BASIC) {
IEEE80211_DPRINTF(("%s: rate mismatch for %s\n",
__func__, ether_sprintf((u_int8_t *)wh->i_addr2)));
- } else {
- IEEE80211_SEND_MGMT(ic, ni,
- IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
+ return;
}
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
}
/*-
@@ -1518,16 +1567,14 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0,
*/
void
ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni, int rssi, u_int32_t rstamp, int reassoc)
{
-#define ISREASSOC(_wh) (((_wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
- IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
-
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
- const u_int8_t *ssid, *rates, *xrates, *rsn, *wpa;
+ const u_int8_t *ssid, *rates, *xrates, *rsnie, *wpaie;
u_int16_t capinfo, bintval;
- int reassoc, resp, reason = 0;
+ int resp, status = 0;
+ struct ieee80211_rsnparams rsn;
u_int8_t rate;
if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
@@ -1538,13 +1585,8 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
frm = (const u_int8_t *)&wh[1];
efrm = mtod(m0, u_int8_t *) + m0->m_len;
- if (ISREASSOC(wh)) {
- reassoc = 1;
- resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
- } else {
- reassoc = 0;
- resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
- }
+ resp = reassoc ? IEEE80211_FC0_SUBTYPE_REASSOC_RESP :
+ IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
@@ -1557,7 +1599,7 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
bintval = LE_READ_2(frm); frm += 2;
if (reassoc)
frm += IEEE80211_ADDR_LEN; /* skip current AP address */
- ssid = rates = xrates = rsn = wpa = NULL;
+ ssid = rates = xrates = rsnie = wpaie = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm) {
ic->ic_stats.is_rx_elem_toosmall++;
@@ -1574,7 +1616,7 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
xrates = frm;
break;
case IEEE80211_ELEMID_RSN:
- rsn = frm;
+ rsnie = frm;
break;
case IEEE80211_ELEMID_QOS_CAP:
break;
@@ -1585,7 +1627,7 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
}
if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) {
if (frm[5] == 1)
- wpa = frm;
+ wpaie = frm;
}
break;
}
@@ -1610,38 +1652,102 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
ic->ic_stats.is_rx_assoc_notauth++;
return;
}
- if (rsn != NULL)
- reason = ieee80211_parse_rsn(ic, ni, rsn);
- else if (wpa != NULL)
- reason = ieee80211_parse_wpa1(ic, ni, wpa);
- if (reason != 0) {
- IEEE80211_DPRINTF(("%s: invalid RSN IE for %s\n",
- __func__, ether_sprintf((u_int8_t *)wh->i_addr2)));
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- reason);
- ieee80211_node_leave(ic, ni);
- ic->ic_stats.is_rx_assoc_badrsnie++;
- return;
+ if (reassoc && ni->ni_state != IEEE80211_STA_ASSOC) {
+ IEEE80211_DPRINTF(("%s: deny reassoc from %s, not "
+ "associated\n", __func__,
+ ether_sprintf((u_int8_t *)wh->i_addr2)));
+ status = IEEE80211_STATUS_NOT_ASSOCED;
+ goto end;
}
+
if (!(capinfo & IEEE80211_CAPINFO_ESS)) {
- IEEE80211_DPRINTF(("%s: capinfo mismatch for %s\n",
- __func__, ether_sprintf((u_int8_t *)wh->i_addr2)));
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_CAPINFO);
- ieee80211_node_leave(ic, ni);
ic->ic_stats.is_rx_assoc_capmismatch++;
- return;
+ status = IEEE80211_STATUS_CAPINFO;
+ goto end;
}
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO |
IEEE80211_F_DODEL);
if (rate & IEEE80211_RATE_BASIC) {
- IEEE80211_DPRINTF(("%s: rate mismatch for %s\n",
- __func__, ether_sprintf((u_int8_t *)wh->i_addr2)));
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE);
- ieee80211_node_leave(ic, ni);
ic->ic_stats.is_rx_assoc_norate++;
- return;
+ status = IEEE80211_STATUS_BASIC_RATE;
+ goto end;
}
+
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ const u_int8_t *saveie;
+ /*
+ * A station should never include both a WPA and an RSN IE
+ * in its (Re)Association Requests, but if it does, we only
+ * consider the IE of the highest version of the protocol
+ * that is allowed (ie RSN over WPA).
+ */
+ if (rsnie != NULL &&
+ (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)) {
+ status = ieee80211_parse_rsn(ic, rsnie, &rsn);
+ if (status != 0)
+ goto end;
+ ni->ni_rsnprotos = IEEE80211_PROTO_RSN;
+ saveie = rsnie;
+ } else if (wpaie != NULL &&
+ (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)) {
+ status = ieee80211_parse_wpa(ic, wpaie, &rsn);
+ if (status != 0)
+ goto end;
+ ni->ni_rsnprotos = IEEE80211_PROTO_WPA;
+ saveie = wpaie;
+ } else {
+ /*
+ * In an RSN, an AP shall not associate with STAs
+ * that fail to include the RSN IE in the
+ * (Re)Association Request.
+ */
+ status = IEEE80211_STATUS_IE_INVALID;
+ goto end;
+ }
+ /*
+ * The initiating STA's RSN IE shall include one authentication
+ * and pairwise cipher suite among those advertised by the
+ * targeted AP. It shall also specify the group cipher suite
+ * specified by the targeted AP.
+ */
+ if (rsn.rsn_nakms != 1 ||
+ !(rsn.rsn_akms & ic->ic_bss->ni_rsnakms)) {
+ status = IEEE80211_STATUS_BAD_AKMP;
+ goto end;
+ }
+ if (rsn.rsn_nciphers != 1 ||
+ !(rsn.rsn_ciphers & ic->ic_bss->ni_rsnciphers)) {
+ status = IEEE80211_STATUS_BAD_PAIRWISE_CIPHER;
+ goto end;
+ }
+ if (rsn.rsn_groupcipher != ic->ic_bss->ni_rsngroupcipher) {
+ status = IEEE80211_STATUS_BAD_GROUP_CIPHER;
+ goto end;
+ }
+ /*
+ * Disallow new associations using TKIP if countermeasures
+ * are active.
+ */
+ if ((ic->ic_flags & IEEE80211_F_COUNTERM) &&
+ (rsn.rsn_ciphers == IEEE80211_CIPHER_TKIP ||
+ rsn.rsn_groupcipher == IEEE80211_CIPHER_TKIP)) {
+ status = IEEE80211_STATUS_CIPHER_REJ_POLICY;
+ goto end;
+ }
+
+ /* everything looks fine, save IE and parameters */
+ if (ieee80211_save_ie(saveie, &ni->ni_rsnie) != 0) {
+ status = IEEE80211_STATUS_TOOMANY;
+ goto end;
+ }
+ ni->ni_rsnakms = rsn.rsn_akms;
+ ni->ni_rsnciphers = rsn.rsn_ciphers;
+ ni->ni_rsngroupcipher = ic->ic_bss->ni_rsngroupcipher;
+ ni->ni_rsncaps = rsn.rsn_caps;
+ } else
+ ni->ni_rsnprotos = IEEE80211_PROTO_NONE;
+
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
ni->ni_intval = bintval;
@@ -1649,9 +1755,12 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
ni->ni_chan = ic->ic_bss->ni_chan;
ni->ni_fhdwell = ic->ic_bss->ni_fhdwell;
ni->ni_fhindex = ic->ic_bss->ni_fhindex;
-
- ieee80211_node_join(ic, ni, resp);
-#undef ISREASSOC
+ end:
+ if (status != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, resp, status);
+ ieee80211_node_leave(ic, ni);
+ } else
+ ieee80211_node_join(ic, ni, resp);
}
/*-
@@ -1665,15 +1774,12 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
*/
void
ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni, int reassoc)
{
-#define ISREASSOC(_wh) (((_wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == \
- IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
-
struct ifnet *ifp = &ic->ic_if;
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
- const u_int8_t *rates, *xrates, *edca, *wmm;
+ const u_int8_t *rates, *xrates, *edcaie, *wmmie;
u_int16_t capinfo, status, associd;
u_int8_t rate;
@@ -1688,14 +1794,13 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
efrm = mtod(m0, u_int8_t *) + m0->m_len;
IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
- ni = ic->ic_bss;
capinfo = LE_READ_2(frm); frm += 2;
status = LE_READ_2(frm); frm += 2;
if (status != 0) {
if (ifp->if_flags & IFF_DEBUG)
printf("%s: %sassociation failed (reason %d)"
" for %s\n", ifp->if_xname,
- ISREASSOC(wh) ? "re" : "",
+ reassoc ? "re" : "",
status, ether_sprintf((u_int8_t *)wh->i_addr3));
if (ni != ic->ic_bss)
ni->ni_fails++;
@@ -1704,7 +1809,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
}
associd = LE_READ_2(frm); frm += 2;
- rates = xrates = edca = wmm = NULL;
+ rates = xrates = edcaie = wmmie = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm) {
ic->ic_stats.is_rx_elem_toosmall++;
@@ -1718,7 +1823,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
xrates = frm;
break;
case IEEE80211_ELEMID_EDCAPARMS:
- edca = frm;
+ edcaie = frm;
break;
case IEEE80211_ELEMID_VENDOR:
if (frm[1] < 4) {
@@ -1727,7 +1832,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
}
if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) {
if (frm[1] >= 5 && frm[5] == 2 && frm[6] == 1)
- wmm = frm;
+ wmmie = frm;
}
break;
}
@@ -1746,14 +1851,14 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
}
ni->ni_capinfo = capinfo;
ni->ni_associd = associd;
- if (edca != NULL || wmm != NULL) {
+ if (edcaie != NULL || wmmie != NULL) {
/* force update of EDCA parameters */
ic->ic_edca_updtcount = -1;
- if ((edca != NULL &&
- ieee80211_parse_edca_params(ic, edca) == 0) ||
- (wmm != NULL &&
- ieee80211_parse_wmm_params(ic, wmm) == 0))
+ if ((edcaie != NULL &&
+ ieee80211_parse_edca_params(ic, edcaie) == 0) ||
+ (wmmie != NULL &&
+ ieee80211_parse_wmm_params(ic, wmmie) == 0))
ni->ni_flags |= IEEE80211_NODE_QOS;
else /* for Reassociation */
ni->ni_flags &= ~IEEE80211_NODE_QOS;
@@ -1778,10 +1883,15 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
ic->ic_flags |= IEEE80211_F_USEPROT;
else
ic->ic_flags &= ~IEEE80211_F_USEPROT;
-
+ /*
+ * If not an RSNA, mark the port as valid, otherwise wait for
+ * 802.1X authentication and 4-way handshake to complete..
+ */
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ /* XXX ic->ic_mgt_timer = 5; */
+ }
ieee80211_new_state(ic, IEEE80211_S_RUN,
- wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
-#undef ISREASSOC
+ IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
}
/*-
@@ -1790,7 +1900,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
*/
void
ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni)
{
struct ifnet *ifp = &ic->ic_if;
const struct ieee80211_frame *wh;
@@ -1807,7 +1917,7 @@ ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0,
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
ieee80211_new_state(ic, IEEE80211_S_AUTH,
- wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ IEEE80211_FC0_SUBTYPE_DEAUTH);
break;
case IEEE80211_M_HOSTAP:
if (ni != ic->ic_bss) {
@@ -1831,7 +1941,7 @@ ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0,
*/
void
ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni)
{
struct ifnet *ifp = &ic->ic_if;
const struct ieee80211_frame *wh;
@@ -1848,7 +1958,7 @@ ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0,
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
ieee80211_new_state(ic, IEEE80211_S_ASSOC,
- wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ IEEE80211_FC0_SUBTYPE_DISASSOC);
break;
case IEEE80211_M_HOSTAP:
if (ni != ic->ic_bss) {
@@ -1871,9 +1981,11 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
{
switch (subtype) {
- case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON:
- ieee80211_recv_probe_resp(ic, m0, ni, rssi, rstamp);
+ ieee80211_recv_probe_resp(ic, m0, ni, rssi, rstamp, 0);
+ break;
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ ieee80211_recv_probe_resp(ic, m0, ni, rssi, rstamp, 1);
break;
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
ieee80211_recv_probe_req(ic, m0, ni, rssi, rstamp);
@@ -1882,18 +1994,22 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
ieee80211_recv_auth(ic, m0, ni, rssi, rstamp);
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
+ ieee80211_recv_assoc_req(ic, m0, ni, rssi, rstamp, 0);
+ break;
case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
- ieee80211_recv_assoc_req(ic, m0, ni, rssi, rstamp);
+ ieee80211_recv_assoc_req(ic, m0, ni, rssi, rstamp, 1);
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
+ ieee80211_recv_assoc_resp(ic, m0, ni, 0);
+ break;
case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
- ieee80211_recv_assoc_resp(ic, m0, ni, rssi, rstamp);
+ ieee80211_recv_assoc_resp(ic, m0, ni, 1);
break;
case IEEE80211_FC0_SUBTYPE_DEAUTH:
- ieee80211_recv_deauth(ic, m0, ni, rssi, rstamp);
+ ieee80211_recv_deauth(ic, m0, ni);
break;
case IEEE80211_FC0_SUBTYPE_DISASSOC:
- ieee80211_recv_disassoc(ic, m0, ni, rssi, rstamp);
+ ieee80211_recv_disassoc(ic, m0, ni);
break;
default:
IEEE80211_DPRINTF(("%s: mgmt frame with subtype 0x%x not "
@@ -1916,15 +2032,9 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
(u_int64_t)(p)[4] << 24 | (u_int64_t)(p)[5] << 16 | \
(u_int64_t)(p)[6] << 8 | (u_int64_t)(p)[7])
-#define BE_WRITE_2(p, v) do { \
- (p)[0] = (v) >> 8; \
- (p)[1] = (v) & 0xff; \
-} while (0)
-
/* unaligned little endian access */
-#define LE_READ_8(p) \
- ((u_int64_t)(p)[7] << 56 | (u_int64_t)(p)[6] << 48 | \
- (u_int64_t)(p)[5] << 40 | (u_int64_t)(p)[4] << 32 | \
+#define LE_READ_6(p) \
+ ((u_int64_t)(p)[5] << 40 | (u_int64_t)(p)[4] << 32 | \
(u_int64_t)(p)[3] << 24 | (u_int64_t)(p)[2] << 16 | \
(u_int64_t)(p)[1] << 8 | (u_int64_t)(p)[0])
@@ -1936,24 +2046,24 @@ void
ieee80211_recv_4way_msg1(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
- u_int8_t snonce[EAPOL_KEY_NONCE_LEN];
+ struct ieee80211_ptk tptk;
const u_int8_t *frm, *efrm;
const u_int8_t *pmkid;
const u_int8_t *pmk;
- size_t pmk_len;
if (ic->ic_opmode != IEEE80211_M_STA &&
ic->ic_opmode != IEEE80211_M_IBSS)
return;
if (ni->ni_replaycnt_ok &&
- BE_READ_8(key->replaycnt) <= ni->ni_replaycnt)
+ BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
return;
-
+ }
/* save authenticator's nonce (ANonce) */
memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN);
- /* parse key data field (shall contain an encapsulated PMKID) */
+ /* parse key data field (may contain an encapsulated PMKID) */
frm = (const u_int8_t *)&key[1];
efrm = frm + BE_READ_2(key->paylen);
@@ -1976,32 +2086,29 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic,
}
frm += 2 + frm[1];
}
- /* check that the PMKID KDE is valid */
+ /* check that the PMKID KDE is valid (if present) */
if (pmkid != NULL && pmkid[1] < 4 + 16)
return;
- /* generate a new nonce (SNonce) */
- arc4random_bytes(snonce, EAPOL_KEY_NONCE_LEN);
+ /* generate a new supplicant's nonce (SNonce) */
+ arc4random_bytes(ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
- if (ni->ni_akm == IEEE80211_AKM_IEEE8021X) {
- /* XXX find the PMK in the PMKSA cache using the PMKID */
- } else {
- /* the PMK is the PSK */
- pmk = ic->ic_psk;
- pmk_len = IEEE80211_PMK_LEN;
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, pmkid)) == NULL) {
+ /* no PMK configured for this STA/PMKID */
+ return;
}
-
- /* derive PTK from PMK */
- ieee80211_derive_ptk(pmk, pmk_len, ni->ni_macaddr, ic->ic_myaddr,
- ni->ni_nonce, snonce, (u_int8_t *)&ni->ni_ptk, sizeof(ni->ni_ptk));
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
+ ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
ic->ic_if.if_xname, 1, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- /* send message 2 to authenticator */
- ieee80211_send_4way_msg2(ic, ni, snonce);
+ /* send message 2 to authenticator using TPTK */
+ (void)ieee80211_send_4way_msg2(ic, ni, key->replaycnt, &tptk);
}
/*
@@ -2015,24 +2122,43 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
{
struct ieee80211_ptk tptk;
const u_int8_t *pmk;
- size_t pmk_len;
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
/* discard if we're not expecting this message */
if (ni->ni_rsn_state != RSNA_PTKSTART &&
- ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING)
+ ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
return;
-
+ }
ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING;
- /* derive TPTK from PMK */
- ieee80211_derive_ptk(pmk, pmk_len, ic->ic_myaddr, ni->ni_macaddr,
- ni->ni_nonce, key->nonce, (u_int8_t *)&tptk, sizeof(tptk));
+ /* replay counter has already been verified by caller */
+
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
+ /* no PMK configured for this STA */
+ return; /* will timeout.. */
+ }
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ic->ic_myaddr,
+ ni->ni_macaddr, ni->ni_nonce, key->nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0)
- return;
+ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return; /* will timeout.. */
+ }
- /* use TPTK as PTK now that MIC is verified */
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2;
+ ni->ni_rsn_retries = 0;
+
+ /* install TPTK as PTK now that MIC is verified */
memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
/*
@@ -2042,21 +2168,18 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
if (ni->ni_rsnie == NULL || rsn[1] != ni->ni_rsnie[1] ||
memcmp(rsn, ni->ni_rsnie, 2 + rsn[1]) != 0) {
IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_IE_INVALID);
+ IEEE80211_REASON_RSN_DIFFERENT_IE);
ieee80211_node_leave(ic, ni);
return;
}
- ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2;
- ni->ni_rsn_tocnt = 0;
-
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
ic->ic_if.if_xname, 2, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
/* send message 3 to supplicant */
- ieee80211_send_4way_msg3(ic, ni);
+ (void)ieee80211_send_4way_msg3(ic, ni);
}
/*
@@ -2067,48 +2190,71 @@ void
ieee80211_recv_4way_msg3(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
+ struct ieee80211_ptk tptk;
struct ieee80211_key *k;
const u_int8_t *frm, *efrm;
- const u_int8_t *rsn1, *rsn2, *gtk;
- u_int16_t info;
+ const u_int8_t *rsnie1, *rsnie2, *gtk;
+ const u_int8_t *pmk;
+ u_int16_t info, reason = 0;
if (ic->ic_opmode != IEEE80211_M_STA &&
ic->ic_opmode != IEEE80211_M_IBSS)
return;
- if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt)
+ if (ni->ni_replaycnt_ok &&
+ BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
return;
+ }
- /* check that ANonce matches the one received in message 1 */
- if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0)
+ /* check that ANonce matches that of message 1 */
+ if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0) {
+ IEEE80211_DPRINTF(("%s: ANonce does not match msg 1/4\n",
+ __func__));
return;
+ }
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
+ /* no PMK configured for this STA */
+ return;
+ }
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
+ ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
info = BE_READ_2(key->info);
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
+ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
return;
+ }
+ /* install TPTK as PTK now that MIC is verified */
+ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
/* if encrypted, decrypt Key Data field using KEK */
if ((info & EAPOL_KEY_ENCRYPTED) &&
- ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0)
+ ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
return;
+ }
/* parse key data field */
frm = (const u_int8_t *)&key[1];
efrm = frm + BE_READ_2(key->paylen);
- rsn1 = rsn2 = gtk = NULL;
+ rsnie1 = rsnie2 = gtk = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm)
break;
switch (frm[0]) {
case IEEE80211_ELEMID_RSN:
- if (rsn1 == NULL)
- rsn1 = frm;
- else if (rsn2 == NULL)
- rsn2 = frm;
- /* ignore if more than two RSN IEs */
+ if (rsnie1 == NULL)
+ rsnie1 = frm;
+ else if (rsnie2 == NULL)
+ rsnie2 = frm;
+ /* ignore others if more than two RSN IEs */
break;
case IEEE80211_ELEMID_VENDOR:
if (frm[1] < 4)
@@ -2122,7 +2268,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
} else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
switch (frm[5]) {
case 1: /* WPA */
- rsn1 = frm;
+ rsnie1 = frm;
break;
}
}
@@ -2131,33 +2277,47 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
frm += 2 + frm[1];
}
/* first WPA/RSN IE is mandatory */
- if (rsn1 == NULL)
+ if (rsnie1 == NULL) {
+ IEEE80211_DPRINTF(("%s: missing RSN IE\n", __func__));
return;
+ }
/* key data must be encrypted if GTK is included */
- if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED))
+ if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED)) {
+ IEEE80211_DPRINTF(("%s: GTK not encrypted\n", __func__));
return;
-
+ }
/*
* Check that first WPA/RSN IE is identical to the one received in
* the beacon or probe response frame.
*/
- if (ni->ni_rsnie == NULL || rsn1[1] != ni->ni_rsnie[1] ||
- memcmp(rsn1, ni->ni_rsnie, 2 + rsn1[1]) != 0) {
- /*ieee80211_new_state();*/
- return;
+ if (ni->ni_rsnie == NULL || rsnie1[1] != ni->ni_rsnie[1] ||
+ memcmp(rsnie1, ni->ni_rsnie, 2 + rsnie1[1]) != 0) {
+ reason = IEEE80211_REASON_RSN_DIFFERENT_IE;
+ goto deauth;
}
/*
* If a second RSN information element is present, use its pairwise
* cipher suite or deauthenticate.
*/
- if (rsn2 != NULL) {
- /* XXX ieee80211_parse_rsn(rsn2); */
- /*ieee80211_new_state();*/
- return;
+ if (rsnie2 != NULL && ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
+ struct ieee80211_rsnparams rsn;
+
+ if (ieee80211_parse_rsn(ic, rsnie2, &rsn) == 0) {
+ if (rsn.rsn_akms != ni->ni_rsnakms ||
+ rsn.rsn_groupcipher != ni->ni_rsngroupcipher ||
+ rsn.rsn_nciphers != 1 ||
+ !(rsn.rsn_ciphers & ic->ic_rsnciphers)) {
+ reason = IEEE80211_REASON_BAD_PAIRWISE_CIPHER;
+ goto deauth;
+ }
+ /* use pairwise cipher suite of second RSN IE */
+ ni->ni_rsnciphers = rsn.rsn_ciphers;
+ ni->ni_rsncipher = ni->ni_rsnciphers;
+ }
}
- /* update the last-seen value of the key replay counter field */
+ /* update the last seen value of the key replay counter field */
ni->ni_replaycnt = BE_READ_8(key->replaycnt);
ni->ni_replaycnt_ok = 1;
@@ -2168,20 +2328,24 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
/* send message 4 to authenticator */
if (ieee80211_send_4way_msg4(ic, ni) != 0)
- return; /* ..authenticator will timeout */
+ return; /* ..authenticator will retry */
if (info & EAPOL_KEY_INSTALL) {
+ u_int64_t prsc;
+
/* check that key length matches that of pairwise cipher */
if (BE_READ_2(key->keylen) !=
- ieee80211_cipher_keylen(ni->ni_pairwise_cipher))
- return;
+ ieee80211_cipher_keylen(ni->ni_rsncipher)) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
/* install the PTK */
+ prsc = (gtk == NULL) ? LE_READ_6(key->rsc) : 0;
k = &ni->ni_pairwise_key;
- ieee80211_map_ptk(&ni->ni_ptk, ni->ni_pairwise_cipher, k);
- if (ic->ic_set_key != NULL &&
- (*ic->ic_set_key)(ic, ni, k) != 0) {
- /* XXX deauthenticate */
- return;
+ ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, prsc, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
}
}
if (gtk != NULL) {
@@ -2189,29 +2353,40 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
u_int8_t kid;
/* check that the GTK KDE is valid */
- if (gtk[1] < 4 + 2)
- return;
+ if (gtk[1] < 4 + 2) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
/* check that key length matches that of group cipher */
- if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_group_cipher))
- return; /* XXX PTK already installed! */
+ if (gtk[1] - 6 !=
+ ieee80211_cipher_keylen(ni->ni_rsngroupcipher)) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
/* install the GTK */
kid = gtk[6] & 3;
- rsc = LE_READ_8(key->rsc);
+ rsc = LE_READ_6(key->rsc);
k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk(&gtk[8], ni->ni_group_cipher, kid,
+ ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
gtk[6] & (1 << 2), rsc, k);
- if (ic->ic_set_key != NULL &&
- (*ic->ic_set_key)(ic, ni, k) != 0) {
- /* XXX deauthenticate */
- return;
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
}
}
if (info & EAPOL_KEY_SECURE) {
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- if (++ni->ni_key_count == 2)
- ni->ni_port_valid = 1;
- } else
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
ni->ni_port_valid = 1;
+ }
+ }
+ deauth:
+ if (reason != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ reason);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
}
}
@@ -2223,41 +2398,58 @@ void
ieee80211_recv_4way_msg4(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
- struct ieee80211_key *k;
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
/* discard if we're not expecting this message */
- if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING)
+ if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
return;
+ }
+
+ /* replay counter has already been verified by caller */
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
- return;
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return; /* will timeout.. */
+ }
+ timeout_del(&ni->ni_rsn_timeout);
ni->ni_rsn_state = RSNA_PTKINITDONE;
+ ni->ni_rsn_retries = 0;
- /* empty key data field */
-
- /* install the PTK */
- k = &ni->ni_pairwise_key;
- ieee80211_map_ptk(&ni->ni_ptk, ni->ni_pairwise_cipher, k);
- if (ic->ic_set_key != NULL && (*ic->ic_set_key)(ic, ni, k) != 0)
- return;
-
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- if (++ni->ni_key_count == 2)
- ni->ni_port_valid = 1;
- } else
+ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) {
+ /* install the PTK */
+ struct ieee80211_key *k = &ni->ni_pairwise_key;
+ ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, 0, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_ASSOC_TOOMANY);
+ ieee80211_node_leave(ic, ni);
+ return;
+ }
+ }
+ if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n", __func__,
+ ether_sprintf(ni->ni_macaddr)));
ni->ni_port_valid = 1;
-
- /* increment the 64-bit Key Replay Counter */
- ni->ni_replaycnt++;
+ }
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
ic->ic_if.if_xname, 4, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- /* XXX start a group key handshake w/ WPA1 */
+ /* initiate a group key handshake for WPA */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA)
+ (void)ieee80211_send_group_msg1(ic, ni);
+ else
+ ni->ni_rsn_gstate = RSNA_IDLE;
}
/*
@@ -2269,22 +2461,24 @@ ieee80211_recv_4way_msg2or4(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
const u_int8_t *frm, *efrm;
- const u_int8_t *rsn;
+ const u_int8_t *rsnie;
- if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt)
+ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
return;
+ }
/* parse key data field (check if an RSN IE is present) */
frm = (const u_int8_t *)&key[1];
efrm = frm + BE_READ_2(key->paylen);
- rsn = NULL;
+ rsnie = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm)
break;
switch (frm[0]) {
case IEEE80211_ELEMID_RSN:
- rsn = frm;
+ rsnie = frm;
break;
case IEEE80211_ELEMID_VENDOR:
if (frm[1] < 4)
@@ -2292,15 +2486,15 @@ ieee80211_recv_4way_msg2or4(struct ieee80211com *ic,
if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
switch (frm[5]) {
case 1: /* WPA */
- rsn = frm;
+ rsnie = frm;
break;
}
}
}
frm += 2 + frm[1];
}
- if (rsn != NULL)
- ieee80211_recv_4way_msg2(ic, key, ni, rsn);
+ if (rsnie != NULL)
+ ieee80211_recv_4way_msg2(ic, key, ni, rsnie);
else
ieee80211_recv_4way_msg4(ic, key, ni);
}
@@ -2324,19 +2518,24 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
ic->ic_opmode != IEEE80211_M_IBSS)
return;
- if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt)
+ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
return;
-
- info = BE_READ_2(key->info);
-
+ }
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
return;
+ }
+ info = BE_READ_2(key->info);
/* check that encrypted and decrypt Key Data field using KEK */
if (!(info & EAPOL_KEY_ENCRYPTED) ||
- ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0)
+ ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
return;
+ }
/* parse key data field (shall contain a GTK KDE) */
frm = (const u_int8_t *)&key[1];
@@ -2361,24 +2560,37 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
}
frm += 2 + frm[1];
}
- if (gtk == NULL)
+ /* check that the GTK KDE is present and valid */
+ if (gtk == NULL || gtk[1] < 4 + 2) {
+ IEEE80211_DPRINTF(("%s: missing or invalid GTK KDE\n",
+ __func__));
return;
+ }
- /* check that the GTK KDE is valid */
- if (gtk[1] < 4 + 2)
- return;
/* check that key length matches that of group cipher */
- if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_group_cipher))
+ if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_rsngroupcipher))
return;
+
/* install the GTK */
kid = gtk[6] & 3;
- rsc = LE_READ_8(key->rsc);
+ rsc = LE_READ_6(key->rsc);
k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk(&gtk[8], ni->ni_group_cipher, kid,
+ ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
gtk[6] & (1 << 2), rsc, k);
- if (ic->ic_set_key != NULL && (*ic->ic_set_key)(ic, ni, k) != 0)
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_LEAVE);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
return;
-
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+ }
/* update the last seen value of the key replay counter field */
ni->ni_replaycnt = BE_READ_8(key->replaycnt);
@@ -2388,7 +2600,7 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
ether_sprintf(ni->ni_macaddr));
/* send message 2 to authenticator */
- ieee80211_send_group_msg2(ic, ni, k);
+ (void)ieee80211_send_group_msg2(ic, ni, k);
}
void
@@ -2396,43 +2608,68 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
struct ieee80211_key *k;
+ const u_int8_t *frm;
u_int64_t rsc;
u_int16_t info;
u_int8_t kid;
+ int keylen;
if (ic->ic_opmode != IEEE80211_M_STA &&
ic->ic_opmode != IEEE80211_M_IBSS)
return;
- if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt)
+ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
return;
-
+ }
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
return;
-
+ }
/*
- * EAPOL-Key data field is encrypted even though WPA1 doesn't set
+ * EAPOL-Key data field is encrypted even though WPA doesn't set
* the ENCRYPTED bit in the info field.
*/
- if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0)
+ if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
return;
-
+ }
info = BE_READ_2(key->info);
+ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher);
/* check that key length matches that of group cipher */
- if (BE_READ_2(key->keylen) !=
- ieee80211_cipher_keylen(ni->ni_group_cipher))
+ if (BE_READ_2(key->keylen) != keylen)
+ return;
+
+ /* check that the data length is large enough to hold the key */
+ if (BE_READ_2(key->paylen) < keylen)
return;
+
+ /* key data field contains the GTK */
+ frm = (const u_int8_t *)&key[1];
+
/* install the GTK */
kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3;
- rsc = LE_READ_8(key->rsc);
+ rsc = LE_READ_6(key->rsc);
k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk((u_int8_t *)&key[1], ni->ni_group_cipher, kid,
+ ieee80211_map_gtk(frm, ni->ni_rsngroupcipher, kid,
info & EAPOL_KEY_WPA_TX, rsc, k);
- if (ic->ic_set_key != NULL && (*ic->ic_set_key)(ic, ni, k) != 0)
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_LEAVE);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
return;
-
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+ }
/* update the last seen value of the key replay counter field */
ni->ni_replaycnt = BE_READ_8(key->replaycnt);
@@ -2442,7 +2679,7 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
ether_sprintf(ni->ni_macaddr));
/* send message 2 to authenticator */
- ieee80211_send_group_msg2(ic, ni, k);
+ (void)ieee80211_send_group_msg2(ic, ni, k);
}
/*
@@ -2457,20 +2694,34 @@ ieee80211_recv_group_msg2(struct ieee80211com *ic,
ic->ic_opmode != IEEE80211_M_IBSS)
return;
- if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt)
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_gstate != RSNA_REKEYNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
return;
-
+ }
+ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
return;
+ }
- /* empty key data field */
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_gstate = RSNA_REKEYESTABLISHED;
+
+ if ((ni->ni_flags & IEEE80211_NODE_REKEY) &&
+ --ic->ic_rsn_keydonesta == 0)
+ ieee80211_setkeysdone(ic);
+ ni->ni_flags &= ~IEEE80211_NODE_REKEY;
+
+ ni->ni_rsn_gstate = RSNA_IDLE;
+ ni->ni_rsn_retries = 0;
-#ifdef notyet
- if (--ic->ic_keydone_sta == 0) {
- /* install GTK */
- }
-#endif
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
ic->ic_if.if_xname, 2, 2, "group key",
@@ -2479,8 +2730,8 @@ ieee80211_recv_group_msg2(struct ieee80211com *ic,
/*
* EAPOL-Key Request frames are sent by the supplicant to request that the
- * authenticator initiate either a 4-Way Handshake or Group Key Handshake
- * and to report a MIC failure in a TKIP MSDU.
+ * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
+ * or to report a MIC failure in a TKIP MSDU.
*/
void
ieee80211_recv_eapol_key_req(struct ieee80211com *ic,
@@ -2494,11 +2745,36 @@ ieee80211_recv_eapol_key_req(struct ieee80211com *ic,
info = BE_READ_2(key->info);
- if (info & EAPOL_KEY_ERROR) {
- /* TKIP MIC failure */
+ /* enforce monotonicity of key request replay counter */
+ if (ni->ni_reqreplaycnt_ok &&
+ BE_READ_8(key->replaycnt) <= ni->ni_reqreplaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ if (!(info & EAPOL_KEY_KEYMIC) ||
+ ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+ /* update key request replay counter now that MIC is verified */
+ ni->ni_reqreplaycnt = BE_READ_8(key->replaycnt);
+ ni->ni_reqreplaycnt_ok = 1;
+
+ if (info & EAPOL_KEY_ERROR) { /* TKIP MIC failure */
+ /* ignore reports from STAs not using TKIP */
+ if (ic->ic_bss->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
+ ni->ni_rsncipher != IEEE80211_CIPHER_TKIP) {
+ IEEE80211_DPRINTF(("%s: MIC failure report from "
+ "STA not using TKIP: %s\n", __func__,
+ ether_sprintf(ni->ni_macaddr)));
+ return;
+ }
+ ic->ic_stats.is_rx_remmicfail++;
+ ieee80211_michael_mic_failure(ic, LE_READ_6(key->rsc));
} else if (info & EAPOL_KEY_PAIRWISE) {
- /* initiate the 4-Way Handshake */
+ /* initiate a 4-Way Handshake */
} else {
/*
@@ -2508,89 +2784,64 @@ ieee80211_recv_eapol_key_req(struct ieee80211com *ic,
}
}
-#ifdef IEEE80211_DEBUG
-static void
-ieee80211_print_eapol_key(struct ieee80211com *ic,
- const struct ieee80211_eapol_key *key, const struct ieee80211_node *ni)
-{
- int i;
- printf("%s: received EAPOL-Key frame from %s\n",
- ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr));
- printf("version=0x%02x type=0x%02x desc=0x%02x body length=%d "
- "data length=%d\n", key->version, key->type, key->desc,
- BE_READ_2(key->len), BE_READ_2(key->paylen));
- printf("info=%b\n", BE_READ_2(key->info),
- "\20\x03PAIRWISE\x06INSTALL\x07KEYACK\x08KEYMIC\x09SECURE"
- "\x0aERROR\x0bREQUEST\x0cENCRYPTED\x0dSMK");
- printf("Key Replay Counter=0x");
- for (i = 0; i < 8; i++)
- printf("%02x", key->replaycnt[i]);
- printf("\n");
- printf("Key Nonce=0x");
- for (i = 0; i < EAPOL_KEY_NONCE_LEN; i++)
- printf("%02x", key->nonce[i]);
- printf("\n");
- printf("Key IV=0x");
- for (i = 0; i < EAPOL_KEY_IV_LEN; i++)
- printf("%02x", key->iv[i]);
- printf("\n");
- printf("Key RSC=0x");
- for (i = 0; i < 8; i++)
- printf("%02x", key->rsc[i]);
- printf("\n");
- printf("Key MIC=0x");
- for (i = 0; i < EAPOL_KEY_MIC_LEN; i++)
- printf("%02x", key->mic[i]);
- printf("\n");
-}
-#endif
-
/*
* Process an incoming EAPOL frame. Notice that we are only interested in
- * EAPOL-Key frames with an IEEE 802.11 or WPA1 descriptor type.
+ * EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type.
*/
void
ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni)
{
+ struct ifnet *ifp = &ic->ic_if;
+ struct ether_header *eh;
struct ieee80211_eapol_key *key;
u_int16_t info, desc;
- if (m0->m_len < sizeof(struct ether_header) + sizeof(*key))
- goto out;
+ ifp->if_ibytes += m0->m_pkthdr.len;
- m_adj(m0, sizeof(struct ether_header));
+ if (m0->m_len < sizeof(*eh) + sizeof(*key))
+ return;
+ eh = mtod(m0, struct ether_header *);
+ if (IEEE80211_IS_MULTICAST(eh->ether_dhost)) {
+ ifp->if_imcasts++;
+ return;
+ }
+ m_adj(m0, sizeof(*eh));
key = mtod(m0, struct ieee80211_eapol_key *);
- if (key->type != EAPOL_KEY || key->desc != ni->ni_eapol_desc)
- goto out;
+ if (key->type != EAPOL_KEY)
+ return;
+ ic->ic_stats.is_rx_eapol_key++;
+
+ if ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
+ key->desc != EAPOL_KEY_DESC_IEEE80211) ||
+ (ni->ni_rsnprotos == IEEE80211_PROTO_WPA &&
+ key->desc != EAPOL_KEY_DESC_WPA))
+ return;
/* check packet body length */
if (m0->m_len < 4 + BE_READ_2(key->len))
- goto out;
+ return;
/* check key data length */
if (m0->m_len < sizeof(*key) + BE_READ_2(key->paylen))
- goto out;
+ return;
-#ifdef IEEE80211_DEBUG
- if (ieee80211_debug > 0)
- ieee80211_print_eapol_key(ic, key, ni);
-#endif
info = BE_READ_2(key->info);
/* discard EAPOL-Key frames with an unknown descriptor version */
desc = info & EAPOL_KEY_VERSION_MASK;
if (desc != EAPOL_KEY_DESC_V1 && desc != EAPOL_KEY_DESC_V2)
- goto out;
+ return;
- if (ni->ni_pairwise_cipher == IEEE80211_CIPHER_CCMP &&
+ if ((ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) &&
desc != EAPOL_KEY_DESC_V2)
- goto out;
+ return;
/* determine message type (see 8.5.3.7) */
if (info & EAPOL_KEY_REQUEST) {
- /* EAPOL-Key Request */
+ /* EAPOL-Key Request frame */
ieee80211_recv_eapol_key_req(ic, key, ni);
} else if (info & EAPOL_KEY_PAIRWISE) {
@@ -2600,22 +2851,20 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
ieee80211_recv_4way_msg3(ic, key, ni);
else
ieee80211_recv_4way_msg2or4(ic, key, ni);
- } else
+ } else if (info & EAPOL_KEY_KEYACK)
ieee80211_recv_4way_msg1(ic, key, ni);
} else {
/* Group Key Handshake */
if (!(info & EAPOL_KEY_KEYMIC))
- goto out;
+ return;
if (info & EAPOL_KEY_KEYACK) {
- if (key->desc == EAPOL_KEY_DESC_WPA1)
+ if (key->desc == EAPOL_KEY_DESC_WPA)
ieee80211_recv_wpa_group_msg1(ic, key, ni);
else
ieee80211_recv_rsn_group_msg1(ic, key, ni);
} else
ieee80211_recv_group_msg2(ic, key, ni);
}
- out:
- m_freem(m0);
}
void
@@ -2628,7 +2877,7 @@ ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m0, int rssi,
struct mbuf *m;
u_int16_t aid;
- if (ic->ic_set_tim == NULL) /* no powersaving functionality */
+ if (ic->ic_set_tim == NULL) /* no powersaving functionality */
return;
wh = mtod(m0, struct ieee80211_frame *);
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index adc7a3efc66..bf379639e9c 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_ioctl.c,v 1.20 2007/11/25 16:47:44 brad Exp $ */
+/* $OpenBSD: ieee80211_ioctl.c,v 1.21 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */
/*-
@@ -92,6 +92,7 @@ ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
nr->nr_inact = ni->ni_inact;
nr->nr_txrate = ni->ni_txrate;
nr->nr_state = ni->ni_state;
+ /* XXX RSN */
/* Node flags */
nr->nr_flags = 0;
@@ -131,6 +132,192 @@ ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
ni->ni_state = nr->nr_state;
}
+static int
+ieee80211_ioctl_setnwkeys(struct ieee80211com *ic,
+ const struct ieee80211_nwkey *nwkey)
+{
+ struct ieee80211_key *k;
+ int error, i;
+
+ if (!(ic->ic_caps & IEEE80211_C_WEP))
+ return ENODEV;
+
+ if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
+ if (!(ic->ic_flags & IEEE80211_F_WEPON))
+ return 0;
+ ic->ic_flags &= ~IEEE80211_F_WEPON;
+ return ENETRESET;
+ }
+ if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID)
+ return EINVAL;
+
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keylen == 0 ||
+ nwkey->i_key[i].i_keydat == NULL)
+ continue; /* entry not set */
+ if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE)
+ return EINVAL;
+
+ /* map wep key to ieee80211_key */
+ k = &ic->ic_nw_keys[i];
+ if (k->k_cipher != IEEE80211_CIPHER_NONE)
+ (*ic->ic_delete_key)(ic, NULL, k);
+ memset(k, 0, sizeof(*k));
+ if (nwkey->i_key[i].i_keylen <= 5)
+ k->k_cipher = IEEE80211_CIPHER_WEP40;
+ else
+ k->k_cipher = IEEE80211_CIPHER_WEP104;
+ k->k_len = nwkey->i_key[i].i_keylen;
+ k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
+ error = copyin(nwkey->i_key[i].i_keydat, k->k_key,
+ nwkey->i_key[i].i_keylen);
+ if (error != 0)
+ return error;
+ if ((error = (*ic->ic_set_key)(ic, NULL, k)) != 0)
+ return error;
+ }
+
+ ic->ic_def_txkey = nwkey->i_defkid - 1;
+ ic->ic_flags |= IEEE80211_F_WEPON;
+
+ return ENETRESET;
+}
+
+static int
+ieee80211_ioctl_getnwkeys(struct ieee80211com *ic,
+ struct ieee80211_nwkey *nwkey)
+{
+ struct ieee80211_key *k;
+ int error, i;
+
+ if (ic->ic_flags & IEEE80211_F_WEPON)
+ nwkey->i_wepon = IEEE80211_NWKEY_WEP;
+ else
+ nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
+
+ nwkey->i_defkid = ic->ic_wep_txkey + 1;
+
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keydat == NULL)
+ continue;
+ /* do not show any keys to non-root user */
+ if ((error = suser(curproc, 0)) != 0)
+ return error;
+ k = &ic->ic_nw_keys[i];
+ if (k->k_cipher != IEEE80211_CIPHER_WEP40 &&
+ k->k_cipher != IEEE80211_CIPHER_WEP104)
+ nwkey->i_key[i].i_keylen = 0;
+ else
+ nwkey->i_key[i].i_keylen = k->k_len;
+ error = copyout(k->k_key, nwkey->i_key[i].i_keydat,
+ nwkey->i_key[i].i_keylen);
+ if (error != 0)
+ return error;
+ }
+ return 0;
+}
+
+static int
+ieee80211_ioctl_setwpaparms(struct ieee80211com *ic,
+ const struct ieee80211_wpaparams *wpa)
+{
+ if (!(ic->ic_caps & IEEE80211_C_RSN))
+ return ENODEV;
+
+ if (!wpa->i_enabled) {
+ if (!(ic->ic_flags & IEEE80211_F_RSNON))
+ return 0;
+ ic->ic_flags &= ~IEEE80211_F_RSNON;
+ return ENETRESET;
+ }
+
+ ic->ic_rsnprotos = 0;
+ if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1)
+ ic->ic_rsnprotos |= IEEE80211_PROTO_WPA;
+ if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
+ ic->ic_rsnprotos |= IEEE80211_PROTO_RSN;
+ if (ic->ic_rsnprotos == 0) /* set to default (WPA+RSN) */
+ ic->ic_rsnprotos = IEEE80211_PROTO_WPA | IEEE80211_PROTO_RSN;
+
+ ic->ic_rsnakms = 0;
+ if (wpa->i_akms & IEEE80211_WPA_AKM_PSK)
+ ic->ic_rsnakms |= IEEE80211_AKM_PSK;
+ if (wpa->i_akms & IEEE80211_WPA_AKM_IEEE8021X)
+ ic->ic_rsnakms |= IEEE80211_AKM_IEEE8021X;
+ if (ic->ic_rsnakms == 0) /* set to default (PSK+802.1X) */
+ ic->ic_rsnakms = IEEE80211_AKM_PSK | IEEE80211_AKM_IEEE8021X;
+
+ if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40)
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40;
+ else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP)
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
+ else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP)
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
+ else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104)
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP104;
+ else { /* set to default */
+ if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
+ else
+ ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
+ }
+
+ ic->ic_rsnciphers = 0;
+ if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP)
+ ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
+ if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP)
+ ic->ic_rsnciphers |= IEEE80211_CIPHER_CCMP;
+ if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP)
+ ic->ic_rsnciphers = IEEE80211_CIPHER_USEGROUP;
+ if (ic->ic_rsnciphers == 0) /* set to default (TKIP+CCMP) */
+ ic->ic_rsnciphers = IEEE80211_CIPHER_TKIP |
+ IEEE80211_CIPHER_CCMP;
+
+ ic->ic_flags |= IEEE80211_F_RSNON;
+
+ return ENETRESET;
+}
+
+static int
+ieee80211_ioctl_getwpaparms(struct ieee80211com *ic,
+ struct ieee80211_wpaparams *wpa)
+{
+ wpa->i_enabled = (ic->ic_flags & IEEE80211_F_RSNON) ? 1 : 0;
+
+ wpa->i_protos = 0;
+ if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
+ wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
+ if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)
+ wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
+
+ wpa->i_akms = 0;
+ if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
+ wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
+ if (ic->ic_rsnakms & IEEE80211_AKM_IEEE8021X)
+ wpa->i_akms |= IEEE80211_WPA_AKM_IEEE8021X;
+
+ if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP40)
+ wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
+ else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_TKIP)
+ wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
+ else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP)
+ wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
+ else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP104)
+ wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
+ else
+ wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
+
+ wpa->i_ciphers = 0;
+ if (ic->ic_rsnciphers & IEEE80211_CIPHER_TKIP)
+ wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
+ if (ic->ic_rsnciphers & IEEE80211_CIPHER_CCMP)
+ wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
+ if (ic->ic_rsnciphers & IEEE80211_CIPHER_USEGROUP)
+ wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
+
+ return 0;
+}
+
int
ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -138,13 +325,13 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *)data;
int i, error = 0;
struct ieee80211_nwid nwid;
- struct ieee80211_nwkey *nwkey;
+ struct ieee80211_wpapsk *psk;
+ struct ieee80211_wmmparams *wmm;
struct ieee80211_power *power;
struct ieee80211_bssid *bssid;
struct ieee80211chanreq *chanreq;
struct ieee80211_channel *chan;
struct ieee80211_txpower *txpower;
- struct ieee80211_key keys[IEEE80211_WEP_NKID];
static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -194,81 +381,63 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCS80211NWKEY:
if ((error = suser(curproc, 0)) != 0)
break;
- nwkey = (struct ieee80211_nwkey *)data;
- if ((ic->ic_caps & IEEE80211_C_WEP) == 0 &&
- nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
- error = EINVAL;
+ error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
+ break;
+ case SIOCG80211NWKEY:
+ error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
+ break;
+ case SIOCS80211WMMPARMS:
+ if ((error = suser(curproc, 0)) != 0)
break;
- }
- /* check and copy keys */
- memset(keys, 0, sizeof(keys));
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- keys[i].k_len = nwkey->i_key[i].i_keylen;
- /*
- * Limit the maximal allowed key size to
- * IEEE80211_KEYBUF_SIZE bytes.
- */
- if (keys[i].k_len > sizeof(keys[i].k_key)) {
- error = EINVAL;
- break;
- }
- if (keys[i].k_len <= 0)
- continue;
- if ((error = copyin(nwkey->i_key[i].i_keydat,
- keys[i].k_key, keys[i].k_len)) != 0)
- break;
- }
- if (error)
+ if (!(ic->ic_flags & IEEE80211_C_QOS)) {
+ error = ENODEV;
break;
- i = nwkey->i_defkid - 1;
- if (i < 0 || i >= IEEE80211_WEP_NKID ||
- keys[i].k_len == 0 ||
- (keys[i].k_len == -1 && ic->ic_nw_keys[i].k_len == 0)) {
- if (nwkey->i_wepon != IEEE80211_NWKEY_OPEN) {
- error = EINVAL;
- break;
- }
- } else
- ic->ic_wep_txkey = i;
- /* save the key */
- if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN)
- ic->ic_flags &= ~IEEE80211_F_WEPON;
+ }
+ wmm = (struct ieee80211_wmmparams *)data;
+ if (wmm->i_enabled)
+ ic->ic_flags |= IEEE80211_F_QOS;
else
- ic->ic_flags |= IEEE80211_F_WEPON;
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- struct ieee80211_key *k = &ic->ic_nw_keys[i];
- if (keys[i].k_len < 0)
- continue;
- if (keys[i].k_len == 0)
- k->k_cipher = IEEE80211_CIPHER_NONE;
- else if (keys[i].k_len <= 5)
- k->k_cipher = IEEE80211_CIPHER_WEP40;
- else
- k->k_cipher = IEEE80211_CIPHER_WEP104;
- k->k_len = keys[i].k_len;
- memcpy(k->k_key, keys[i].k_key, sizeof(keys[i].k_key));
+ ic->ic_flags &= ~IEEE80211_F_QOS;
+ error = ENETRESET;
+ break;
+ case SIOCG80211WMMPARMS:
+ wmm = (struct ieee80211_wmmparams *)data;
+ wmm->i_enabled = (ic->ic_flags & IEEE80211_F_QOS) ? 1 : 0;
+ break;
+ case SIOCS80211WPAPARMS:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+ error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
+ break;
+ case SIOCG80211WPAPARMS:
+ error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
+ break;
+ case SIOCS80211WPAPSK:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+ psk = (struct ieee80211_wpapsk *)data;
+ if (psk->i_enabled) {
+ ic->ic_flags |= IEEE80211_F_PSK;
+ memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
+ } else {
+ ic->ic_flags &= ~IEEE80211_F_PSK;
+ memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
}
error = ENETRESET;
break;
- case SIOCG80211NWKEY:
- nwkey = (struct ieee80211_nwkey *)data;
- if (ic->ic_flags & IEEE80211_F_WEPON)
- nwkey->i_wepon = IEEE80211_NWKEY_WEP;
- else
- nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
- nwkey->i_defkid = ic->ic_wep_txkey + 1;
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- if (nwkey->i_key[i].i_keydat == NULL)
- continue;
+ case SIOCG80211WPAPSK:
+ psk = (struct ieee80211_wpapsk *)data;
+ if (ic->ic_flags & IEEE80211_F_PSK) {
+ psk->i_enabled = 1;
/* do not show any keys to non-root user */
- if ((error = suser(curproc, 0)) != 0)
- break;
- nwkey->i_key[i].i_keylen = ic->ic_nw_keys[i].k_len;
- if ((error = copyout(ic->ic_nw_keys[i].k_key,
- nwkey->i_key[i].i_keydat,
- ic->ic_nw_keys[i].k_len)) != 0)
- break;
- }
+ if (suser(curproc, 0) != 0) {
+ psk->i_enabled = 2;
+ memset(psk->i_psk, 0, sizeof(psk->i_psk));
+ break; /* return ok but w/o key */
+ }
+ memcpy(psk->i_psk, ic->ic_psk, sizeof(psk->i_psk));
+ } else
+ psk->i_enabled = 0;
break;
case SIOCS80211POWER:
if ((error = suser(curproc, 0)) != 0)
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index 5cf82ec1676..8541ac556a0 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_ioctl.h,v 1.10 2007/08/14 20:33:47 bluhm Exp $ */
+/* $OpenBSD: ieee80211_ioctl.h,v 1.11 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $ */
/*-
@@ -82,6 +82,13 @@ struct ieee80211_stats {
u_int32_t is_node_timeout; /* nodes timed out inactivity */
u_int32_t is_crypto_nomem; /* no memory for crypto ctx */
u_int32_t is_rx_assoc_badrsnie; /* rx assoc w/ bad RSN IE */
+ u_int32_t is_rx_unauth; /* rx port not valid */
+ u_int32_t is_tx_noauth; /* tx port not valid */
+ u_int32_t is_rx_eapol_key; /* rx eapol-key frames */
+ u_int32_t is_rx_eapol_replay; /* rx replayed eapol frames */
+ u_int32_t is_rx_eapol_badmic; /* rx eapol frames w/ bad mic */
+ u_int32_t is_rx_remmicfail; /* rx tkip remote mic fails */
+ u_int32_t is_rx_locmicfail; /* rx tkip local mic fails */
};
#define SIOCG80211STATS _IOWR('i', 242, struct ifreq)
@@ -171,6 +178,49 @@ struct ieee80211_txpower {
#define IEEE80211_TXPOWER_MODE_FIXED 0 /* fixed tx power value */
#define IEEE80211_TXPOWER_MODE_AUTO 1 /* auto level control */
+struct ieee80211_wpapsk {
+ char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
+ int i_enabled;
+ u_int8_t i_psk[32];
+};
+
+#define SIOCS80211WPAPSK _IOW('i', 245, struct ieee80211_wpapsk)
+#define SIOCG80211WPAPSK _IOWR('i', 246, struct ieee80211_wpapsk)
+
+#define IEEE80211_WPA_PROTO_WPA1 0x01
+#define IEEE80211_WPA_PROTO_WPA2 0x02
+
+#define IEEE80211_WPA_CIPHER_NONE 0x00
+#define IEEE80211_WPA_CIPHER_USEGROUP 0x01
+#define IEEE80211_WPA_CIPHER_WEP40 0x02
+#define IEEE80211_WPA_CIPHER_TKIP 0x04
+#define IEEE80211_WPA_CIPHER_CCMP 0x08
+#define IEEE80211_WPA_CIPHER_WEP104 0x10
+
+#define IEEE80211_WPA_AKM_PSK 0x01
+#define IEEE80211_WPA_AKM_IEEE8021X 0x02
+
+struct ieee80211_wpaparams {
+ char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
+ int i_enabled;
+ u_int i_protos;
+ u_int i_akms;
+ u_int i_ciphers;
+ u_int i_groupcipher;
+};
+
+#define SIOCS80211WPAPARMS _IOW('i', 247, struct ieee80211_wpaparams)
+#define SIOCG80211WPAPARMS _IOWR('i', 248, struct ieee80211_wpaparams)
+
+struct ieee80211_wmmparams {
+ char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
+ int i_enabled;
+ /* XXX more */
+};
+
+#define SIOCS80211WMMPARMS _IOW('i', 249, struct ieee80211_wmmparams)
+#define SIOCG80211WMMPARMS _IOWR('i', 250, struct ieee80211_wmmparams)
+
/* scan request (will block) */
#define IEEE80211_SCAN_TIMEOUT 30 /* timeout in seconds */
@@ -210,6 +260,8 @@ struct ieee80211_nodereq {
u_int8_t nr_txrate; /* index to nr_rates[] */
u_int16_t nr_state; /* node state in the cache */
+ /* XXX RSN */
+
/* Node flags */
u_int8_t nr_flags;
};
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index 1384c998a10..53f4fe4af29 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.c,v 1.30 2007/10/29 15:40:23 chl Exp $ */
+/* $OpenBSD: ieee80211_node.c,v 1.31 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */
/*-
@@ -79,7 +79,9 @@ void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *,
void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *);
+void ieee80211_node_join_rsn(struct ieee80211com *, struct ieee80211_node *);
void ieee80211_node_join_11g(struct ieee80211com *, struct ieee80211_node *);
+void ieee80211_node_leave_rsn(struct ieee80211com *, struct ieee80211_node *);
void ieee80211_node_leave_11g(struct ieee80211com *, struct ieee80211_node *);
void ieee80211_set_tim(struct ieee80211com *, int, int);
@@ -110,7 +112,6 @@ ieee80211_node_attach(struct ifnet *ifp)
printf("%s: no memory for AID bitmap!\n", __func__);
ic->ic_max_aid = 0;
}
-
if (ic->ic_caps & (IEEE80211_C_HOSTAP | IEEE80211_C_IBSS)) {
ic->ic_tim_len = howmany(ic->ic_max_aid, 8);
ic->ic_tim_bitmap = malloc(ic->ic_tim_len, M_DEVBUF,
@@ -120,6 +121,8 @@ ieee80211_node_attach(struct ifnet *ifp)
ic->ic_tim_len = 0;
} else
ic->ic_set_tim = ieee80211_set_tim;
+ timeout_set(&ic->ic_rsn_timeout,
+ ieee80211_gtk_rekey_timeout, ic);
}
}
@@ -299,6 +302,36 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
if (ic->ic_flags & IEEE80211_F_WEPON)
ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ struct ieee80211_key *k;
+ u_int8_t gtk[IEEE80211_PMK_LEN];
+
+ /* initialize 256-bit global key counter to a random value */
+ arc4random_bytes(ic->ic_globalcnt, EAPOL_KEY_NONCE_LEN);
+
+ ni->ni_rsnprotos = ic->ic_rsnprotos;
+ ni->ni_rsnakms = ic->ic_rsnakms;
+ ni->ni_rsnciphers = ic->ic_rsnciphers;
+ ni->ni_rsngroupcipher = ic->ic_rsngroupcipher;
+ ni->ni_rsncaps = 0;
+
+ ic->ic_def_txkey = 1;
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
+ arc4random_bytes(gtk, sizeof(gtk));
+ ieee80211_map_gtk(gtk, ni->ni_rsngroupcipher,
+ ic->ic_def_txkey, 1, 0, k);
+ (*ic->ic_set_key)(ic, ni, k); /* XXX */
+
+ /*
+ * In HostAP mode, multicast traffic is sent using ic_bss
+ * as the Tx node, so mark our node as valid so we can send
+ * multicast frames using the group key we've just configured.
+ */
+ ni->ni_port_valid = 1;
+
+ /* schedule a GTK rekeying after 3600s */
+ timeout_add(&ic->ic_rsn_timeout, 3600 * hz);
+ }
if (ic->ic_phytype == IEEE80211_T_FH) {
ni->ni_fhdwell = 200; /* XXX */
ni->ni_fhindex = 1;
@@ -325,14 +358,14 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
fail |= 0x02;
}
- if (ic->ic_flags & IEEE80211_F_WEPON) {
+ if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
fail |= 0x04;
} else {
- /* XXX does this mean privacy is supported or required? */
if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
fail |= 0x04;
}
+
rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
if (rate & IEEE80211_RATE_BASIC)
fail |= 0x08;
@@ -343,6 +376,24 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
!IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
fail |= 0x20;
+
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ /*
+ * If at least one RSN IE field from the AP's RSN IE fails
+ * to overlap with any value the STA supports, the STA shall
+ * decline to associate with that AP.
+ */
+ if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0)
+ fail |= 0x40;
+ if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0)
+ fail |= 0x40;
+ if ((ni->ni_rsnakms & ic->ic_rsnakms) == IEEE80211_AKM_PSK &&
+ !(ic->ic_flags & IEEE80211_F_PSK))
+ fail |= 0x40;
+ if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0)
+ fail |= 0x40;
+ }
+
#ifdef IEEE80211_DEBUG
if (ic->ic_if.if_flags & IFF_DEBUG) {
printf(" %c %s", fail ? '-' : '+',
@@ -359,10 +410,14 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
(ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
"????",
fail & 0x02 ? '!' : ' ');
- printf(" %3s%c ",
+ printf(" %7s%c ",
(ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
- "wep" : "no",
+ "privacy" : "no",
fail & 0x04 ? '!' : ' ');
+ printf(" %3s%c ",
+ (ic->ic_flags & IEEE80211_F_RSNON) ?
+ "rsn" : "no",
+ fail & 0x40 ? '!' : ' ');
ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
printf("%s\n", fail & 0x10 ? "!" : "");
}
@@ -472,20 +527,51 @@ ieee80211_end_scan(struct ifnet *ifp)
if (selbs == NULL)
goto notfound;
(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
+ ni = ic->ic_bss;
/*
* Set the erp state (mostly the slot time) to deal with
* the auto-select case; this should be redundant if the
* mode is locked.
*/
- ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan);
+ ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan);
ieee80211_reset_erp(ic);
+ if (ic->ic_flags & IEEE80211_F_RSNON) {
+ /* prefer RSN (WPA2) over WPA */
+ ni->ni_rsnprotos &= ic->ic_rsnprotos;
+ if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)
+ ni->ni_rsnprotos = IEEE80211_PROTO_RSN;
+ else
+ ni->ni_rsnprotos = IEEE80211_PROTO_WPA;
+ /*
+ * If a pre-shared key is configured and AP supports PSK,
+ * choose PSK as AKMP.
+ */
+ ni->ni_rsnakms &= ic->ic_rsnakms;
+ if ((ni->ni_rsnakms & IEEE80211_AKM_PSK) &&
+ (ic->ic_flags & IEEE80211_F_PSK))
+ ni->ni_rsnakms = IEEE80211_AKM_PSK;
+ else
+ ni->ni_rsnakms = IEEE80211_AKM_IEEE8021X;
+
+ /* prefer CCMP over TKIP if the AP supports it */
+ ni->ni_rsnciphers &= ic->ic_rsnciphers;
+ if (ni->ni_rsnciphers & IEEE80211_CIPHER_CCMP)
+ ni->ni_rsnciphers = IEEE80211_CIPHER_CCMP;
+ else
+ ni->ni_rsnciphers = IEEE80211_CIPHER_TKIP;
+
+ ni->ni_rsncipher = ni->ni_rsnciphers;
+
+ } else if (ic->ic_flags & IEEE80211_F_WEPON)
+ ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP;
+
ieee80211_node_newstate(selbs, IEEE80211_STA_BSS);
if (ic->ic_opmode == IEEE80211_M_IBSS) {
- ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
+ ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
- if (ic->ic_bss->ni_rates.rs_nrates == 0)
+ if (ni->ni_rates.rs_nrates == 0)
goto notfound;
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
} else {
@@ -529,6 +615,10 @@ ieee80211_node_alloc(struct ieee80211com *ic)
void
ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni)
{
+ if (ni->ni_rsnie != NULL) {
+ free(ni->ni_rsnie, M_DEVBUF);
+ ni->ni_rsnie = NULL;
+ }
}
void
@@ -544,6 +634,9 @@ ieee80211_node_copy(struct ieee80211com *ic,
{
ieee80211_node_cleanup(ic, dst);
*dst = *src;
+ dst->ni_rsnie = NULL;
+ if (src->ni_rsnie != NULL)
+ ieee80211_save_ie(src->ni_rsnie, &dst->ni_rsnie);
}
u_int8_t
@@ -564,6 +657,8 @@ ieee80211_setup_node(struct ieee80211com *ic,
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
ieee80211_node_newstate(ni, IEEE80211_STA_CACHE);
+ ni->ni_ic = ic; /* back-pointer */
+
/*
* Note we don't enable the inactive timer when acting
* as a station. Nodes created in this mode represent
@@ -945,6 +1040,37 @@ ieee80211_iserp_sta(const struct ieee80211_node *ni)
}
/*
+ * Handle a station joining an RSN network.
+ */
+void
+ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ IEEE80211_DPRINTF(("station %s associated using proto %d akm 0x%x "
+ "cipher 0x%x groupcipher 0x%x\n", ether_sprintf(ni->ni_macaddr),
+ ni->ni_rsnprotos, ni->ni_rsnakms, ni->ni_rsnciphers,
+ ni->ni_rsngroupcipher));
+
+ ni->ni_rsn_state = RSNA_AUTHENTICATION;
+ ic->ic_rsnsta++;
+
+ ni->ni_key_count = 0;
+ ni->ni_port_valid = 0;
+ ni->ni_replaycnt = -1; /* XXX */
+ ni->ni_rsn_retries = 0;
+ ni->ni_rsncipher = ni->ni_rsnciphers;
+ timeout_set(&ni->ni_rsn_timeout, ieee80211_eapol_timeout, ni);
+
+ ni->ni_rsn_state = RSNA_AUTHENTICATION_2;
+
+ /* generate a new authenticator nonce (ANonce) */
+ arc4random_bytes(ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
+
+ /* initiate 4-way handshake */
+ if (ni->ni_rsnakms == IEEE80211_AKM_PSK)
+ (void)ieee80211_send_4way_msg1(ic, ni);
+}
+
+/*
* Handle a station joining an 11g network.
*/
void
@@ -1032,6 +1158,12 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC);
+ if (!(ic->ic_flags & IEEE80211_F_RSNON)) {
+ ni->ni_port_valid = 1;
+ ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP;
+ } else
+ ieee80211_node_join_rsn(ic, ni);
+
#if NBRIDGE > 0
/*
* If the parent interface belongs to a bridge, learn
@@ -1044,6 +1176,29 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
}
/*
+ * Handle a station leaving an RSN network.
+ */
+void
+ieee80211_node_leave_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ ni->ni_rsn_state = RSNA_DISCONNECTED;
+ ic->ic_rsnsta--;
+
+ ni->ni_rsn_state = RSNA_INITIALIZE;
+ if ((ni->ni_flags & IEEE80211_NODE_REKEY) &&
+ --ic->ic_rsn_keydonesta == 0)
+ ieee80211_setkeysdone(ic);
+ ni->ni_flags &= ~IEEE80211_NODE_REKEY;
+
+ ni->ni_rsn_gstate = RSNA_IDLE;
+
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_retries = 0;
+ ni->ni_port_valid = 0;
+ (*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key);
+}
+
+/*
* Handle a station leaving an 11g network.
*/
void
@@ -1114,6 +1269,9 @@ ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
ni->ni_associd = 0;
+ if (ic->ic_flags & IEEE80211_F_RSNON)
+ ieee80211_node_leave_rsn(ic, ni);
+
if (ic->ic_curmode == IEEE80211_MODE_11G)
ieee80211_node_leave_11g(ic, ni);
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index f7d971a78e9..4cb40c5d397 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.h,v 1.25 2007/11/03 14:59:55 mglocker Exp $ */
+/* $OpenBSD: ieee80211_node.h,v 1.26 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
/*-
@@ -65,8 +65,9 @@ enum ieee80211_node_state {
(__ni)->ni_state = (__state); \
} while (0)
-/* RSNA Authenticator state machine (see 8.5.6). */
+/* Authenticator state machine: 4-Way Handshake (see 8.5.6.1.1) */
enum {
+ RSNA_INITIALIZE,
RSNA_AUTHENTICATION,
RSNA_AUTHENTICATION_2,
RSNA_INITPMK,
@@ -77,15 +78,15 @@ enum {
RSNA_PTKINITNEGOTIATING,
RSNA_PTKINITDONE,
RSNA_DISCONNECT,
- RSNA_DISCONNECTED,
- RSNA_INITIALIZE,
+ RSNA_DISCONNECTED
+};
+
+/* Authenticator state machine: Group Key Handshake (see 8.5.6.1.2) */
+enum {
RSNA_IDLE,
RSNA_REKEYNEGOTIATING,
- RSNA_KEYERROR,
RSNA_REKEYESTABLISHED,
- RSNA_GTK_INIT,
- RSNA_SETKEYSDONE,
- RSNA_SETKEYS
+ RSNA_KEYERROR
};
/*
@@ -97,6 +98,8 @@ enum {
struct ieee80211_node {
RB_ENTRY(ieee80211_node) ni_node;
+ struct ieee80211com *ni_ic; /* back-pointer */
+
u_int ni_refcnt;
u_int ni_scangen; /* gen# for timeout scan */
@@ -137,22 +140,25 @@ struct ieee80211_node {
/* RSN */
u_int ni_rsn_state;
- u_int ni_rsn_tocnt;
- u_int ni_group_cipher;
- enum ieee80211_cipher ni_pairwise_cipher;
- u_int ni_pairwise_cipherset;
- enum ieee80211_akm ni_akm;
- u_int ni_akmset;
+ u_int ni_rsn_gstate;
+ u_int ni_rsn_retries;
+ struct timeout ni_rsn_timeout;
+ u_int ni_rsnprotos;
+ u_int ni_rsnakms;
+ u_int ni_rsnciphers;
+ enum ieee80211_cipher ni_rsngroupcipher;
u_int16_t ni_rsncaps;
- int ni_port_valid;
- u_int8_t ni_eapol_desc;
+ enum ieee80211_cipher ni_rsncipher;
u_int8_t ni_nonce[EAPOL_KEY_NONCE_LEN];
u_int64_t ni_replaycnt;
u_int8_t ni_replaycnt_ok;
+ u_int64_t ni_reqreplaycnt;
+ u_int8_t ni_reqreplaycnt_ok;
u_int8_t *ni_rsnie;
struct ieee80211_key ni_pairwise_key;
struct ieee80211_ptk ni_ptk;
u_int8_t ni_key_count;
+ int ni_port_valid;
/* others */
u_int16_t ni_associd; /* assoc response */
@@ -168,6 +174,7 @@ struct ieee80211_node {
u_int8_t ni_flags; /* special-purpose state */
#define IEEE80211_NODE_ERP 0x01
#define IEEE80211_NODE_QOS 0x02
+#define IEEE80211_NODE_REKEY 0x04
};
RB_HEAD(ieee80211_tree, ieee80211_node);
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 6523e409cf8..33654eb2d32 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: ieee80211_output.c,v 1.58 2007/08/27 20:14:21 damien Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.59 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
- * Copyright (c) 2007 Damien Bergamini
+ * Copyright (c) 2007, 2008 Damien Bergamini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,15 +65,13 @@
#include <net80211/ieee80211_var.h>
-#include <dev/rndvar.h>
-
enum ieee80211_edca_ac ieee80211_up_to_ac(struct ieee80211com *, int);
int ieee80211_classify(struct ieee80211com *, struct mbuf *);
int ieee80211_mgmt_output(struct ifnet *, struct ieee80211_node *,
struct mbuf *, int);
u_int8_t *ieee80211_add_rsn_body(u_int8_t *, struct ieee80211com *,
const struct ieee80211_node *, int);
-struct mbuf *ieee80211_getmbuf(int, int, u_int);
+struct mbuf *ieee80211_getmgmt(int, int, u_int);
struct mbuf *ieee80211_get_probe_req(struct ieee80211com *,
struct ieee80211_node *);
struct mbuf *ieee80211_get_probe_resp(struct ieee80211com *,
@@ -89,8 +87,9 @@ struct mbuf *ieee80211_get_assoc_resp(struct ieee80211com *,
struct mbuf *ieee80211_get_disassoc(struct ieee80211com *,
struct ieee80211_node *, u_int16_t);
int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *);
-u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, const struct ieee80211_key *);
+ struct ieee80211_node *, const struct ieee80211_ptk *);
+u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *,
+ const struct ieee80211_key *);
u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *);
struct mbuf *ieee80211_get_eapol_key(int, int, u_int);
@@ -507,14 +506,19 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
ic->ic_stats.is_tx_nonode++;
goto bad;
}
-#if 0
- if (!ni->ni_port_valid && eh.ether_type != htons(ETHERTYPE_PAE)) {
+
+ if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid &&
+ eh.ether_type != htons(ETHERTYPE_PAE)) {
IEEE80211_DPRINTF(("%s: port not valid: %s\n",
__func__, ether_sprintf(eh.ether_dhost)));
ic->ic_stats.is_tx_noauth++;
goto bad;
}
-#endif
+
+ if ((ic->ic_flags & IEEE80211_F_COUNTERM) &&
+ ni->ni_rsncipher == IEEE80211_CIPHER_TKIP)
+ /* XXX TKIP countermeasures! */;
+
ni->ni_inact = 0;
if ((ic->ic_flags & IEEE80211_F_QOS) &&
@@ -581,8 +585,11 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
case IEEE80211_M_MONITOR:
goto bad;
}
- if (ic->ic_flags & IEEE80211_F_WEPON)
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
+
+ if ((ic->ic_flags & IEEE80211_F_WEPON) ||
+ ((ic->ic_flags & IEEE80211_F_RSNON) && ni->ni_port_valid))
+ wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
+
*pni = ni;
return m;
bad:
@@ -615,7 +622,8 @@ ieee80211_add_capinfo(u_int8_t *frm, struct ieee80211com *ic,
capinfo = IEEE80211_CAPINFO_ESS;
else
capinfo = 0;
- if (ic->ic_flags & IEEE80211_F_WEPON)
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)))
capinfo |= IEEE80211_CAPINFO_PRIVACY;
/* NB: some 11a AP's reject the request when short preamble is set */
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
@@ -814,9 +822,9 @@ ieee80211_add_qos_capability(u_int8_t *frm, struct ieee80211com *ic)
*/
u_int8_t *
ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
- const struct ieee80211_node *ni, int wpa1)
+ const struct ieee80211_node *ni, int wpa)
{
- const u_int8_t *oui = wpa1 ? MICROSOFT_OUI : IEEE80211_OUI;
+ const u_int8_t *oui = wpa ? MICROSOFT_OUI : IEEE80211_OUI;
u_int8_t *pcount;
u_int16_t count;
@@ -825,11 +833,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
/* write Group Cipher Suite field (see Table 20da) */
memcpy(frm, oui, 3); frm += 3;
- switch (ni->ni_group_cipher) {
- case IEEE80211_CIPHER_USEGROUP:
- /* can't get there */
- panic("invalid group cipher!");
- break;
+ switch (ni->ni_rsngroupcipher) {
case IEEE80211_CIPHER_WEP40:
*frm++ = 1;
break;
@@ -842,22 +846,25 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
case IEEE80211_CIPHER_WEP104:
*frm++ = 5;
break;
+ default:
+ /* can't get there */
+ panic("invalid group cipher!");
}
pcount = frm; frm += 2;
count = 0;
/* write Pairwise Cipher Suite List */
- if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_USEGROUP) {
+ if (ni->ni_rsnciphers & IEEE80211_CIPHER_USEGROUP) {
memcpy(frm, oui, 3); frm += 3;
*frm++ = 0;
count++;
}
- if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_TKIP) {
+ if (ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP) {
memcpy(frm, oui, 3); frm += 3;
*frm++ = 2;
count++;
}
- if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_CCMP) {
+ if (ni->ni_rsnciphers & IEEE80211_CIPHER_CCMP) {
memcpy(frm, oui, 3); frm += 3;
*frm++ = 4;
count++;
@@ -868,12 +875,12 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
pcount = frm; frm += 2;
count = 0;
/* write AKM Suite List (see Table 20dc) */
- if (ni->ni_akmset & IEEE80211_AKM_IEEE8021X) {
+ if (ni->ni_rsnakms & IEEE80211_AKM_IEEE8021X) {
memcpy(frm, oui, 3); frm += 3;
*frm++ = 1;
count++;
}
- if (ni->ni_akmset & IEEE80211_AKM_PSK) {
+ if (ni->ni_rsnakms & IEEE80211_AKM_PSK) {
memcpy(frm, oui, 3); frm += 3;
*frm++ = 2;
count++;
@@ -881,11 +888,12 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
/* write AKM Suite List Count field */
LE_WRITE_2(pcount, count);
- /* write RSN Capabilities field */
- LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
-
- /* no PMKID List for now */
+ if (!wpa) {
+ /* write RSN Capabilities field */
+ LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
+ /* no PMKID List for now */
+ }
return frm;
}
@@ -905,11 +913,11 @@ ieee80211_add_rsn(u_int8_t *frm, struct ieee80211com *ic,
}
/*
- * Add a vendor specific WPA1 element to a frame.
- * This is required for compatibility with Wi-Fi Alliance WPA1/WPA1+WPA2.
+ * Add a vendor-specific WPA element to a frame.
+ * This is required for compatibility with Wi-Fi Alliance WPA.
*/
u_int8_t *
-ieee80211_add_wpa1(u_int8_t *frm, struct ieee80211com *ic,
+ieee80211_add_wpa(u_int8_t *frm, struct ieee80211com *ic,
const struct ieee80211_node *ni)
{
u_int8_t *plen;
@@ -917,7 +925,7 @@ ieee80211_add_wpa1(u_int8_t *frm, struct ieee80211com *ic,
*frm++ = IEEE80211_ELEMID_VENDOR;
plen = frm++; /* length filled in later */
memcpy(frm, MICROSOFT_OUI, 3); frm += 3;
- *frm++ = 1; /* WPA1 */
+ *frm++ = 1; /* WPA */
frm = ieee80211_add_rsn_body(frm, ic, ni, 1);
/* write length field */
@@ -943,21 +951,24 @@ ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
}
struct mbuf *
-ieee80211_getmbuf(int flags, int type, u_int pktlen)
+ieee80211_getmgmt(int flags, int type, u_int pktlen)
{
struct mbuf *m;
- /* account for 802.11 header */
+ /* reserve space for 802.11 header */
pktlen += sizeof(struct ieee80211_frame);
if (pktlen > MCLBYTES)
- panic("802.11 packet too large: %u", pktlen);
+ panic("management frame too large: %u", pktlen);
MGETHDR(m, flags, type);
- if (m != NULL && pktlen > MHLEN) {
+ if (m == NULL)
+ return NULL;
+ if (pktlen >= MINCLSIZE) {
MCLGET(m, flags);
if (!(m->m_flags & M_EXT))
- m = m_free(m);
+ return m_free(m);
}
+ m->m_data += sizeof(struct ieee80211_frame);
return m;
}
@@ -975,7 +986,7 @@ ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni)
struct mbuf *m;
u_int8_t *frm;
- m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
2 + ic->ic_des_esslen +
2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
@@ -983,8 +994,6 @@ ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni)
if (m == NULL)
return NULL;
- m->m_data += sizeof(struct ieee80211_frame);
-
frm = mtod(m, u_int8_t *);
frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
frm = ieee80211_add_rates(frm, rs);
@@ -1017,7 +1026,7 @@ ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni)
struct mbuf *m;
u_int8_t *frm;
- m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
8 + 2 + 2 +
2 + ni->ni_esslen +
2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
@@ -1026,14 +1035,14 @@ ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni)
((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) +
((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
- ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + 44 : 0) +
((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) +
- ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + 48 : 0));
if (m == NULL)
return NULL;
- m->m_data += sizeof(struct ieee80211_frame);
-
frm = mtod(m, u_int8_t *);
memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */
LE_WRITE_2(frm, ic->ic_bss->ni_intval); frm += 2;
@@ -1051,12 +1060,14 @@ ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni)
frm = ieee80211_add_erp(frm, ic);
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
frm = ieee80211_add_xrates(frm, rs);
- if (ic->ic_flags & IEEE80211_F_RSN)
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_RSN))
frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
if (ic->ic_flags & IEEE80211_F_QOS)
frm = ieee80211_add_edca_params(frm, ic);
- if (ic->ic_flags & IEEE80211_F_WPA1)
- frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_WPA))
+ frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
@@ -1131,7 +1142,7 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
u_int8_t *frm;
u_int16_t capinfo;
- m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
2 + 2 +
((reassoc == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) ?
IEEE80211_ADDR_LEN : 0) +
@@ -1139,14 +1150,14 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
- ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + 44 : 0) +
((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 1 : 0) +
- ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + 48 : 0));
if (m == NULL)
return NULL;
- m->m_data += sizeof(struct ieee80211_frame);
-
frm = mtod(m, u_int8_t *);
capinfo = IEEE80211_CAPINFO_ESS;
if (ic->ic_flags & IEEE80211_F_WEPON)
@@ -1159,7 +1170,7 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
LE_WRITE_2(frm, capinfo); frm += 2;
LE_WRITE_2(frm, ic->ic_lintval); frm += 2;
- if (reassoc == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
+ if (reassoc) {
IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
frm += IEEE80211_ADDR_LEN;
}
@@ -1167,13 +1178,15 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
frm = ieee80211_add_rates(frm, rs);
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
frm = ieee80211_add_xrates(frm, rs);
- if (ic->ic_flags & IEEE80211_F_RSN)
- frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_RSN))
+ frm = ieee80211_add_rsn(frm, ic, ni);
if ((ic->ic_flags & IEEE80211_F_QOS) &&
(ni->ni_flags & IEEE80211_NODE_QOS))
frm = ieee80211_add_qos_capability(frm, ic);
- if (ic->ic_flags & IEEE80211_F_WPA1)
- frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
+ frm = ieee80211_add_wpa(frm, ic, ni);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
@@ -1197,7 +1210,7 @@ ieee80211_get_assoc_resp(struct ieee80211com *ic, struct ieee80211_node *ni,
struct mbuf *m;
u_int8_t *frm;
- m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
2 + 2 + 2 +
2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
@@ -1206,8 +1219,6 @@ ieee80211_get_assoc_resp(struct ieee80211com *ic, struct ieee80211_node *ni,
if (m == NULL)
return NULL;
- m->m_data += sizeof(struct ieee80211_frame);
-
frm = mtod(m, u_int8_t *);
frm = ieee80211_add_capinfo(frm, ic, ni);
LE_WRITE_2(frm, status); frm += 2;
@@ -1362,7 +1373,7 @@ ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh,
if (m == NULL)
return NULL;
- m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_rts);
+ m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts);
rts = mtod(m, struct ieee80211_frame_rts *);
rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
@@ -1388,7 +1399,7 @@ ieee80211_get_cts_to_self(struct ieee80211com *ic, u_int16_t dur)
if (m == NULL)
return NULL;
- m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_cts);
+ m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts);
cts = mtod(m, struct ieee80211_frame_cts *);
cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
@@ -1424,7 +1435,7 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
struct mbuf *m;
u_int8_t *frm;
- m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
8 + 2 + 2 +
2 + ((ic->ic_flags & IEEE80211_F_HIDENWID) ? 0 : ni->ni_esslen) +
2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
@@ -1433,12 +1444,17 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) +
((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
- ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + 44 : 0) +
((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) +
- ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
+ (((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + 48 : 0));
if (m == NULL)
return NULL;
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ if (m == NULL)
+ return NULL;
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_BEACON;
@@ -1470,12 +1486,14 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
frm = ieee80211_add_erp(frm, ic);
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
frm = ieee80211_add_xrates(frm, rs);
- if (ic->ic_flags & IEEE80211_F_RSN)
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_RSN))
frm = ieee80211_add_rsn(frm, ic, ni);
if (ic->ic_flags & IEEE80211_F_QOS)
frm = ieee80211_add_edca_params(frm, ic);
- if (ic->ic_flags & IEEE80211_F_WPA1)
- frm = ieee80211_add_wpa1(frm, ic, ni);
+ if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+ (ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
+ frm = ieee80211_add_wpa(frm, ic, ni);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
m->m_pkthdr.rcvif = (void *)ni;
@@ -1499,16 +1517,53 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
} while (0)
/* unaligned little endian access */
-#define LE_WRITE_8(p, v) do { \
- (p)[7] = (v) >> 56; (p)[6] = (v) >> 48; \
+#define LE_WRITE_6(p, v) do { \
(p)[5] = (v) >> 40; (p)[4] = (v) >> 32; \
(p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \
(p)[1] = (v) >> 8; (p)[0] = (v); \
} while (0)
+/*
+ * Handle EAPOL-Key timeouts (no answer from supplicant).
+ */
+void
+ieee80211_eapol_timeout(void *arg)
+{
+ struct ieee80211_node *ni = arg;
+ struct ieee80211com *ic = ni->ni_ic;
+ int s;
+
+ IEEE80211_DPRINTF(("%s: no answer from station %s in state %d\n",
+ __func__, ether_sprintf(ni->ni_macaddr), ni->ni_rsn_state));
+
+ s = splnet();
+
+ switch (ni->ni_rsn_state) {
+ case RSNA_PTKSTART:
+ case RSNA_PTKCALCNEGOTIATING:
+ (void)ieee80211_send_4way_msg1(ic, ni);
+ break;
+ case RSNA_PTKINITNEGOTIATING:
+ (void)ieee80211_send_4way_msg3(ic, ni);
+ break;
+ }
+
+ switch (ni->ni_rsn_gstate) {
+ case RSNA_REKEYNEGOTIATING:
+ (void)ieee80211_send_group_msg1(ic, ni);
+ break;
+ }
+
+ splx(s);
+}
+
+/*
+ * Send an EAPOL-Key frame to node `ni'. If MIC or encryption is required,
+ * the PTK must be passed (otherwise it can be set to NULL.)
+ */
int
ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni)
+ struct ieee80211_node *ni, const struct ieee80211_ptk *ptk)
{
struct ifnet *ifp = &ic->ic_if;
struct ether_header *eh;
@@ -1519,6 +1574,7 @@ ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
if (m == NULL)
return ENOMEM;
+ /* no need to m_pullup here (ok by construction) */
eh = mtod(m, struct ether_header *);
eh->ether_type = htons(ETHERTYPE_PAE);
IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr);
@@ -1527,43 +1583,60 @@ ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
key = (struct ieee80211_eapol_key *)&eh[1];
key->version = EAPOL_VERSION;
key->type = EAPOL_KEY;
- key->desc = ni->ni_eapol_desc;
+ key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
+ EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA;
info = BE_READ_2(key->info);
- /* use V2 descriptor iff pairwise cipher is CCMP */
- info |= (ni->ni_pairwise_cipher != IEEE80211_CIPHER_CCMP) ?
- EAPOL_KEY_DESC_V1 : EAPOL_KEY_DESC_V2;
+ /* use V2 descriptor if pairwise or group cipher is CCMP */
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP)
+ info |= EAPOL_KEY_DESC_V2;
+ else
+ info |= EAPOL_KEY_DESC_V1;
BE_WRITE_2(key->info, info);
len = m->m_len - sizeof(struct ether_header);
BE_WRITE_2(key->paylen, len - sizeof(*key));
BE_WRITE_2(key->len, len - 4);
- if (info & EAPOL_KEY_ENCRYPTED)
- ieee80211_eapol_key_encrypt(ic, key, ni->ni_ptk.kek);
+ if (info & EAPOL_KEY_ENCRYPTED) {
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* clear "Encrypted" bit for WPA */
+ info &= ~EAPOL_KEY_ENCRYPTED;
+ BE_WRITE_2(key->info, info);
+ }
+ ieee80211_eapol_key_encrypt(ic, key, ptk->kek);
+ if ((info & EAPOL_KEY_VERSION_MASK) == EAPOL_KEY_DESC_V2) {
+ /* AES Key Wrap adds 8 bytes + padding */
+ m->m_pkthdr.len = m->m_len =
+ sizeof(*eh) + 4 + BE_READ_2(key->len);
+ }
+ }
if (info & EAPOL_KEY_KEYMIC)
- ieee80211_eapol_key_mic(key, ni->ni_ptk.kck);
+ ieee80211_eapol_key_mic(key, ptk->kck);
s = splnet();
+ /* start a 100ms timeout if an answer is expected from supplicant */
+ if (info & EAPOL_KEY_KEYACK)
+ timeout_add(&ni->ni_rsn_timeout, hz / 10);
IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
- if (error) {
- splx(s);
- return error;
+ if (error == 0) {
+ ifp->if_obytes += m->m_pkthdr.len;
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
}
- ifp->if_obytes += m->m_pkthdr.len;
- if ((ifp->if_flags & IFF_OACTIVE) == 0)
- (*ifp->if_start)(ifp);
splx(s);
- return 0;
+ return error;
}
/*
* Add a GTK KDE to an EAPOL-Key frame (see Figure 144).
*/
u_int8_t *
-ieee80211_add_gtk_kde(u_int8_t *frm, const struct ieee80211_key *k)
+ieee80211_add_gtk_kde(u_int8_t *frm, struct ieee80211_node *ni,
+ const struct ieee80211_key *k)
{
KASSERT(k->k_flags & IEEE80211_KEY_GROUP);
@@ -1572,7 +1645,11 @@ ieee80211_add_gtk_kde(u_int8_t *frm, const struct ieee80211_key *k)
memcpy(frm, IEEE80211_OUI, 3); frm += 3;
*frm++ = IEEE80211_KDE_GTK;
*frm = k->k_id & 3;
- if (k->k_flags & IEEE80211_KEY_TX)
+ /*
+ * The TxRx flag for sending a GTK is always the opposite of whether
+ * the pairwise key is used for data encryption/integrity or not.
+ */
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
*frm |= 1 << 2; /* set the Tx bit */
frm++;
*frm++ = 0; /* reserved */
@@ -1599,18 +1676,21 @@ ieee80211_get_eapol_key(int flags, int type, u_int pktlen)
{
struct mbuf *m;
- pktlen += sizeof(struct ether_header) +
+ /* reserve space for 802.11 encapsulation and EAPOL-Key header */
+ pktlen += sizeof(struct ieee80211_frame) + sizeof(struct llc) +
sizeof(struct ieee80211_eapol_key);
if (pktlen > MCLBYTES)
panic("EAPOL-Key frame too large: %u", pktlen);
MGETHDR(m, flags, type);
- if (m != NULL && pktlen > MHLEN) {
+ if (m == NULL)
+ return NULL;
+ if (pktlen >= MINCLSIZE) {
MCLGET(m, flags);
if (!(m->m_flags & M_EXT))
- m = m_free(m);
+ return m_free(m);
}
- m->m_data += sizeof(struct ether_header);
+ m->m_data += sizeof(struct ieee80211_frame) + sizeof(struct llc);
return m;
}
@@ -1624,15 +1704,17 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
struct ieee80211_eapol_key *key;
struct mbuf *m;
u_int16_t info, keylen;
- u_int8_t *pmkid;
u_int8_t *frm;
ni->ni_rsn_state = RSNA_PTKSTART;
- if (++ni->ni_rsn_tocnt == 3)
- return 0; /* XXX move to RSNA_DISCONNECT */
-
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_4WAY_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ? 2 + 20 : 0);
+ (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0);
if (m == NULL)
return ENOMEM;
key = mtod(m, struct ieee80211_eapol_key *);
@@ -1644,14 +1726,15 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
/* copy the authenticator's nonce (ANonce) */
memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
- keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
BE_WRITE_2(key->keylen, keylen);
frm = (u_int8_t *)&key[1];
- /* WPA1 does not have PMKID KDE */
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) {
+ /* WPA does not have PMKID KDE */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
+ ni->ni_rsnakms == IEEE80211_AKM_IEEE8021X) {
/* XXX retrieve PMKID from the PMKSA cache */
- frm = ieee80211_add_pmkid_kde(frm, pmkid);
+ /* frm = ieee80211_add_pmkid_kde(frm, pmkid); */
}
m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
@@ -1661,7 +1744,10 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
ic->ic_if.if_xname, 1, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ ni->ni_replaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ return ieee80211_send_eapol_key(ic, m, ni, NULL);
}
/*
@@ -1670,7 +1756,7 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
*/
int
ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
- const u_int8_t *snonce)
+ const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk)
{
struct ieee80211_eapol_key *key;
struct mbuf *m;
@@ -1687,19 +1773,19 @@ ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
BE_WRITE_2(key->info, info);
- /* copy key replay counter from authenticator */
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+ /* copy key replay counter from Message 1/4 */
+ memcpy(key->replaycnt, replaycnt, 8);
/* copy the supplicant's nonce (SNonce) */
- memcpy(key->nonce, snonce, EAPOL_KEY_NONCE_LEN);
+ memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
frm = (u_int8_t *)&key[1];
/* add the WPA/RSN IE used in the (Re)Association Request */
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
u_int16_t keylen;
- frm = ieee80211_add_wpa1(frm, ic, ni);
- /* WPA1 sets the key length field here */
- keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
+ frm = ieee80211_add_wpa(frm, ic, ni);
+ /* WPA sets the key length field here */
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
BE_WRITE_2(key->keylen, keylen);
} else /* RSN */
frm = ieee80211_add_rsn(frm, ic, ni);
@@ -1711,7 +1797,7 @@ ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
ic->ic_if.if_xname, 2, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, tptk);
}
/*
@@ -1722,45 +1808,54 @@ int
ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
{
struct ieee80211_eapol_key *key;
- struct ieee80211_key *gtk;
+ struct ieee80211_key *k;
struct mbuf *m;
u_int16_t info, keylen;
u_int8_t *frm;
ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
- if (++ni->ni_rsn_tocnt == 3)
- return 0; /* XXX move to RSNA_KEYERROR */
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_4WAY_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN)
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
2 + 48 +
- ((ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ?
- 2 + 6 + gtk->k_len : 0) +
+ ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
+ 2 + 6 + k->k_len : 0) +
8);
if (m == NULL)
return ENOMEM;
key = mtod(m, struct ieee80211_eapol_key *);
memset(key, 0, sizeof(*key));
- info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_INSTALL | EAPOL_KEY_KEYACK |
- EAPOL_KEY_KEYMIC;
+ info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC;
+ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
+ info |= EAPOL_KEY_INSTALL;
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
/* use same nonce as in Message 1 */
memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
- keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
+ ni->ni_replaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
BE_WRITE_2(key->keylen, keylen);
frm = (u_int8_t *)&key[1];
/* add the WPA/RSN IE included in Beacon/Probe Response */
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) {
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
- /* RSN: encapsulate the GTK and ask for encryption */
- frm = ieee80211_add_gtk_kde(frm, gtk);
- LE_WRITE_8(key->rsc, gtk->k_rsc);
+ /* encapsulate the GTK and ask for encryption */
+ frm = ieee80211_add_gtk_kde(frm, ni, k);
+ LE_WRITE_6(key->rsc, k->k_tsc);
info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE;
- } else /* WPA1 */
- frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
+ } else /* WPA */
+ frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);
/* write the key info field */
BE_WRITE_2(key->info, info);
@@ -1772,7 +1867,7 @@ ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
ic->ic_if.if_xname, 3, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
@@ -1797,10 +1892,10 @@ ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
/* copy key replay counter from authenticator */
BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
u_int16_t keylen;
- /* WPA1 sets the key length field here */
- keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
+ /* WPA sets the key length field here */
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
BE_WRITE_2(key->keylen, keylen);
} else
info |= EAPOL_KEY_SECURE;
@@ -1816,7 +1911,7 @@ ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
ic->ic_if.if_xname, 4, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
@@ -1827,14 +1922,23 @@ int
ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
{
struct ieee80211_eapol_key *key;
- struct ieee80211_key *gtk;
+ const struct ieee80211_key *k;
struct mbuf *m;
u_int16_t info;
u_int8_t *frm;
+ ni->ni_rsn_gstate = RSNA_REKEYNEGOTIATING;
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_GROUP_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
+
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- ((ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) ?
- gtk->k_len : 2 + 6 + gtk->k_len) +
+ ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
+ k->k_len : 2 + 6 + k->k_len) +
8);
if (m == NULL)
return ENOMEM;
@@ -1844,26 +1948,23 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE |
EAPOL_KEY_ENCRYPTED;
+ ni->ni_replaycnt++;
BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-#if 0
- /* use global counter as GNonce */
- ieee80211_derive_gtk(ic->ic_gmk, IEEE80211_PMK_LEN, ic->ic_myaddr,
- ic->ic_globalcnt, &gtk, sizeof gtk);
- /* XXX increment global counter */
-#endif
+
frm = (u_int8_t *)&key[1];
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
- /* WPA1 does not have GTK KDE */
- BE_WRITE_2(key->keylen, gtk->k_len);
- memcpy(frm, gtk->k_key, gtk->k_len);
- frm += gtk->k_len;
- info |= gtk->k_id << EAPOL_KEY_WPA_KID_SHIFT;
- if (gtk->k_flags & IEEE80211_KEY_TX)
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* WPA does not have GTK KDE */
+ BE_WRITE_2(key->keylen, k->k_len);
+ memcpy(frm, k->k_key, k->k_len);
+ frm += k->k_len;
+ info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT;
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
info |= EAPOL_KEY_WPA_TX;
} else /* RSN */
- frm = ieee80211_add_gtk_kde(frm, gtk);
+ frm = ieee80211_add_gtk_kde(frm, ni, k);
- LE_WRITE_8(key->rsc, gtk->k_rsc);
+ /* RSC = last transmit sequence number for the GTK */
+ LE_WRITE_6(key->rsc, k->k_tsc);
/* write the key info field */
BE_WRITE_2(key->info, info);
@@ -1875,7 +1976,7 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
ic->ic_if.if_xname, 1, 2, "group key",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
@@ -1884,7 +1985,7 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
*/
int
ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
- const struct ieee80211_key *gtk)
+ const struct ieee80211_key *k)
{
struct ieee80211_eapol_key *key;
u_int16_t info;
@@ -1901,10 +2002,10 @@ ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
/* copy key replay counter from authenticator */
BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
- if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
- /* WPA1 sets the key length and key id fields here */
- BE_WRITE_2(key->keylen, gtk->k_len);
- info |= (gtk->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT;
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* WPA sets the key length and key id fields here */
+ BE_WRITE_2(key->keylen, k->k_len);
+ info |= (k->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT;
}
/* write the key info field */
@@ -1918,13 +2019,13 @@ ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
ic->ic_if.if_xname, 2, 2, "group key",
ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
* EAPOL-Key Request frames are sent by the supplicant to request that the
- * authenticator initiate either a 4-Way Handshake or Group Key Handshake
- * and to report a MIC failure in a TKIP MSDU.
+ * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
+ * or to report a MIC failure in a TKIP MSDU.
*/
int
ieee80211_send_eapol_key_req(struct ieee80211com *ic,
@@ -1939,21 +2040,22 @@ ieee80211_send_eapol_key_req(struct ieee80211com *ic,
key = mtod(m, struct ieee80211_eapol_key *);
memset(key, 0, sizeof(*key));
+ info |= EAPOL_KEY_REQUEST;
BE_WRITE_2(key->info, info);
/* in case of TKIP MIC failure, fill the RSC field */
if (info & EAPOL_KEY_ERROR)
- LE_WRITE_8(key->rsc, tsc);
+ LE_WRITE_6(key->rsc, tsc);
/* use our separate key replay counter for key requests */
- BE_WRITE_8(key->replaycnt, ic->ic_keyreplaycnt);
- ic->ic_keyreplaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_reqreplaycnt);
+ ni->ni_reqreplaycnt++;
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: sending EAPOL-Key request to %s\n",
ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
- return ieee80211_send_eapol_key(ic, m, ni);
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
void
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 17e8d60e85d..b77d2477289 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1,9 +1,10 @@
-/* $OpenBSD: ieee80211_proto.c,v 1.21 2007/10/08 17:31:24 mglocker Exp $ */
+/* $OpenBSD: ieee80211_proto.c,v 1.22 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Damien Bergamini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,6 +64,8 @@
#include <net80211/ieee80211_var.h>
+#include <dev/rndvar.h>
+
const char * const ieee80211_mgt_subtype_name[] = {
"assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
"probe_req", "probe_resp", "reserved#6", "reserved#7",
@@ -356,6 +359,77 @@ ieee80211_set_shortslottime(struct ieee80211com *ic, int on)
ic->ic_updateslot(ic);
}
+/*
+ * Initiate a group key handshake with a node.
+ */
+static void
+ieee80211_node_gtk_rekey(void *arg, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = arg;
+
+ if (ni->ni_state != IEEE80211_STA_ASSOC ||
+ ni->ni_rsn_gstate != RSNA_IDLE)
+ return;
+
+ /* initiate a group key handshake with STA */
+ if (ieee80211_send_group_msg1(ic, ni) == 0) {
+ ni->ni_flags |= IEEE80211_NODE_REKEY;
+ ic->ic_rsn_keydonesta++;
+ }
+}
+
+/*
+ * This function is called in HostAP mode when the group key needs to be
+ * changed.
+ */
+void
+ieee80211_setkeys(struct ieee80211com *ic)
+{
+ u_int8_t gtk[IEEE80211_PMK_LEN];
+ u_int8_t kid;
+
+ /* Swap(GM, GN) */
+ kid = (ic->ic_def_txkey == 1) ? 2 : 1;
+
+ arc4random_bytes(gtk, sizeof(gtk));
+ ieee80211_map_gtk(gtk, ic->ic_bss->ni_rsngroupcipher, kid, 1, 0,
+ &ic->ic_nw_keys[kid]);
+
+ ic->ic_rsn_keydonesta = 0;
+ ieee80211_iterate_nodes(ic, ieee80211_node_gtk_rekey, ic);
+}
+
+/*
+ * The group key handshake has been completed with all associated stations.
+ */
+void
+ieee80211_setkeysdone(struct ieee80211com *ic)
+{
+ u_int8_t kid;
+
+ /* install GTK */
+ kid = (ic->ic_def_txkey == 1) ? 2 : 1;
+ if ((*ic->ic_set_key)(ic, ic->ic_bss, &ic->ic_nw_keys[kid]) == 0)
+ ic->ic_def_txkey = kid;
+}
+
+/*
+ * Group key lifetime has expired, update it.
+ */
+void
+ieee80211_gtk_rekey_timeout(void *arg)
+{
+ struct ieee80211com *ic = arg;
+ int s;
+
+ s = splnet();
+ ieee80211_setkeys(ic);
+ splx(s);
+
+ /* re-schedule a GTK rekeying after 3600s */
+ timeout_add(&ic->ic_rsn_timeout, 3600 * hz);
+}
+
int
ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
int mgt)
@@ -422,13 +496,11 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
/* FALLTHROUGH */
case IEEE80211_S_AUTH:
case IEEE80211_S_SCAN:
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ timeout_del(&ic->ic_rsn_timeout);
ic->ic_mgt_timer = 0;
IF_PURGE(&ic->ic_mgtq);
IF_PURGE(&ic->ic_pwrsaveq);
- if (ic->ic_wep_ctx != NULL) {
- free(ic->ic_wep_ctx, M_DEVBUF);
- ic->ic_wep_ctx = NULL;
- }
ieee80211_free_allnodes(ic);
break;
}
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index fd43c0c49a3..e3fb831dfb8 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.27 2007/08/23 16:59:32 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.28 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -76,10 +76,13 @@ extern struct mbuf *ieee80211_get_cts_to_self(struct ieee80211com *,
u_int16_t);
extern struct mbuf *ieee80211_beacon_alloc(struct ieee80211com *,
struct ieee80211_node *);
+extern int ieee80211_save_ie(const u_int8_t *, u_int8_t **);
+extern void ieee80211_eapol_timeout(void *);
extern int ieee80211_send_4way_msg1(struct ieee80211com *,
struct ieee80211_node *);
extern int ieee80211_send_4way_msg2(struct ieee80211com *,
- struct ieee80211_node *, const u_int8_t *);
+ struct ieee80211_node *, const u_int8_t *,
+ const struct ieee80211_ptk *);
extern int ieee80211_send_4way_msg3(struct ieee80211com *,
struct ieee80211_node *);
extern int ieee80211_send_4way_msg4(struct ieee80211com *,
@@ -113,7 +116,7 @@ extern u_int8_t *ieee80211_add_qos_capability(u_int8_t *,
struct ieee80211com *);
extern u_int8_t *ieee80211_add_rsn(u_int8_t *, struct ieee80211com *,
const struct ieee80211_node *);
-extern u_int8_t *ieee80211_add_wpa1(u_int8_t *, struct ieee80211com *,
+extern u_int8_t *ieee80211_add_wpa(u_int8_t *, struct ieee80211com *,
const struct ieee80211_node *);
extern u_int8_t *ieee80211_add_xrates(u_int8_t *,
const struct ieee80211_rateset *);
@@ -131,5 +134,8 @@ extern void ieee80211_eapol_key_encrypt(struct ieee80211com *,
struct ieee80211_eapol_key *, const u_int8_t *);
extern int ieee80211_eapol_key_decrypt(struct ieee80211_eapol_key *,
const u_int8_t *);
+extern void ieee80211_gtk_rekey_timeout(void *);
+extern void ieee80211_setkeys(struct ieee80211com *);
+extern void ieee80211_setkeysdone(struct ieee80211com *);
#endif /* _NET80211_IEEE80211_PROTO_H_ */
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 17d856f3797..973afb5005f 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_var.h,v 1.37 2007/11/17 14:05:01 damien Exp $ */
+/* $OpenBSD: ieee80211_var.h,v 1.38 2008/04/16 18:32:15 damien Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
/*-
@@ -37,6 +37,8 @@
* Definitions for IEEE 802.11 drivers.
*/
+#include <sys/timeout.h>
+
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h> /* for ieee80211_stats */
@@ -143,6 +145,19 @@ struct ieee80211_edca_ac_params {
u_int8_t ac_acm;
};
+#define IEEE80211_PROTO_NONE 0
+#define IEEE80211_PROTO_RSN (1 << 0)
+#define IEEE80211_PROTO_WPA (1 << 1)
+
+struct ieee80211_rsnparams {
+ u_int16_t rsn_nakms;
+ u_int32_t rsn_akms;
+ u_int16_t rsn_nciphers;
+ u_int32_t rsn_ciphers;
+ enum ieee80211_cipher rsn_groupcipher;
+ u_int16_t rsn_caps;
+};
+
#define IEEE80211_PS_SLEEP 0x1 /* STA is in power saving mode */
#define IEEE80211_PS_MAX_QUEUE 50 /* maximum saved packets */
@@ -171,9 +186,10 @@ struct ieee80211com {
void (*ic_set_tim)(struct ieee80211com *, int, int);
int (*ic_set_key)(struct ieee80211com *,
struct ieee80211_node *,
- const struct ieee80211_key *);
+ struct ieee80211_key *);
void (*ic_delete_key)(struct ieee80211com *,
- struct ieee80211_node *, int);
+ struct ieee80211_node *,
+ struct ieee80211_key *);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
@@ -223,6 +239,7 @@ struct ieee80211com {
u_int16_t ic_bmisstimeout;/* beacon miss threshold (ms) */
u_int16_t ic_nonerpsta; /* # non-ERP stations */
u_int16_t ic_longslotsta; /* # long slot time stations */
+ u_int16_t ic_rsnsta; /* # RSN stations */
int ic_mgt_timer; /* mgmt timeout */
int ic_inact_timer; /* inactivity timer wait */
int ic_des_esslen;
@@ -230,8 +247,8 @@ struct ieee80211com {
struct ieee80211_channel *ic_des_chan; /* desired channel */
u_int8_t ic_des_bssid[IEEE80211_ADDR_LEN];
struct ieee80211_key ic_nw_keys[IEEE80211_WEP_NKID];
- int ic_wep_txkey; /* default tx key index */
- void *ic_wep_ctx; /* wep crypt context */
+ int ic_def_txkey; /* default tx key index */
+#define ic_wep_txkey ic_def_txkey
u_int32_t ic_iv; /* initial vector for wep */
struct ieee80211_stats ic_stats; /* statistics */
struct timeval ic_last_merge_print; /* for rate-limiting
@@ -240,8 +257,16 @@ struct ieee80211com {
struct ieee80211_edca_ac_params ic_edca_ac[EDCA_NUM_AC];
u_int ic_edca_updtcount;
u_int8_t ic_globalcnt[EAPOL_KEY_NONCE_LEN];
- u_int64_t ic_keyreplaycnt;
+ u_int8_t ic_nonce[EAPOL_KEY_NONCE_LEN];
u_int8_t ic_psk[IEEE80211_PMK_LEN];
+ struct timeout ic_rsn_timeout;
+ u_int16_t ic_rsn_keydonesta;
+ int ic_tkip_micfail;
+
+ u_int ic_rsnprotos;
+ u_int ic_rsnakms;
+ u_int ic_rsnciphers;
+ enum ieee80211_cipher ic_rsngroupcipher;
u_int8_t *ic_tim_bitmap;
u_int ic_tim_len;
@@ -276,8 +301,9 @@ extern struct ieee80211com_head ieee80211com_head;
#define IEEE80211_F_SHPREAMBLE 0x00040000 /* STATUS: short preamble */
#define IEEE80211_F_QOS 0x00080000 /* CONF: QoS enabled */
#define IEEE80211_F_USEPROT 0x00100000 /* STATUS: protection enabled */
-#define IEEE80211_F_RSN 0x00200000 /* CONF: RSN enabled */
-#define IEEE80211_F_WPA1 0x00400000 /* CONF: WPA1 enabled */
+#define IEEE80211_F_RSNON 0x00200000 /* CONF: RSN enabled */
+#define IEEE80211_F_PSK 0x00400000 /* CONF: pre-shared key set */
+#define IEEE80211_F_COUNTERM 0x00800000 /* STATUS: countermeasures */
#define IEEE80211_F_USERMASK 0xf0000000 /* CONF: ioctl flag mask */
/* ic_caps */