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)
This commit is contained in:
Monthadar Al Jaberi 2013-02-07 21:26:06 +00:00
parent b79858dac6
commit 15254d455e

View File

@ -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);
}
/*