PERFORCE change 64714 for review
Sam Leffler
sam at FreeBSD.org
Tue Nov 9 12:29:23 PST 2004
http://perforce.freebsd.org/chv.cgi?CH=64714
Change 64714 by sam at sam_ebb on 2004/11/09 20:28:25
checkpoint ibss support
Affected files ...
.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.c#9 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.h#8 edit
Differences ...
==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 (text+ko) ====
@@ -190,8 +190,12 @@
}
bssid = wh->i_addr3;
}
- if (type == IEEE80211_FC0_TYPE_DATA &&
- !IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
+ if (type != IEEE80211_FC0_TYPE_DATA)
+ break;
+ /*
+ * Data frame, validate the bssid.
+ */
+ if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
!IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) {
/* not interested in */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
@@ -200,6 +204,24 @@
ic->ic_stats.is_rx_wrongbss++;
goto out;
}
+ /*
+ * For adhoc mode we cons up a node when it doesn't
+ * exist. This should probably done after an ACL check.
+ */
+ if (ni == ic->ic_bss &&
+ ic->ic_opmode != IEEE80211_M_HOSTAP) {
+ /*
+ * Fake up a node for this newly
+ * discovered member of the IBSS.
+ */
+ ni = ieee80211_fakeup_adhoc_node(ic->ic_sta,
+ type == IEEE80211_FC0_TYPE_CTL ?
+ wh->i_addr1 : wh->i_addr2);
+ if (ni == NULL) {
+ /* NB: stat kept for alloc failure */
+ goto err;
+ }
+ }
break;
default:
goto out;
@@ -1805,7 +1827,20 @@
wh->i_addr2, chan, bchan, capinfo,
bintval, erp, ssid, country);
#endif
- ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2);
+ /*
+ * Create a new entry. If scanning the entry goes
+ * in the scan cache. Otherwise, be particular when
+ * operating in adhoc mode--only take nodes marked
+ * as ibss participants so we don't populate our
+ * neighbor table with unintersting sta's.
+ */
+ if (ic->ic_state != IEEE80211_S_SCAN) {
+ if ((capinfo & IEEE80211_CAPINFO_IBSS) == 0)
+ return;
+ ni = ieee80211_fakeup_adhoc_node(ic->ic_sta,
+ wh->i_addr2);
+ } else
+ ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2);
if (ni == NULL)
return;
ni->ni_esslen = ssid[1];
@@ -1898,7 +1933,17 @@
IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, "probe");
if (ni == ic->ic_bss) {
- ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2);
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ /*
+ * XXX Cannot tell if the sender is operating
+ * in ibss mode. But we need a new node to
+ * send the response so blindly add them to the
+ * neighbor table.
+ */
+ ni = ieee80211_fakeup_adhoc_node(ic->ic_sta,
+ wh->i_addr2);
+ } else
+ ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2);
if (ni == NULL)
return;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
==== //depot/projects/wifi/sys/net80211/ieee80211_node.c#9 (text+ko) ====
@@ -63,10 +63,10 @@
static void ieee80211_timeout_stations(struct ieee80211_node_table *);
static void ieee80211_node_table_init(struct ieee80211com *ic,
- struct ieee80211_node_table *nt, int inact,
+ struct ieee80211_node_table *nt, const char *name, int inact,
void (*timeout)(struct ieee80211_node_table *));
static struct ieee80211_node_table *ieee80211_node_table_alloc(
- struct ieee80211com *ic, int inact,
+ struct ieee80211com *ic, const char *name, int inact,
void (*timeout)(struct ieee80211_node_table *));
static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
@@ -77,7 +77,7 @@
{
ic->ic_sta = NULL; /* defer to when we need it */
- ieee80211_node_table_init(ic, &ic->ic_scan,
+ ieee80211_node_table_init(ic, &ic->ic_scan, "scan",
IEEE80211_INACT_SCAN, ieee80211_timeout_scan_candidates);
ic->ic_node_alloc = node_alloc;
@@ -327,21 +327,34 @@
{
struct ieee80211_node *ni;
- ni = ic->ic_bss;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: creating ibss\n", __func__);
- ic->ic_sta = ieee80211_node_table_alloc(ic,
- ic->ic_inact_init, ieee80211_timeout_stations);
+ /*
+ * Create the station/neighbor table. Note that for adhoc
+ * mode we make the initial inactivity timer longer since
+ * we create nodes only through discovery and they typically
+ * are long-lived associations.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ ic->ic_sta = ieee80211_node_table_alloc(ic,
+ "station", ic->ic_inact_init,
+ ieee80211_timeout_stations);
+ else
+ ic->ic_sta = ieee80211_node_table_alloc(ic,
+ "neighbor", ic->ic_inact_run,
+ ieee80211_timeout_stations);
if (ic->ic_sta == NULL) {
/*
* Should remain in SCAN state and retry.
*/
+ /* XXX stat+msg */
return;
}
+ ni = ic->ic_bss;
ic->ic_flags |= IEEE80211_F_SIBSS;
- ieee80211_set_chan(ic, ic->ic_bss, chan);
+ ieee80211_set_chan(ic, ni, chan);
IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
if (ic->ic_opmode == IEEE80211_M_IBSS)
@@ -612,7 +625,43 @@
goto notfound;
}
}
+
+/*
+ * Handle 802.11 ad hoc network merge. The
+ * convention, set by the Wireless Ethernet Compatibility Alliance
+ * (WECA), is that an 802.11 station will change its BSSID to match
+ * the "oldest" 802.11 ad hoc network, on the same channel, that
+ * has the station's desired SSID. The "oldest" 802.11 network
+ * sends beacons with the greatest TSF timestamp.
+ *
+ * The caller is assumed to validate TSF's before attempting a merge.
+ *
+ * Return !0 if the BSSID changed, 0 otherwise.
+ */
+int
+ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
+ /* unchanged, nothing to do */
+ return 0;
+ }
+ if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+ "%s: merge failed, capabilities mismatch\n", __func__);
+ ic->ic_stats.is_ibss_capmismatch++;
+ return 0;
+ }
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
+ "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
+ ether_sprintf(ni->ni_bssid),
+ ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
+ ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
+ ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
+ );
+ return ieee80211_sta_join(ic, ni);
+}
+
/*
* Join the specified IBSS/BSS network. The node is assumed to
* be passed in with a held reference.
@@ -630,6 +679,7 @@
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (selbs->ni_rates.rs_nrates == 0) {
selbs->ni_fails++;
+ ic->ic_stats.is_ibss_norate++;
return 0;
}
}
@@ -742,7 +792,9 @@
int hash;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
- "%s %s\n", __func__, ether_sprintf(macaddr));
+ "%s %s in %s table\n", __func__,
+ ether_sprintf(macaddr), nt->nt_name);
+
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
hash = IEEE80211_NODE_HASH(macaddr);
ieee80211_node_initref(ni); /* mark referenced */
@@ -845,15 +897,16 @@
}
/*
- * Fake up a node; this handles node discovery in
- * adhoc mode. Note that for the driver's benefit
- * we we treat this like an association so the driver
- * has an opportunity to setup it's private state.
+ * Fake up a node; this handles node discovery in adhoc mode.
+ * Note that for the driver's benefit we we treat this like
+ * an association so the driver has an opportunity to setup
+ * it's private state.
*/
-static __inline struct ieee80211_node *
-fakeup_node(struct ieee80211com *ic, struct ieee80211_node_table *nt,
+struct ieee80211_node *
+ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt,
const u_int8_t macaddr[IEEE80211_ADDR_LEN])
{
+ struct ieee80211com *ic = nt->nt_ic;
struct ieee80211_node *ni;
ni = ieee80211_dup_bss(nt, macaddr);
@@ -862,21 +915,20 @@
ni->ni_rates = ic->ic_bss->ni_rates;
if (ic->ic_newassoc)
ic->ic_newassoc(ic, ni, 1);
- /* XXX not sure how 802.1x works w/ IBSS */
+ /* XXX not right for 802.1x/WPA */
ieee80211_node_authorize(ic, ni);
+ ieee80211_ref_node(ni); /* hold reference */
}
return ni;
}
/*
- * Locate the node for sender, track state, and then
- * pass the (referenced) node up to the 802.11 layer
- * for its use. We are required to pass some node so
- * we fall back to ic_bss when this frame is from an
- * unknown sender. The 802.11 layer knows this means the
- * sender wasn't in the node table and acts accordingly.
- * Note also that by convention we do not reference
- * count ic_bss, only other nodes (ic_bss is never free'd).
+ * Locate the node for sender, track state, and then pass the
+ * (referenced) node up to the 802.11 layer for its use. We
+ * are required to pass some node so we fall back to ic_bss
+ * when this frame is from an unknown sender. The 802.11 layer
+ * knows this means the sender wasn't in the node table and
+ * acts accordingly.
*/
struct ieee80211_node *
#ifdef IEEE80211_DEBUG_REFCNT
@@ -892,10 +944,13 @@
struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
- if (ic->ic_opmode != IEEE80211_M_STA)
+ /* XXX may want scanned nodes in the neighbor table for adhoc */
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_opmode == IEEE80211_M_MONITOR ||
+ ic->ic_state == IEEE80211_S_SCAN /*XXX*/)
+ nt = &ic->ic_scan;
+ else
nt = ic->ic_sta;
- else
- nt = &ic->ic_scan;
/* XXX check ic_bss first in station mode */
/* XXX 4-address frames? */
IEEE80211_NODE_LOCK(nt);
@@ -905,10 +960,6 @@
ni = _ieee80211_find_node(nt, wh->i_addr2);
IEEE80211_NODE_UNLOCK(nt);
- if (ni == NULL &&
- (ic->ic_opmode == IEEE80211_M_IBSS ||
- ic->ic_opmode == IEEE80211_M_AHDEMO))
- ni = fakeup_node(ic, nt, wh->i_addr2);
return (ni != NULL ? ni : ieee80211_ref_node(ic->ic_bss));
#undef IS_CTL
}
@@ -944,7 +995,7 @@
if (ni == NULL &&
(ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_AHDEMO))
- ni = fakeup_node(ic, nt, macaddr);
+ ni = ieee80211_fakeup_adhoc_node(nt, macaddr);
return ni;
}
@@ -1029,14 +1080,14 @@
_ieee80211_free_node(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_node_table *nt = ni->ni_table;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
- "%s %s\n", __func__, ether_sprintf(ni->ni_macaddr));
+ "%s %s in %s table\n", __func__, ether_sprintf(ni->ni_macaddr),
+ nt != NULL ? nt->nt_name : "<gone>");
IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
- if (ni->ni_table != NULL) {
- struct ieee80211_node_table *nt = ni->ni_table;
-
+ if (nt != NULL) {
TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
LIST_REMOVE(ni, ni_hash);
}
@@ -1111,7 +1162,7 @@
struct ieee80211_node *ni;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
- "%s: free all nodes\n", __func__);
+ "%s: free all nodes in %s table\n", __func__, nt->nt_name);
while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) {
if (ni->ni_associd != 0) {
@@ -1219,7 +1270,7 @@
* in LOR between the node lock and the driver lock.
*/
IEEE80211_NODE_UNLOCK(nt);
- if (ieee80211_node_is_authorized(ni)) {
+ if (ni->ni_associd != 0) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_EXPIRE);
@@ -1454,12 +1505,15 @@
"station %s with aid %d leaves\n",
ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_AID(ni));
- KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
- ("not in ap mode, mode %u", ic->ic_opmode));
+ KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_IBSS ||
+ ic->ic_opmode == IEEE80211_M_AHDEMO,
+ ("unexpected operating mode %u", ic->ic_opmode));
/*
* If node wasn't previously associated all
* we need to do is reclaim the reference.
*/
+ /* XXX ibss mode bypasses 11g and notification */
if (ni->ni_associd == 0)
goto done;
/*
@@ -1550,20 +1604,27 @@
static void
ieee80211_node_table_init(struct ieee80211com *ic,
- struct ieee80211_node_table *nt, int inact,
+ struct ieee80211_node_table *nt,
+ const char *name, int inact,
void (*timeout)(struct ieee80211_node_table *))
{
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+ "%s %s table, inact %u\n", __func__, name, inact);
+
nt->nt_ic = ic;
/* XXX need unit */
IEEE80211_NODE_LOCK_INIT(nt, ic->ic_ifp->if_xname);
TAILQ_INIT(&nt->nt_node);
+ nt->nt_name = name;
nt->nt_scangen = 1;
nt->nt_inact_init = inact;
nt->nt_timeout = timeout;
}
static struct ieee80211_node_table *
-ieee80211_node_table_alloc(struct ieee80211com *ic, int inact,
+ieee80211_node_table_alloc(struct ieee80211com *ic,
+ const char *name, int inact,
void (*timeout)(struct ieee80211_node_table *))
{
struct ieee80211_node_table *nt;
@@ -1575,13 +1636,17 @@
printf("%s: no memory node table!\n", __func__);
return NULL;
}
- ieee80211_node_table_init(ic, nt, inact, timeout);
+ ieee80211_node_table_init(ic, nt, name, inact, timeout);
return nt;
}
void
ieee80211_node_table_reset(struct ieee80211_node_table *nt)
{
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+ "%s %s table\n", __func__, nt->nt_name);
+
IEEE80211_NODE_LOCK(nt);
nt->nt_inact_timer = 0;
ieee80211_free_allnodes_locked(nt);
@@ -1591,6 +1656,10 @@
static void
ieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
{
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+ "%s %s table\n", __func__, nt->nt_name);
+
ieee80211_free_allnodes_locked(nt);
IEEE80211_NODE_LOCK_DESTROY(nt);
}
@@ -1601,6 +1670,10 @@
void
ieee80211_node_table_free(struct ieee80211_node_table *nt)
{
+
+ IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
+ "%s %s table\n", __func__, nt->nt_name);
+
IEEE80211_NODE_LOCK(nt);
nt->nt_inact_timer = 0;
ieee80211_node_table_cleanup(nt);
==== //depot/projects/wifi/sys/net80211/ieee80211_node.h#8 (text+ko) ====
@@ -191,7 +191,7 @@
extern void ieee80211_node_detach(struct ieee80211com *);
static __inline int
-ieee80211_node_is_authorized(struct ieee80211_node *ni)
+ieee80211_node_is_authorized(const struct ieee80211_node *ni)
{
return (ni->ni_flags & IEEE80211_NODE_AUTH);
}
@@ -206,6 +206,8 @@
extern void ieee80211_create_ibss(struct ieee80211com*,
struct ieee80211_channel *);
extern void ieee80211_end_scan(struct ieee80211com *);
+extern int ieee80211_ibss_merge(struct ieee80211com *,
+ struct ieee80211_node *);
extern int ieee80211_sta_join(struct ieee80211com *,
struct ieee80211_node *);
extern void ieee80211_sta_leave(struct ieee80211com *,
@@ -222,6 +224,7 @@
ieee80211_node_lock_t nt_nodelock; /* on node table */
TAILQ_HEAD(, ieee80211_node) nt_node; /* information of all nodes */
LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
+ const char *nt_name; /* for debugging */
u_int nt_scangen; /* gen# for timeout scan */
int nt_inact_timer; /* inactivity timer */
int nt_inact_init; /* initial node inact setting */
@@ -290,6 +293,9 @@
struct ieee80211_node *);
extern void ieee80211_dump_nodes(struct ieee80211_node_table *);
+extern struct ieee80211_node *ieee80211_fakeup_adhoc_node(
+ struct ieee80211_node_table *nt,
+ const u_int8_t macaddr[]);
extern void ieee80211_node_join(struct ieee80211com *,
struct ieee80211_node *, int);
extern void ieee80211_node_leave(struct ieee80211com *,
More information about the p4-projects
mailing list