diff options
author | monthadar <monthadar@FreeBSD.org> | 2013-02-07 21:26:06 +0000 |
---|---|---|
committer | monthadar <monthadar@FreeBSD.org> | 2013-02-07 21:26:06 +0000 |
commit | 9cc12d2c5f7a100b44e6de96a1d195b962db14d3 (patch) | |
tree | 7b38b4c881fd04eb5e9800518c7cfd7c03c14eba /sys/net80211 | |
parent | 6bc4d326227cd340b42d20c050e4a27b9c41f2b2 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/net80211/ieee80211_mesh.c | 192 |
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); - } /* |