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);
-
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to