summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_proto.c
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2009-01-26 19:09:42 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2009-01-26 19:09:42 +0000
commitf5bde2a8b2c137a3c51797048f76f625179c249b (patch)
treee7ada894dc97c72e04d71f1fca20fee90e8dc80b /sys/net80211/ieee80211_proto.c
parentba892d095172c6f93edba4a0a5af1c2f8754d770 (diff)
Add some initial HT bits (not enabled yet) based on 802.11n Draft 7.01:
- implement A-MPDU frames buffering and reordering - implement A-MSDU decapsulation - process/send ADDBA Request, ADDBA Response and DELBA action frames - process Block Ack Request control frames (including MTBAR) - implement PBAC support (Protected Block Ack) - add some incomplete HT Capabilities and HT Operation IEs parsing Add more Management Frame Protection bits based on 802.11w Draft 7.0: - implement SA Query procedure (both AP and STA) - cleanup BIP Fix some bugs: - fix check for WEP key length that otherwise caused a stack smash in ieee80211_wep_encrypt (pointed out by Xavier Santolaria on macppc) - properly stop EAPOL timeout: fixes a panic that occured in HostAP mode when turning the interface down while a 4-way handshake is in progress (pointed out by Doughertys) Did some code cleanup too. The HT bits are currently not compiled in (IEEE80211_NO_HT is defined) because they won't be ready until after the next release and I didn't want to grow the kernel or to inadvertently introduce new bugs. They are here such that other people can look at the code. Notice that I had to add an extra parameter to ic_send_mgmt() for action frames, that is why there are small changes in drivers defining their own ic_send_mgmt() handler. Sorry for the not very incremental diff but this has been sitting in my tree for too long now.
Diffstat (limited to 'sys/net80211/ieee80211_proto.c')
-rw-r--r--sys/net80211/ieee80211_proto.c139
1 files changed, 137 insertions, 2 deletions
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index c79455e450c..b1eb2f5dcbe 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: ieee80211_proto.c,v 1.37 2008/10/15 19:12:18 blambert Exp $ */
+/* $OpenBSD: ieee80211_proto.c,v 1.38 2009/01/26 19:09:41 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
+ * Copyright (c) 2008, 2009 Damien Bergamini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -511,8 +511,143 @@ ieee80211_gtk_rekey_timeout(void *arg)
/* re-schedule a GTK rekeying after 3600s */
timeout_add_sec(&ic->ic_rsn_timeout, 3600);
}
+
+void
+ieee80211_sa_query_timeout(void *arg)
+{
+ struct ieee80211_node *ni = arg;
+ struct ieee80211com *ic = ni->ni_ic;
+ int s;
+
+ s = splnet();
+ if (++ni->ni_sa_query_count >= 3) {
+ ni->ni_flags &= ~IEEE80211_NODE_SA_QUERY;
+ ni->ni_flags |= IEEE80211_NODE_SA_QUERY_FAILED;
+ } else /* retry SA Query Request */
+ ieee80211_sa_query_request(ic, ni);
+ splx(s);
+}
+
+/*
+ * Request that a SA Query Request frame be sent to a specified peer STA
+ * to which the STA is associated.
+ */
+void
+ieee80211_sa_query_request(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ /* MLME-SAQuery.request */
+
+ if (!(ni->ni_flags & IEEE80211_NODE_SA_QUERY)) {
+ ni->ni_flags |= IEEE80211_NODE_SA_QUERY;
+ ni->ni_flags &= ~IEEE80211_NODE_SA_QUERY_FAILED;
+ ni->ni_sa_query_count = 0;
+ }
+ /* generate random Transaction Identifier */
+ arc4random_buf(ni->ni_sa_query_trid, 16);
+
+ /* send SA Query Request */
+ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_SA_QUERY,
+ IEEE80211_ACTION_SA_QUERY_REQ, 0);
+ timeout_add_msec(&ni->ni_sa_query_to, 10);
+}
#endif /* IEEE80211_STA_ONLY */
+#ifndef IEEE80211_NO_HT
+void
+ieee80211_ba_timeout(void *arg)
+{
+ struct ieee80211_ba *ba = arg;
+ struct ieee80211_node *ni = ba->ba_ni;
+ struct ieee80211com *ic = ni->ni_ic;
+ u_int8_t tid;
+ int s;
+
+ s = splnet();
+ if (ba->ba_state == IEEE80211_BA_REQUESTED) {
+ /* MLME-ADDBA.confirm(TIMEOUT) */
+ ba->ba_state = IEEE80211_BA_INIT;
+ free(ba->ba_buf, M_DEVBUF);
+ ba->ba_buf = NULL;
+
+ } else if (ba->ba_state == IEEE80211_BA_AGREED) {
+ /* Block Ack inactivity timeout */
+ tid = ((caddr_t)ba - (caddr_t)ni->ni_ba) / sizeof(*ba);
+ ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, tid);
+ }
+ splx(s);
+}
+
+/*
+ * Request initiation of Block Ack with the specified peer.
+ */
+int
+ieee80211_addba_request(struct ieee80211com *ic, struct ieee80211_node *ni,
+ u_int16_t ssn, u_int8_t tid)
+{
+ struct ieee80211_ba *ba = &ni->ni_ba[tid];
+
+ /* MLME-ADDBA.request */
+
+ /* setup Block Ack */
+ ba->ba_state = IEEE80211_BA_REQUESTED;
+ ba->ba_token = ic->ic_dialog_token++;
+ ba->ba_timeout_val = IEEE80211_BA_MAX_TIMEOUT;
+ timeout_set(&ba->ba_to, ieee80211_ba_timeout, ba);
+ ba->ba_winsize = IEEE80211_BA_MAX_WINSZ;
+ ba->ba_winstart = ssn;
+ ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
+ /* allocate and setup our reordering buffer */
+ ba->ba_buf = malloc(IEEE80211_BA_MAX_WINSZ * sizeof(*ba->ba_buf),
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ba->ba_buf == NULL)
+ return ENOMEM;
+ ba->ba_head = 0;
+
+ timeout_add_sec(&ba->ba_to, 1); /* dot11ADDBAResponseTimeout */
+ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA,
+ IEEE80211_ACTION_ADDBA_REQ, tid);
+ return 0;
+}
+
+/*
+ * Request the deletion of Block Ack with a peer.
+ */
+void
+ieee80211_delba_request(struct ieee80211com *ic, struct ieee80211_node *ni,
+ u_int16_t reason, u_int8_t tid)
+{
+ struct ieee80211_ba *ba = &ni->ni_ba[tid];
+ int i;
+
+ /* MLME-DELBA.request */
+
+ /* transmit a DELBA frame */
+ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA,
+ IEEE80211_ACTION_DELBA, reason << 16 | tid);
+ /*
+ * XXX We should wait for an acknowledgment of the DELBA frame but
+ * drivers are not necessarily notified when a frame is ACK'ed by
+ * hardware.
+ */
+ /* MLME-DELBA.confirm */
+ if (ic->ic_htimmba_stop != NULL)
+ ic->ic_htimmba_stop(ic, ni, tid);
+
+ ba->ba_state = IEEE80211_BA_INIT;
+ /* stop Block Ack inactivity timer */
+ timeout_del(&ba->ba_to);
+ if (ba->ba_buf != NULL) {
+ /* free all MSDUs stored in reordering buffer */
+ for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++)
+ if (ba->ba_buf[i].m != NULL)
+ m_freem(ba->ba_buf[i].m);
+ /* free reordering buffer */
+ free(ba->ba_buf, M_DEVBUF);
+ ba->ba_buf = NULL;
+ }
+}
+#endif /* !IEEE80211_NO_HT */
+
void
ieee80211_auth_open(struct ieee80211com *ic, const struct ieee80211_frame *wh,
struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, u_int16_t seq,