diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2006-06-18 18:39:42 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2006-06-18 18:39:42 +0000 |
commit | b6efe24e3cd0a45a2c3b9be9b804f53c1db0152e (patch) | |
tree | f509d197cf8f8687c2f10f508d445ddaaa8d9534 | |
parent | e6d4b8dbc6221983c325d69573f969a9b074cdc6 (diff) |
Improve 802.11b/g interoperability and move toward better compliance
with IEEE Std 802.11g-2003 standard:
- add ERP Information Element in probe responses and beacons
- keep track of the number of associated non-ERP STAs and non-short slot
time capable STAs in the BSS
- enable use of RTS/CTS or CTS-to-self protection when required by the BSS
- add a ic_updateslot() callback to notify drivers of slot time changes
- cleanup computation of mgmt frames sizes in ieee80211_output.c
- nuke unnecessary <sys/cdefs.h> includes
- remove an unused macro (LOGICALLY_EQUAL) while i'm here
From {free,net}bsd, with additional fixes.
ok brad@, reyk@
-rw-r--r-- | sys/net80211/ieee80211.c | 35 | ||||
-rw-r--r-- | sys/net80211/ieee80211_crypto.c | 4 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 88 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 151 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 125 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 58 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.h | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 10 |
9 files changed, 390 insertions, 91 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 677bac6f42e..2e1c684ec44 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.c,v 1.16 2006/01/04 06:04:42 canacar Exp $ */ +/* $OpenBSD: ieee80211.c,v 1.17 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ /*- @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - /* * IEEE 802.11 generic handler */ @@ -80,8 +78,6 @@ struct ieee80211com_head ieee80211com_head = static void ieee80211_setbasicrates(struct ieee80211com *); -#define LOGICALLY_EQUAL(x, y) (!(x) == !(y)) - #if 0 static const char *ieee80211_phymode_name[] = { "auto", /* IEEE80211_MODE_AUTO */ @@ -529,6 +525,12 @@ ieee80211_media_change(struct ifnet *ifp) ic->ic_flags |= IEEE80211_F_IBSSON; break; } + /* + * Yech, slot time may change depending on the + * operating mode so reset it to be sure everything + * is setup appropriately. + */ + ieee80211_reset_erp(ic); error = ENETRESET; } #ifdef notdef @@ -733,28 +735,9 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) */ ieee80211_reset_scan(ifp); - /* - * Set/reset state flags that influence beacon contents, etc. - * - * XXX what if we have stations already associated??? - * XXX probably not right for autoselect? - * - * Short preamble is not interoperable with legacy .11b - * equipment, so it should not be the default for b or - * mixed b/g networks. -dcy - */ -#if 0 - if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) - ic->ic_flags |= IEEE80211_F_SHPREAMBLE; -#endif - if (mode == IEEE80211_MODE_11G) { - if (ic->ic_caps & IEEE80211_C_SHSLOT) - ic->ic_flags |= IEEE80211_F_SHSLOT; - } else { - ic->ic_flags &= ~IEEE80211_F_SHSLOT; - } - ic->ic_curmode = mode; + ieee80211_reset_erp(ic); /* reset ERP state */ + return 0; #undef N } diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index b71ccc595c3..62a8f5c2a4c 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.c,v 1.7 2005/09/08 13:24:52 reyk Exp $ */ +/* $OpenBSD: ieee80211_crypto.c,v 1.8 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_crypto.c,v 1.5 2003/12/14 09:56:53 dyoung Exp $ */ /*- @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - #include "bpfilter.h" #include <sys/param.h> diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 53f5889af89..303df489c72 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,5 +1,5 @@ /* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */ -/* $OpenBSD: ieee80211_input.c,v 1.15 2006/03/25 22:41:48 djm Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.16 2006/06/18 18:39:41 damien Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - #include "bpfilter.h" #include <sys/param.h> @@ -1056,7 +1054,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ic->ic_stats.is_rx_chanmismatch++; return; } - /* * Use mac, channel and rssi so we collect only the * best potential AP with the equal bssid while scanning. @@ -1099,6 +1096,52 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, } else is_new = 0; + /* + * When operating in station mode, check for state updates + * while we're associated. We consider only 11g stuff right + * now. + */ + if (ic->ic_opmode == IEEE80211_M_STA && + ni->ni_associd != 0 && + (!(ic->ic_flags & IEEE80211_F_ASCAN) || + IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) { + /* record tsf of last beacon */ + ni->ni_rstamp = rstamp; + memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp)); + /* + * Check if protection mode has changed since last + * beacon. + */ + if (ni->ni_erp != erp) { + IEEE80211_DPRINTF(( + "[%s] erp change: was 0x%x, now 0x%x\n", + ether_sprintf(wh->i_addr2), ni->ni_erp, + erp)); + if (ic->ic_curmode == IEEE80211_MODE_11G && + (erp & IEEE80211_ERP_USE_PROTECTION)) + ic->ic_flags |= IEEE80211_F_USEPROT; + else + ic->ic_flags &= ~IEEE80211_F_USEPROT; + ni->ni_erp = erp; + } + + /* + * Check if AP short slot time setting has changed + * since last beacon and give the driver a chance to + * update the hardware. + */ + if ((ni->ni_capinfo ^ letoh16(*(u_int16_t *)capinfo)) & + IEEE80211_CAPINFO_SHORT_SLOTTIME) { + ieee80211_set_shortslottime(ic, + ic->ic_curmode == IEEE80211_MODE_11A || + (letoh16(*(u_int16_t *)capinfo) & + IEEE80211_CAPINFO_SHORT_SLOTTIME)); + ni->ni_capinfo = + letoh16(*(u_int16_t *)capinfo); + } + break; + } + if (ssid[1] != 0 && ni->ni_esslen == 0) { /* * Update ESSID at probe response to adopt hidden AP by @@ -1122,6 +1165,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, /* NB: must be after ni_chan is setup */ ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT); + /* * When scanning we record results (nodes) with a zero * refcnt. Otherwise we want to hold the reference for @@ -1145,9 +1189,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, case IEEE80211_FC0_SUBTYPE_PROBE_REQ: { u_int8_t rate; - if (ic->ic_opmode == IEEE80211_M_STA) - return; - if (ic->ic_state != IEEE80211_S_RUN) + if (ic->ic_opmode == IEEE80211_M_STA || + ic->ic_state != IEEE80211_S_RUN) return; /* @@ -1242,7 +1285,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, u_int16_t capinfo, bintval; if (ic->ic_opmode != IEEE80211_M_HOSTAP || - (ic->ic_state != IEEE80211_S_RUN)) + ic->ic_state != IEEE80211_S_RUN) return; if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { @@ -1409,9 +1452,32 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (ni->ni_rates.rs_nrates != 0) - ieee80211_new_state(ic, IEEE80211_S_RUN, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + if (ni->ni_rates.rs_nrates == 0) + break; + + /* + * Configure state now that we are associated. + */ + if (ic->ic_curmode == IEEE80211_MODE_11A || + (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) + ic->ic_flags |= IEEE80211_F_SHPREAMBLE; + else + ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; + + ieee80211_set_shortslottime(ic, + ic->ic_curmode == IEEE80211_MODE_11A || + (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); + /* + * Honor ERP protection. + */ + if (ic->ic_curmode == IEEE80211_MODE_11G && + (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) + ic->ic_flags |= IEEE80211_F_USEPROT; + else + ic->ic_flags &= ~IEEE80211_F_USEPROT; + + ieee80211_new_state(ic, IEEE80211_S_RUN, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); break; } diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 8fcaa58e027..0ffd31dcfac 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.c,v 1.14 2006/02/19 17:34:13 damien Exp $ */ +/* $OpenBSD: ieee80211_node.c,v 1.15 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - #include "bpfilter.h" #include "bridge.h" @@ -88,6 +86,10 @@ static struct ieee80211_node * ieee80211_alloc_node_helper(struct ieee80211com *); static void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *); +static void ieee80211_node_join_11g(struct ieee80211com *, + struct ieee80211_node *); +static void ieee80211_node_leave_11g(struct ieee80211com *, + struct ieee80211_node *); #define M_80211_NODE M_DEVBUF @@ -468,6 +470,15 @@ ieee80211_end_scan(struct ifnet *ifp) if (selbs == NULL) goto notfound; (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); + + /* + * 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); + ieee80211_reset_erp(ic); + ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); if (ic->ic_opmode == IEEE80211_M_IBSS) { ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE | @@ -907,6 +918,78 @@ ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, IEEE80211_NODE_UNLOCK(ic); } +/* + * Check if the specified node supports ERP. + */ +int +ieee80211_iserp_sta(struct ieee80211_node *ni) +{ +#define N(a) (sizeof (a) / sizeof (a)[0]) + static const uint8_t rates[] = { 2, 4, 11, 22, 12, 24, 48 }; + struct ieee80211_rateset *rs = &ni->ni_rates; + int i, j; + + /* + * A STA supports ERP operation if it includes all the Clause 19 + * mandatory rates in its supported rate set. + */ + for (i = 0; i < N(rates); i++) { + for (j = 0; j < rs->rs_nrates; j++) { + if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == rates[i]) + break; + } + if (j == rs->rs_nrates) + return 0; + } + return 1; +#undef N +} + +/* + * Handle a station joining an 11g network. + */ +static void +ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) { + /* + * Joining STA doesn't support short slot time. We must + * disable the use of short slot time for all other associated + * STAs and give the driver a chance to reconfigure the + * hardware. + */ + if (++ic->ic_longslotsta == 1) { + if (ic->ic_caps & IEEE80211_C_SHSLOT) + ieee80211_set_shortslottime(ic, 0); + } + IEEE80211_DPRINTF(("[%s] station needs long slot time, " + "count %d\n", ether_sprintf(ni->ni_macaddr), + ic->ic_longslotsta)); + } + + if (!ieee80211_iserp_sta(ni)) { + /* + * Joining STA is non-ERP. + */ + ic->ic_nonerpsta++; + + IEEE80211_DPRINTF(("[%s] station is non-ERP, %d non-ERP " + "stations associated\n", ether_sprintf(ni->ni_macaddr), + ic->ic_nonerpsta)); + + /* must enable the use of protection */ + if (ic->ic_protmode != IEEE80211_PROT_NONE) { + IEEE80211_DPRINTF(("%s: enable use of protection\n", + __func__)); + ic->ic_flags |= IEEE80211_F_USEPROT; + } + + if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) + ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; + } else + ni->ni_flags |= IEEE80211_NODE_ERP; +} + void ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) @@ -934,8 +1017,8 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, ni->ni_associd = aid | 0xc000; IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); newassoc = 1; - /* XXX for 11g must turn off short slot time if long - slot time sta associates */ + if (ic->ic_curmode == IEEE80211_MODE_11G) + ieee80211_node_join_11g(ic, ni); } else newassoc = 0; @@ -962,6 +1045,59 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, } /* + * Handle a station leaving an 11g network. + */ +static void +ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) { +#ifdef DIAGNOSTIC + if (ic->ic_longslotsta == 0) { + panic("bogus long slot station count %d", + ic->ic_longslotsta); + } +#endif + /* leaving STA did not support short slot time */ + if (--ic->ic_longslotsta == 0) { + /* + * All associated STAs now support short slot time, so + * enable this feature and give the driver a chance to + * reconfigure the hardware. Notice that IBSS always + * use a long slot time. + */ + if ((ic->ic_caps & IEEE80211_C_SHSLOT) && + ic->ic_opmode != IEEE80211_M_IBSS) + ieee80211_set_shortslottime(ic, 1); + } + IEEE80211_DPRINTF(("[%s] long slot time station leaves, " + "count now %d\n", ether_sprintf(ni->ni_macaddr), + ic->ic_longsta)); + } + + if (!(ni->ni_flags & IEEE80211_NODE_ERP)) { +#ifdef DIAGNOSTIC + if (ic->ic_nonerpsta == 0) { + panic("bogus non-ERP station count %d\n", + ic->ic_nonerpsta); + } +#endif + /* leaving STA was non-ERP */ + if (--ic->ic_nonerpsta == 0) { + /* + * All associated STAs are now ERP capable, disable use + * of protection and re-enable short preamble support. + */ + ic->ic_flags &= ~IEEE80211_F_USEPROT; + if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) + ic->ic_flags |= IEEE80211_F_SHPREAMBLE; + } + IEEE80211_DPRINTF(("[%s] non-ERP station leaves, " + "count now %d\n", ether_sprintf(ni->ni_macaddr), + ic->ic_nonerpsta)); + } +} + +/* * Handle bookkeeping for station deauthentication/disassociation * when operating as an ap. */ @@ -978,6 +1114,10 @@ ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) return; IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); ni->ni_associd = 0; + + if (ic->ic_curmode == IEEE80211_MODE_11G) + ieee80211_node_leave_11g(ic, ni); + ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT); #if NBRIDGE > 0 @@ -1004,4 +1144,3 @@ ieee80211_node_cmp(struct ieee80211_node *b1, struct ieee80211_node *b2) * Generate red-black tree function logic */ RB_GENERATE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp); - diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 2a4828cefb2..325225a8528 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.8 2005/09/13 12:11:03 reyk Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.9 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -122,6 +122,8 @@ struct ieee80211_node { int ni_txrate; /* index to ni_rates[] */ int ni_state; u_int32_t *ni_challenge; /* shared-key challenge */ + u_int8_t ni_flags; /* special-purpose state */ +#define IEEE80211_NODE_ERP 0x01 }; RB_HEAD(ieee80211_tree, ieee80211_node); @@ -202,6 +204,7 @@ typedef void ieee80211_iter_func(void *, struct ieee80211_node *); extern void ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *, void *); extern void ieee80211_clean_nodes(struct ieee80211com *); +extern int ieee80211_iserp_sta(struct ieee80211_node *); extern void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *, int); diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 55aadc60b1e..a5e86e1ce11 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_output.c,v 1.19 2006/05/21 07:47:26 damien Exp $ */ +/* $OpenBSD: ieee80211_output.c,v 1.20 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ /*- @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - #include "bpfilter.h" #include <sys/param.h> @@ -65,7 +63,7 @@ /* * IEEE 802.11 output routine. Normally this will directly call the * Ethernet output routine because 802.11 encapsulation is called - * later by the driver. This function could be used to send raw frames + * later by the driver. This function can be used to send raw frames * if the mbuf has been tagged with a 802.11 data link type. */ int @@ -551,6 +549,41 @@ ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) return frm + len; } +/* + * Add an ERP element to a frame. + */ +u_int8_t * +ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic) +{ + u_int8_t erp; + + *frm++ = IEEE80211_ELEMID_ERP; + *frm++ = 1; + erp = 0; + /* + * The NonERP_Present bit shall be set to 1 when a NonERP STA + * is associated with the BSS. + */ + if (ic->ic_nonerpsta != 0) + erp |= IEEE80211_ERP_NON_ERP_PRESENT; + /* + * If one or more NonERP STAs are associated in the BSS, the + * Use_Protection bit shall be set to 1 in transmitted ERP + * Information Elements. + */ + if (ic->ic_flags & IEEE80211_F_USEPROT) + erp |= IEEE80211_ERP_USE_PROTECTION; + /* + * The Barker_Preamble_Mode bit shall be set to 1 by the ERP + * Information Element sender if one or more associated NonERP + * STAs are not short preamble capable. + */ + if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + erp |= IEEE80211_ERP_BARKER_MODE; + *frm++ = erp; + return frm; +} + static struct mbuf * ieee80211_getmbuf(int flags, int type, u_int pktlen) { @@ -603,7 +636,8 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, - 2 + ic->ic_des_esslen + 2 + IEEE80211_RATE_SIZE + + 2 + ic->ic_des_esslen + + 2 + IEEE80211_RATE_SIZE + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); @@ -629,12 +663,18 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) + * [tlv] extended rate phy (ERP) * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, - 8 + 2 + 2 + 2 + 2 + ni->ni_esslen + - 2 + IEEE80211_RATE_SIZE + - (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3) + 6 + + 8 + /* time stamp */ + 2 + /* beacon interval */ + 2 + /* cabability information */ + 2 + ni->ni_esslen + /* ssid */ + 2 + IEEE80211_RATE_SIZE + /* supported rates */ + 7 + /* parameter set (FH/DS) */ + 6 + /* parameter set (IBSS) */ + 2 + 1 + /* extended rate phy (ERP) */ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); @@ -654,6 +694,8 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHSLOT) + capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; @@ -690,6 +732,8 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, *frm++ = 0; /* bitmap control */ *frm++ = 0; /* Partial Virtual Bitmap (variable) */ } + if (ic->ic_curmode == IEEE80211_MODE_11G) + frm = ieee80211_add_erp(frm, ic); frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); break; @@ -763,10 +807,12 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, - sizeof(capinfo) + sizeof(u_int16_t) + - IEEE80211_ADDR_LEN + 2 + ni->ni_esslen + - 2 + IEEE80211_RATE_SIZE + 2 + - (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); + 2 + /* capability information */ + 2 + /* listen interval */ + IEEE80211_ADDR_LEN + /* current AP address */ + 2 + ni->ni_esslen + /* ssid */ + 2 + IEEE80211_RATE_SIZE + /* supported rates */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); m->m_data += sizeof(struct ieee80211_frame); @@ -786,7 +832,8 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; - if (ic->ic_flags & IEEE80211_F_SHSLOT) + if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) && + (ic->ic_flags & IEEE80211_F_SHSLOT)) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; @@ -818,8 +865,10 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, * [tlv] extended supported rates */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, - sizeof(capinfo) + sizeof(u_int16_t) + - sizeof(u_int16_t) + 2 + IEEE80211_RATE_SIZE + + 2 + /* capability information */ + 2 + /* status */ + 2 + /* association ID */ + 2 + IEEE80211_RATE_SIZE + /* supported rates */ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); @@ -832,6 +881,8 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHSLOT) + capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; *(u_int16_t *)frm = htole16(capinfo); frm += 2; @@ -883,18 +934,31 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni) { struct ieee80211_frame *wh; struct mbuf *m; - int pktlen; u_int8_t *frm; u_int16_t capinfo; struct ieee80211_rateset *rs; - rs = &ni->ni_rates; - pktlen = sizeof (struct ieee80211_frame) - + 8 + 2 + 2 + 2+ni->ni_esslen + 2+rs->rs_nrates + 3 + 6; - if (rs->rs_nrates > IEEE80211_RATE_SIZE) - pktlen += 2; + /* + * beacon frame format + * [8] time stamp + * [2] beacon interval + * [2] cabability information + * [tlv] ssid + * [tlv] supported rates + * [3] parameter set (DS) + * [tlv] parameter set (IBSS/TIM) + * [tlv] extended rate phy (ERP) + * [tlv] extended supported rates + */ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, - 2 + ni->ni_esslen + 2 + IEEE80211_RATE_SIZE + + 8 + /* time stamp */ + 2 + /* beacon interval */ + 2 + /* cabability information */ + 2 + ni->ni_esslen + /* ssid */ + 2 + IEEE80211_RATE_SIZE + /* supported rates */ + 2 + 1 + /* parameter set (DS) */ + 6 + /* parameter set (IBSS/TIM) */ + 2 + 1 + /* extended rate phy (ERP) */ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); if (m == NULL) return NULL; @@ -909,16 +973,6 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni) IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); *(u_int16_t *)wh->i_seq = 0; - /* - * beacon frame format - * [8] time stamp - * [2] beacon interval - * [2] cabability information - * [tlv] ssid - * [tlv] supported rates - * [tlv] parameter set (IBSS) - * [tlv] extended supported rates - */ frm = (u_int8_t *)&wh[1]; bzero(frm, 8); /* timestamp is set by hardware */ frm += 8; @@ -939,6 +993,7 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni) *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); + rs = &ni->ni_rates; frm = ieee80211_add_rates(frm, rs); *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; @@ -956,12 +1011,12 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni) *frm++ = 0; /* bitmap control */ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ } + if (ic->ic_curmode == IEEE80211_MODE_11G) + frm = ieee80211_add_erp(frm, ic); frm = ieee80211_add_xrates(frm, rs); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); m->m_pkthdr.rcvif = (void *)ni; - if (m->m_pkthdr.len > pktlen) - panic("beacon bigger than expected, len %u calculated %u", - m->m_pkthdr.len, pktlen); + return m; } diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 6417049fc5b..a25e148f604 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.c,v 1.9 2005/09/13 12:11:03 reyk Exp $ */ +/* $OpenBSD: ieee80211_proto.c,v 1.10 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- @@ -33,8 +33,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - /* * IEEE 802.11 protocol support. */ @@ -305,6 +303,51 @@ ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, #undef RV } +/* + * Reset 11g-related state. + */ +void +ieee80211_reset_erp(struct ieee80211com *ic) +{ + ic->ic_flags &= ~IEEE80211_F_USEPROT; + ic->ic_nonerpsta = 0; + ic->ic_longslotsta = 0; + + /* + * Enable short slot time iff: + * - we're operating in 802.11a or + * - we're operating in 802.11g and we're not in IBSS mode and + * the device supports short slot time + */ + ieee80211_set_shortslottime(ic, + ic->ic_curmode == IEEE80211_MODE_11A || + (ic->ic_curmode == IEEE80211_MODE_11G && + ic->ic_opmode == IEEE80211_M_HOSTAP && + (ic->ic_caps & IEEE80211_C_SHSLOT))); + + if (ic->ic_curmode == IEEE80211_MODE_11A || + (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) + ic->ic_flags |= IEEE80211_F_SHPREAMBLE; + else + ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; +} + +/* + * Set the short slot time state and notify the driver. + */ +void +ieee80211_set_shortslottime(struct ieee80211com *ic, int on) +{ + if (on) + ic->ic_flags |= IEEE80211_F_SHSLOT; + else + ic->ic_flags &= ~IEEE80211_F_SHSLOT; + + /* notify the driver */ + if (ic->ic_updateslot != NULL) + ic->ic_updateslot(ic); +} + static int ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) @@ -508,8 +551,15 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(ic->ic_bss->ni_essid, ni->ni_esslen); - printf(" channel %d start %uMb\n", + printf(" channel %d start %uMb", ieee80211_chan2ieee(ic, ni->ni_chan), mbps); + printf(" %s preamble %s slot time%s\n", + (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? + "short" : "long", + (ic->ic_flags & IEEE80211_F_SHSLOT) ? + "short" : "long", + (ic->ic_flags & IEEE80211_F_USEPROT) ? + " protection enabled" : ""); } ic->ic_mgt_timer = 0; (*ifp->if_start)(ifp); diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index 2e4904c4a8d..392a53634eb 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.h,v 1.8 2006/05/19 18:06:50 damien Exp $ */ +/* $OpenBSD: ieee80211_proto.h,v 1.9 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */ /*- @@ -81,6 +81,7 @@ extern u_int8_t *ieee80211_add_rates(u_int8_t *frm, extern u_int8_t *ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *); extern u_int8_t *ieee80211_add_ssid(u_int8_t *, const u_int8_t *, u_int); +extern u_int8_t *ieee80211_add_erp(u_int8_t *, struct ieee80211com *); extern void ieee80211_print_essid(u_int8_t *, int); extern void ieee80211_dump_pkt(u_int8_t *, int, int, int); extern int ieee80211_ibss_merge(struct ieee80211com *, @@ -88,6 +89,8 @@ extern int ieee80211_ibss_merge(struct ieee80211com *, extern int ieee80211_compute_duration(struct ieee80211_frame *, int, uint32_t, int, int, struct ieee80211_duration *, struct ieee80211_duration *, int *, int); +extern void ieee80211_reset_erp(struct ieee80211com *); +extern void ieee80211_set_shortslottime(struct ieee80211com *, int); extern const char *ieee80211_state_name[IEEE80211_S_MAX]; #endif /* _NET80211_IEEE80211_PROTO_H_ */ diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 0a24d613e17..0273d5d1dac 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_var.h,v 1.12 2005/09/13 12:11:03 reyk Exp $ */ +/* $OpenBSD: ieee80211_var.h,v 1.13 2006/06/18 18:39:41 damien Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- @@ -155,6 +155,7 @@ struct ieee80211com { enum ieee80211_state, int); void (*ic_newassoc)(struct ieee80211com *, struct ieee80211_node *, int); + void (*ic_updateslot)(struct ieee80211com *); int (*ic_set_tim)(struct ieee80211com *, int, int); u_int8_t ic_myaddr[IEEE80211_ADDR_LEN]; struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; @@ -203,6 +204,8 @@ struct ieee80211com { u_int16_t ic_txlifetime; /* tx lifetime */ int16_t ic_txpower; /* tx power setting (dBm) */ 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 */ int ic_mgt_timer; /* mgmt timeout */ int ic_inact_timer; /* inactivity timer wait */ int ic_des_esslen; @@ -241,10 +244,9 @@ extern struct ieee80211com_head ieee80211com_head; #define IEEE80211_F_TXPOW_OFF 0x00000000 /* TX Power: radio disabled */ #define IEEE80211_F_TXPOW_FIXED 0x00008000 /* TX Power: fixed rate */ #define IEEE80211_F_TXPOW_AUTO 0x00010000 /* TX Power: undefined */ -#define IEEE80211_F_SHSLOT 0x00020000 /* CONF: short slot time */ -#define IEEE80211_F_SHPREAMBLE 0x00040000 /* CONF: short preamble */ +#define IEEE80211_F_SHSLOT 0x00020000 /* STATUS: short slot time */ +#define IEEE80211_F_SHPREAMBLE 0x00040000 /* STATUS: short preamble */ #define IEEE80211_F_USEPROT 0x00100000 /* STATUS: protection enabled */ -#define IEEE80211_F_USEBARKER 0x00200000 /* STATUS: use barker preamble*/ /* ic_caps */ #define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */ |