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:
parent
b79858dac6
commit
15254d455e
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user