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)
This commit is contained in:
parent
6f3f5a1170
commit
750d6d0c60
@ -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,24 +499,79 @@ 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.
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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 *,
|
||||
|
@ -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));
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user