diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2009-01-26 19:09:42 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2009-01-26 19:09:42 +0000 |
commit | f5bde2a8b2c137a3c51797048f76f625179c249b (patch) | |
tree | e7ada894dc97c72e04d71f1fca20fee90e8dc80b /sys/net80211/ieee80211_proto.c | |
parent | ba892d095172c6f93edba4a0a5af1c2f8754d770 (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.c | 139 |
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, |