summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2006-06-18 18:39:42 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2006-06-18 18:39:42 +0000
commitb6efe24e3cd0a45a2c3b9be9b804f53c1db0152e (patch)
treef509d197cf8f8687c2f10f508d445ddaaa8d9534
parente6d4b8dbc6221983c325d69573f969a9b074cdc6 (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.c35
-rw-r--r--sys/net80211/ieee80211_crypto.c4
-rw-r--r--sys/net80211/ieee80211_input.c88
-rw-r--r--sys/net80211/ieee80211_node.c151
-rw-r--r--sys/net80211/ieee80211_node.h5
-rw-r--r--sys/net80211/ieee80211_output.c125
-rw-r--r--sys/net80211/ieee80211_proto.c58
-rw-r--r--sys/net80211/ieee80211_proto.h5
-rw-r--r--sys/net80211/ieee80211_var.h10
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 */