From b024266b895c0a68076a0ede4910ffe39b7e258a Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 2 Apr 2004 23:25:39 +0000 Subject: fix adhoc/ibss operation for drivers that require host support (e.g. ath): o remove IEEE80211_C_RCVMGT capability o on transmit craft new nodes as needed using new ieee80211_find_txnode routine o add ieee80211_find_txnode routine to lookup a node by mac address and if not present create one when operating in ibss/ahdemo mode; new nodes are dup'd from bss and the driver is told to treat the node as if a new association has been created so driver-private state (e.g. rate control handling) is setup Obtained from: netbsd (basic idea) --- sys/net80211/ieee80211_node.c | 76 +++++++++++++++++++++++++++++++++++++---- sys/net80211/ieee80211_node.h | 2 ++ sys/net80211/ieee80211_output.c | 36 ++++--------------- sys/net80211/ieee80211_var.h | 1 - 4 files changed, 79 insertions(+), 36 deletions(-) (limited to 'sys/net80211') diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 59bac26..e8fe0ff 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -403,6 +403,14 @@ ieee80211_end_scan(struct ifnet *ifp) goto notfound; } ieee80211_unref_node(&selbs); + /* + * Discard scan set; the nodes have a refcnt of zero + * and have not asked the driver to setup private + * node state. Let them be repopulated on demand either + * through transmission (ieee80211_find_txnode) or receipt + * of a probe response (to be added). + */ + ieee80211_free_allnodes(ic); ieee80211_new_state(ic, IEEE80211_S_RUN, -1); } else { ieee80211_unref_node(&selbs); @@ -491,25 +499,80 @@ ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr) return ni; } -struct ieee80211_node * -ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr) +static struct ieee80211_node * +_ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr) { struct ieee80211_node *ni; int hash; + IEEE80211_NODE_LOCK_ASSERT(ic); + hash = IEEE80211_NODE_HASH(macaddr); - IEEE80211_NODE_LOCK(ic); LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { - atomic_add_int(&ni->ni_refcnt, 1); /* mark referenced */ - break; + atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */ + return ni; } } + return NULL; +} + +struct ieee80211_node * +ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr) +{ + struct ieee80211_node *ni; + + IEEE80211_NODE_LOCK(ic); + ni = _ieee80211_find_node(ic, macaddr); IEEE80211_NODE_UNLOCK(ic); return ni; } /* + * Return a reference to the appropriate node for sending + * a data frame. This handles node discovery in adhoc networks. + */ +struct ieee80211_node * +ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr) +{ + struct ieee80211_node *ni; + + /* + * The destination address should be in the node table + * unless we are operating in station mode or this is a + * multicast/broadcast frame. + */ + if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) + return ic->ic_bss; + + /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ + IEEE80211_NODE_LOCK(ic); + ni = _ieee80211_find_node(ic, macaddr); + IEEE80211_NODE_UNLOCK(ic); + if (ni == NULL && + (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO)) { + /* + * 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. + * + * XXX need better way to handle this; issue probe + * request so we can deduce rate set, etc. + */ + ni = ieee80211_dup_bss(ic, macaddr); + if (ni != NULL) { + /* XXX no rate negotiation; just dup */ + ni->ni_rates = ic->ic_bss->ni_rates; + if (ic->ic_newassoc) + (*ic->ic_newassoc)(ic, ni, 1); + } + } + return ni; +} + +/* * Like find but search based on the channel too. */ struct ieee80211_node * @@ -522,7 +585,8 @@ ieee80211_lookup_node(struct ieee80211com *ic, hash = IEEE80211_NODE_HASH(macaddr); IEEE80211_NODE_LOCK(ic); LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { - if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && ni->ni_chan == chan) { + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && + ni->ni_chan == chan) { atomic_add_int(&ni->ni_refcnt, 1);/* mark referenced */ break; } diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index b0e0437..0725ffb 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -141,6 +141,8 @@ extern struct ieee80211_node *ieee80211_dup_bss(struct ieee80211com *, u_int8_t *); extern struct ieee80211_node *ieee80211_find_node(struct ieee80211com *, u_int8_t *); +extern struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *, + u_int8_t *); extern struct ieee80211_node * ieee80211_lookup_node(struct ieee80211com *, u_int8_t *macaddr, struct ieee80211_channel *); extern void ieee80211_free_node(struct ieee80211com *, diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 6ea342d..3e144458 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -161,35 +161,13 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) } memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); - if (ic->ic_opmode != IEEE80211_M_STA) { - ni = ieee80211_find_node(ic, eh.ether_dhost); - if (ni == NULL) { - /* - * When not in station mode the destination - * address should always be in the node table - * if the device sends management frames to us; - * unless this is a multicast/broadcast frame. - * For devices that don't send management frames - * to the host we have to cheat; use the bss - * node instead; the card will/should clobber - * the bssid address as necessary. - * - * XXX this handles AHDEMO because all devices - * that support it don't send mgmt frames; - * but it might be better to test explicitly - */ - if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) && - (ic->ic_caps & IEEE80211_C_RCVMGT)) { - IEEE80211_DPRINTF(("%s: no node for dst %s, " - "discard frame\n", __func__, - ether_sprintf(eh.ether_dhost))); - ic->ic_stats.is_tx_nonode++; - goto bad; - } - ni = ic->ic_bss; - } - } else - ni = ic->ic_bss; + ni = ieee80211_find_txnode(ic, eh.ether_dhost); + if (ni == NULL) { + IEEE80211_DPRINTF(("%s: no node for dst %s, discard frame\n", + __func__, ether_sprintf(eh.ether_dhost))); + ic->ic_stats.is_tx_nonode++; + goto bad; + } ni->ni_inact = 0; m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 3750c6a..c5ef197 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -253,7 +253,6 @@ struct ieee80211com { #define IEEE80211_C_SHSLOT 0x00000080 /* CAPABILITY: short slottime */ #define IEEE80211_C_SHPREAMBLE 0x00000100 /* CAPABILITY: short preamble */ #define IEEE80211_C_MONITOR 0x00000200 /* CAPABILITY: monitor mode */ -#define IEEE80211_C_RCVMGT 0x00000400 /* CAPABILITY: rcv mgt frames */ /* flags for ieee80211_fix_rate() */ #define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ -- cgit v1.1