svn commit: r246511 - head/sys/net80211

Monthadar Al Jaberi monthadar at FreeBSD.org
Thu Feb 7 21:26:06 UTC 2013


Author: monthadar
Date: Thu Feb  7 21:26:06 2013
New Revision: 246511
URL: http://svnweb.freebsd.org/changeset/base/246511

Log:
  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)

Modified:
  head/sys/net80211/ieee80211_mesh.c

Modified: head/sys/net80211/ieee80211_mesh.c
==============================================================================
--- head/sys/net80211/ieee80211_mesh.c	Thu Feb  7 21:25:32 2013	(r246510)
+++ head/sys/net80211/ieee80211_mesh.c	Thu Feb  7 21:26:06 2013	(r246511)
@@ -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 ieee802
 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 *va
 	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 i
 {
 	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 i
 				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 i
 		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);
-
 }
 
 /*


More information about the svn-src-all mailing list