summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2004-04-02 23:25:39 +0000
committersam <sam@FreeBSD.org>2004-04-02 23:25:39 +0000
commitb024266b895c0a68076a0ede4910ffe39b7e258a (patch)
tree993e3d1529ff6a97bf28e206984714e0e08a3c61 /sys/net80211
parent5c586165c7b79b179b3583cb3d33b957f21edfdf (diff)
downloadFreeBSD-src-b024266b895c0a68076a0ede4910ffe39b7e258a.zip
FreeBSD-src-b024266b895c0a68076a0ede4910ffe39b7e258a.tar.gz
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)
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_node.c76
-rw-r--r--sys/net80211/ieee80211_node.h2
-rw-r--r--sys/net80211/ieee80211_output.c36
-rw-r--r--sys/net80211/ieee80211_var.h1
4 files changed, 79 insertions, 36 deletions
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 */
OpenPOWER on IntegriCloud