summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_mesh.c
diff options
context:
space:
mode:
authormonthadar <monthadar@FreeBSD.org>2013-02-07 21:26:06 +0000
committermonthadar <monthadar@FreeBSD.org>2013-02-07 21:26:06 +0000
commit9cc12d2c5f7a100b44e6de96a1d195b962db14d3 (patch)
tree7b38b4c881fd04eb5e9800518c7cfd7c03c14eba /sys/net80211/ieee80211_mesh.c
parent6bc4d326227cd340b42d20c050e4a27b9c41f2b2 (diff)
downloadFreeBSD-src-9cc12d2c5f7a100b44e6de96a1d195b962db14d3.zip
FreeBSD-src-9cc12d2c5f7a100b44e6de96a1d195b962db14d3.tar.gz
Mesh gate code to transmit to all mesh gates.
* Modified mesh_find_txnode to be able to handle proxy marked entries by recursively calling itself to find the txnode towards the active mesh gate; * Mesh Gate: Added a new function that transmits data frames similar to ieee80211_start; * Modified ieee80211_mesh_forward_to_gates so that: + Frames are duplicated and sent to each valid Mesh Gate; + Route is marked invalid before return of function, this is because we dont know yet which Mesh Gate is we will use; Approved by: adrian (mentor)
Diffstat (limited to 'sys/net80211/ieee80211_mesh.c')
-rw-r--r--sys/net80211/ieee80211_mesh.c192
1 files changed, 167 insertions, 25 deletions
diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c
index f8eb30b..1cc4419 100644
--- a/sys/net80211/ieee80211_mesh.c
+++ b/sys/net80211/ieee80211_mesh.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <net/bpf.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_llc.h>
@@ -79,6 +80,8 @@ static int mesh_checkpseq(struct ieee80211vap *,
static struct ieee80211_node *
mesh_find_txnode(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
+static void mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
+ struct ieee80211_mesh_route *);
static void mesh_forward(struct ieee80211vap *, struct mbuf *,
const struct ieee80211_meshcntl *);
static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int);
@@ -1011,21 +1014,151 @@ mesh_find_txnode(struct ieee80211vap *vap,
rt = ieee80211_mesh_rt_find(vap, dest);
if (rt == NULL)
return NULL;
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
- (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
- "%s: !valid or proxy, flags 0x%x", __func__, rt->rt_flags);
+ "%s: !valid, flags 0x%x", __func__, rt->rt_flags);
/* XXX stat */
return NULL;
}
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ rt = ieee80211_mesh_rt_find(vap, rt->rt_mesh_gate);
+ if (rt == NULL) return NULL;
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
+ "%s: meshgate !valid, flags 0x%x", __func__,
+ rt->rt_flags);
+ /* XXX stat */
+ return NULL;
+ }
+ }
return ieee80211_find_txnode(vap, rt->rt_nexthop);
}
+static void
+mesh_transmit_to_gate(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_mesh_route *rt_gate)
+{
+ struct ifnet *ifp = vap->iv_ifp;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *parent = ic->ic_ifp;
+ struct ieee80211_node *ni;
+ struct ether_header *eh;
+ int error;
+
+ eh = mtod(m, struct ether_header *);
+ ni = mesh_find_txnode(vap, rt_gate->rt_dest);
+ if (ni == NULL) {
+ ifp->if_oerrors++;
+ m_freem(m);
+ return;
+ }
+
+ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
+ (m->m_flags & M_PWR_SAV) == 0) {
+ /*
+ * Station in power save mode; pass the frame
+ * to the 802.11 layer and continue. We'll get
+ * the frame back when the time is right.
+ * XXX lose WDS vap linkage?
+ */
+ (void) ieee80211_pwrsave(ni, m);
+ ieee80211_free_node(ni);
+ return;
+ }
+
+ /* calculate priority so drivers can find the tx queue */
+ if (ieee80211_classify(ni, m)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
+ eh->ether_dhost, NULL,
+ "%s", "classification failure");
+ vap->iv_stats.is_tx_classify++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ ieee80211_free_node(ni);
+ return;
+ }
+ /*
+ * Stash the node pointer. Note that we do this after
+ * any call to ieee80211_dwds_mcast because that code
+ * uses any existing value for rcvif to identify the
+ * interface it (might have been) received on.
+ */
+ m->m_pkthdr.rcvif = (void *)ni;
+
+ BPF_MTAP(ifp, m); /* 802.3 tx */
+
+ /*
+ * Check if A-MPDU tx aggregation is setup or if we
+ * should try to enable it. The sta must be associated
+ * with HT and A-MPDU enabled for use. When the policy
+ * routine decides we should enable A-MPDU we issue an
+ * ADDBA request and wait for a reply. The frame being
+ * encapsulated will go out w/o using A-MPDU, or possibly
+ * it might be collected by the driver and held/retransmit.
+ * The default ic_ampdu_enable routine handles staggering
+ * ADDBA requests in case the receiver NAK's us or we are
+ * otherwise unable to establish a BA stream.
+ */
+ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
+ (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) &&
+ (m->m_flags & M_EAPOL) == 0) {
+ int tid = WME_AC_TO_TID(M_WME_GETAC(m));
+ struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid];
+
+ ieee80211_txampdu_count_packet(tap);
+ if (IEEE80211_AMPDU_RUNNING(tap)) {
+ /*
+ * Operational, mark frame for aggregation.
+ *
+ * XXX do tx aggregation here
+ */
+ m->m_flags |= M_AMPDU_MPDU;
+ } else if (!IEEE80211_AMPDU_REQUESTED(tap) &&
+ ic->ic_ampdu_enable(ni, tap)) {
+ /*
+ * Not negotiated yet, request service.
+ */
+ ieee80211_ampdu_request(ni, tap);
+ /* XXX hold frame for reply? */
+ }
+ }
+#ifdef IEEE80211_SUPPORT_SUPERG
+ else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) {
+ m = ieee80211_ff_check(ni, m);
+ if (m == NULL) {
+ /* NB: any ni ref held on stageq */
+ return;
+ }
+ }
+#endif /* IEEE80211_SUPPORT_SUPERG */
+ if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(vap, ni, m);
+ if (m == NULL) {
+ /* NB: stat+msg handled in ieee80211_encap */
+ ieee80211_free_node(ni);
+ return;
+ }
+ }
+ error = parent->if_transmit(parent, m);
+ if (error != 0) {
+ m_freem(m);
+ ieee80211_free_node(ni);
+ } else {
+ ifp->if_opackets++;
+ }
+ ic->ic_lastdata = ticks;
+}
+
/*
* Forward the queued frames to known valid mesh gates.
* Assume destination to be outside the MBSS (i.e. proxy entry),
* If no valid mesh gates are known silently discard queued frames.
- * If there is no 802.2 path route will be timedout.
+ * After transmitting frames to all known valid mesh gates, this route
+ * will be marked invalid, and a new path discovery will happen in the hopes
+ * that (at least) one of the mesh gates have a new proxy entry for us to use.
*/
void
ieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
@@ -1033,17 +1166,20 @@ ieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
{
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
- struct ifnet *ifp = vap->iv_ifp;
struct ieee80211_mesh_route *rt_gate;
struct ieee80211_mesh_gate_route *gr = NULL, *gr_next;
- struct mbuf *m, *next;
- int gates_found = 0;
+ struct mbuf *m, *mcopy, *next;
KASSERT( rt_dest->rt_flags == IEEE80211_MESHRT_FLAGS_DISCOVER,
("Route is not marked with IEEE80211_MESHRT_FLAGS_DISCOVER"));
/* XXX: send to more than one valid mash gate */
MESH_RT_LOCK(ms);
+
+ m = ieee80211_ageq_remove(&ic->ic_stageq,
+ (struct ieee80211_node *)(uintptr_t)
+ ieee80211_mac_hash(ic, rt_dest->rt_dest));
+
TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, gr_next) {
rt_gate = gr->gr_route;
if (rt_gate == NULL) {
@@ -1053,8 +1189,18 @@ ieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
gr->gr_addr, ":");
continue;
}
- gates_found = 1;
- /* convert route to a proxy route */
+ if ((rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
+ continue;
+ KASSERT(rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_GATE,
+ ("route not marked as a mesh gate"));
+ KASSERT((rt_gate->rt_flags &
+ IEEE80211_MESHRT_FLAGS_PROXY) == 0,
+ ("found mesh gate that is also marked porxy"));
+ /*
+ * convert route to a proxy route gated by the current
+ * mesh gate, this is needed so encap can built data
+ * frame with correct address.
+ */
rt_dest->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
IEEE80211_MESHRT_FLAGS_VALID;
rt_dest->rt_ext_seq = 1; /* random value */
@@ -1064,26 +1210,22 @@ ieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
rt_dest->rt_nhops = rt_gate->rt_nhops;
ieee80211_mesh_rt_update(rt_dest, ms->ms_ppath->mpp_inact);
MESH_RT_UNLOCK(ms);
- m = ieee80211_ageq_remove(&ic->ic_stageq,
- (struct ieee80211_node *)(uintptr_t)
- ieee80211_mac_hash(ic, rt_dest->rt_dest));
- for (; m != NULL; m = next) {
- next = m->m_nextpkt;
- m->m_nextpkt = NULL;
- IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, rt_dest->rt_dest,
- "flush queued frame %p len %d", m, m->m_pkthdr.len);
- ifp->if_transmit(ifp, m);
+ /* XXX: lock?? */
+ mcopy = m_dup(m, M_NOWAIT);
+ for (; mcopy != NULL; mcopy = next) {
+ next = mcopy->m_nextpkt;
+ mcopy->m_nextpkt = NULL;
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
+ rt_dest->rt_dest,
+ "flush queued frame %p len %d", mcopy,
+ mcopy->m_pkthdr.len);
+ mesh_transmit_to_gate(vap, mcopy, rt_gate);
}
MESH_RT_LOCK(ms);
}
-
- if (gates_found == 0) {
- rt_dest->rt_flags = 0; /* Mark invalid */
- IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, rt_dest->rt_dest,
- "%s", "no mesh gate found, or no path setup for mesh gate yet");
- }
+ rt_dest->rt_flags = 0; /* Mark invalid */
+ m_freem(m);
MESH_RT_UNLOCK(ms);
-
}
/*
OpenPOWER on IntegriCloud