summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211/ieee80211.c')
-rw-r--r--sys/net80211/ieee80211.c254
1 files changed, 231 insertions, 23 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index db9b4d7d610..20af2f2d2ea 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.c,v 1.3 2004/11/03 20:42:41 claudio Exp $ */
+/* $OpenBSD: ieee80211.c,v 1.4 2005/02/17 18:28:05 reyk Exp $ */
/* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */
/*-
@@ -107,13 +107,29 @@ SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug,
#endif
#endif
-int ieee80211_inact_max = IEEE80211_INACT_MAX;
+int ieee80211_cache_size = IEEE80211_CACHE_SIZE;
#ifdef __NetBSD__
-static int ieee80211_inact_max_nodenum;
+static int ieee80211_cache_size_nodenum;
#endif
+struct ieee80211com_head ieee80211com_head =
+ LIST_HEAD_INITIALIZER(ieee80211com_head);
+
static void ieee80211_setbasicrates(struct ieee80211com *);
+#ifdef __NetBSD__
+static void sysctl_ieee80211_fill_node(struct ieee80211_node *,
+ struct ieee80211_node_sysctl *, int, struct ieee80211_channel *, int);
+static struct ieee80211_node *ieee80211_node_walknext(
+ struct ieee80211_node_walk *);
+static struct ieee80211_node *ieee80211_node_walkfirst(
+ struct ieee80211_node_walk *, u_short);
+static int sysctl_ieee80211_verify(SYSCTLFN_ARGS);
+static int sysctl_ieee80211_node(SYSCTLFN_ARGS);
+#endif /* __NetBSD__ */
+
+#define LOGICALLY_EQUAL(x, y) (!(x) == !(y))
+
#if 0
static const char *ieee80211_phymode_name[] = {
"auto", /* IEEE80211_MODE_AUTO */
@@ -193,6 +209,7 @@ ieee80211_ifattach(struct ifnet *ifp)
ic->ic_lintval = 100; /* default sleep */
ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
+ LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
ieee80211_node_attach(ifp);
ieee80211_proto_attach(ifp);
}
@@ -205,6 +222,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
ieee80211_proto_detach(ifp);
ieee80211_crypto_detach(ifp);
ieee80211_node_detach(ifp);
+ LIST_REMOVE(ic, ic_list);
#ifdef __FreeBSD__
ifmedia_removeall(&ic->ic_media);
#else
@@ -395,9 +413,6 @@ ieee80211_media_init(struct ifnet *ifp,
if (maxrate)
ifp->if_baudrate = IF_Mbps(maxrate);
- if (ic->ic_max_aid == 0)
- ic->ic_max_aid = IEEE80211_MAX_AID;
-
#undef ADD
}
@@ -631,10 +646,8 @@ ieee80211_watchdog(struct ifnet *ifp)
if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- if (ic->ic_inact_timer && --ic->ic_inact_timer == 0)
- ieee80211_timeout_nodes(ic);
- if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0)
+ if (ic->ic_mgt_timer != 0)
ifp->if_timer = 1;
}
@@ -765,9 +778,15 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
*
* 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;
@@ -926,6 +945,16 @@ ieee80211_media2rate(int mword)
}
#ifdef __NetBSD__
+static void
+ieee80211_clean_all_nodes(int cache_size)
+{
+ struct ieee80211com *ic;
+ LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
+ ic->ic_max_nnodes = cache_size;
+ ieee80211_clean_nodes(ic);
+ }
+}
+
/* TBD factor with sysctl_ath_verify. */
static int
sysctl_ieee80211_verify(SYSCTLFN_ARGS)
@@ -940,19 +969,14 @@ sysctl_ieee80211_verify(SYSCTLFN_ARGS)
if (error || newp == NULL)
return (error);
- IEEE80211_DPRINTF(("%s: t = %d, nodenum = %d, rnodenum = %d\n",
- __func__, t, node.sysctl_num, rnode->sysctl_num));
-
- if (node.sysctl_num == ieee80211_inact_max_nodenum) {
- if (t < 1)
+ if (node.sysctl_num == ieee80211_cache_size_nodenum) {
+ if (t < 0)
return (EINVAL);
- t = roundup(t, IEEE80211_INACT_WAIT) / IEEE80211_INACT_WAIT;
#ifdef IEEE80211_DEBUG
- } else if (node.sysctl_num == ieee80211_debug_nodenum) {
- if (t < 0 || t > 2)
- return (EINVAL);
-#endif /* IEEE80211_DEBUG */
+ } else if (node.sysctl_num != ieee80211_debug_nodenum)
+#else /* IEEE80211_DEBUG */
} else
+#endif /* IEEE80211_DEBUG */
return (EINVAL);
*(int*)rnode->sysctl_data = t;
@@ -961,6 +985,185 @@ sysctl_ieee80211_verify(SYSCTLFN_ARGS)
}
/*
+ * Pointers for testing:
+ *
+ * If there are no interfaces, or else no 802.11 interfaces,
+ * ieee80211_node_walkfirst must return NULL.
+ *
+ * If there is any single 802.11 interface, ieee80211_node_walkfirst
+ * must not return NULL.
+ */
+static struct ieee80211_node *
+ieee80211_node_walkfirst(struct ieee80211_node_walk *nw,
+ u_short if_index)
+{
+ struct ieee80211com *ic;
+ (void)memset(nw, 0, sizeof(*nw));
+
+ nw->nw_ifindex = if_index;
+
+ LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
+ if (if_index != 0 && ic->ic_if.if_index != if_index)
+ continue;
+ nw->nw_ic = ic;
+ nw->nw_ni = ic->ic_bss;
+ break;
+ }
+
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ return nw->nw_ni;
+}
+
+static struct ieee80211_node *
+ieee80211_node_walknext(struct ieee80211_node_walk *nw)
+{
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ if (nw->nw_ic == NULL && nw->nw_ni == NULL)
+ return NULL;
+
+ if (nw->nw_ni == nw->nw_ic->ic_bss)
+ nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node);
+ else
+ nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list);
+
+ if (nw->nw_ni == NULL) {
+ if (nw->nw_ifindex != 0)
+ return NULL;
+
+ nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list);
+ if (nw->nw_ic == NULL)
+ return NULL;
+
+ nw->nw_ni = nw->nw_ic->ic_bss;
+ }
+
+ KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
+
+ return nw->nw_ni;
+}
+
+static void
+sysctl_ieee80211_fill_node(struct ieee80211_node *ni,
+ struct ieee80211_node_sysctl *ns, int ifindex,
+ struct ieee80211_channel *chan0, int is_bss)
+{
+ ns->ns_ifindex = ifindex;
+ ns->ns_capinfo = ni->ni_capinfo;
+ ns->ns_flags = (is_bss) ? IEEE80211_NODE_SYSCTL_F_BSS : 0;
+ (void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr));
+ (void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid));
+ if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
+ ns->ns_freq = ni->ni_chan->ic_freq;
+ ns->ns_chanflags = ni->ni_chan->ic_flags;
+ ns->ns_chanidx = ni->ni_chan - chan0;
+ } else {
+ ns->ns_freq = ns->ns_chanflags = 0;
+ ns->ns_chanidx = 0;
+ }
+ ns->ns_rssi = ni->ni_rssi;
+ ns->ns_esslen = ni->ni_esslen;
+ (void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid));
+ ns->ns_pwrsave = ni->ni_pwrsave;
+ ns->ns_erp = ni->ni_erp;
+ ns->ns_associd = ni->ni_associd;
+ ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT;
+ ns->ns_rstamp = ni->ni_rstamp;
+ ns->ns_rates = ni->ni_rates;
+ ns->ns_txrate = ni->ni_txrate;
+ ns->ns_intval = ni->ni_intval;
+ (void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp));
+ ns->ns_txseq = ni->ni_txseq;
+ ns->ns_rxseq = ni->ni_rxseq;
+ ns->ns_fhdwell = ni->ni_fhdwell;
+ ns->ns_fhindex = ni->ni_fhindex;
+ ns->ns_fails = ni->ni_fails;
+}
+
+/* Between two examinations of the sysctl tree, I expect each
+ * interface to add no more than 5 nodes.
+ */
+#define IEEE80211_SYSCTL_NODE_GROWTH 5
+
+static int
+sysctl_ieee80211_node(SYSCTLFN_ARGS)
+{
+ struct ieee80211_node_walk nw;
+ struct ieee80211_node *ni;
+ struct ieee80211_node_sysctl ns;
+ char *dp;
+ u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type;
+ size_t len, needed, eltsize, out_size;
+ int error, s, nelt;
+
+ if (namelen == 1 && name[0] == CTL_QUERY)
+ return (sysctl_query(SYSCTLFN_CALL(rnode)));
+
+ if (namelen != IEEE80211_SYSCTL_NODENAMELEN)
+ return (EINVAL);
+
+ /* ifindex.op.arg.header-type.eltsize.nelt */
+ dp = oldp;
+ len = (oldp != NULL) ? *oldlenp : 0;
+ ifindex = name[IEEE80211_SYSCTL_NODENAME_IF];
+ op = name[IEEE80211_SYSCTL_NODENAME_OP];
+ arg = name[IEEE80211_SYSCTL_NODENAME_ARG];
+ hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE];
+ eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE];
+ nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT];
+ out_size = MIN(sizeof(ns), eltsize);
+
+ if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 ||
+ hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0)
+ return (EINVAL);
+
+ error = 0;
+ needed = 0;
+ ifcount = 0;
+ last_ifindex = 0;
+
+ s = splnet();
+
+ for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL;
+ ni = ieee80211_node_walknext(&nw)) {
+ struct ieee80211com *ic;
+
+ ic = nw.nw_ic;
+ cur_ifindex = ic->ic_if.if_index;
+
+ if (cur_ifindex != last_ifindex) {
+ ifcount++;
+ last_ifindex = cur_ifindex;
+ }
+
+ if (nelt <= 0)
+ continue;
+
+ if (len >= eltsize) {
+ sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex,
+ &ic->ic_channels[0], ni == ic->ic_bss);
+ error = copyout(&ns, dp, out_size);
+ if (error)
+ goto cleanup;
+ dp += eltsize;
+ len -= eltsize;
+ }
+ needed += eltsize;
+ if (nelt != INT_MAX)
+ nelt--;
+ }
+cleanup:
+ splx(s);
+
+ *oldlenp = needed;
+ if (oldp == NULL)
+ *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize;
+
+ return (error);
+}
+
+/*
* Setup sysctl(3) MIB, net.ieee80211.*
*
* TBD condition CTLFLAG_PERMANENT on being an LKM or not
@@ -987,6 +1190,11 @@ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup")
NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
goto err;
+ if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
+ sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
+ goto err;
+
#ifdef IEEE80211_DEBUG
/* control debugging printfs */
@@ -1001,15 +1209,15 @@ SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup")
#endif /* IEEE80211_DEBUG */
- /* control inactivity timer */
+ /* control LRU cache size */
if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
- "maxinact", SYSCTL_DESCR("Station inactivity timeout"),
- sysctl_ieee80211_verify, 0, &ieee80211_inact_max,
+ "maxnodecache", SYSCTL_DESCR("Maximum station cache size"),
+ sysctl_ieee80211_verify, 0, &ieee80211_cache_size,
0, CTL_CREATE, CTL_EOL)) != 0)
goto err;
- ieee80211_inact_max_nodenum = cnode->sysctl_num;
+ ieee80211_cache_size_nodenum = cnode->sysctl_num;
return;
err: