diff options
author | Sam Leffler <sam@FreeBSD.org> | 2004-04-02 23:25:39 +0000 |
---|---|---|
committer | Sam Leffler <sam@FreeBSD.org> | 2004-04-02 23:25:39 +0000 |
commit | 750d6d0c60338c0c1bc74b07b6b19b37b874bb9f (patch) | |
tree | 993e3d1529ff6a97bf28e206984714e0e08a3c61 /sys/net80211/ieee80211_node.c | |
parent | 6f3f5a11705053bf58bdc145d1a54b4abc629a49 (diff) | |
download | src-750d6d0c60338c0c1bc74b07b6b19b37b874bb9f.tar.gz src-750d6d0c60338c0c1bc74b07b6b19b37b874bb9f.zip |
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)
Notes
Notes:
svn path=/head/; revision=127772
Diffstat (limited to 'sys/net80211/ieee80211_node.c')
-rw-r--r-- | sys/net80211/ieee80211_node.c | 76 |
1 files changed, 70 insertions, 6 deletions
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 59bac2616b66..e8fe0ff38d66 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; } |