mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-22 11:17:19 +00:00
Mesh forwarding with proxy support.
* Modified HWMP PREP/PREQ to contain a proxy entry and also changed PREP frame processing according to amendment as following: o Fixed PREP to always update/create if acceptance criteria is meet; o PREQ processing to reply if request is for a proxy entry that is proxied by us; o Removed hwmp_discover call from PREQ, because sending a PREP will build the forward path, and by receving and accepting a PREQ we have already built the reverse path (non-proactive code); * Disabled code for pro-active in PREP for now (will make a separate patch for pro-active HWMP routing later) * Added proxy information for a Mesh route, mesh gate to use and proxy seqno; * Modified ieee80211_encap according to amendment; * Introduced Mesh control address extension enum and removed unused struct, also rename some structure element names. * Modified mesh_input and added mesh_recv_* that should verify and process mesh data frames according to 9.32 Mesh forwarding framework in amendment; * Modified mesh_decap accordingly to changes done in mesh control AE struct; Approved by: adrian
This commit is contained in:
parent
b5df85a6fd
commit
3c314f6dc3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=234878
@ -143,6 +143,8 @@ typedef uint32_t ieee80211_hwmp_seq;
|
||||
#define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0)
|
||||
#define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
|
||||
|
||||
#define HWMP_SEQ_MAX(a, b) (a > b ? a : b)
|
||||
|
||||
/*
|
||||
* Private extension of ieee80211_mesh_route.
|
||||
*/
|
||||
@ -866,7 +868,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
|
||||
{
|
||||
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||
struct ieee80211_mesh_route *rt = NULL;
|
||||
struct ieee80211_mesh_route *rt = NULL; /* pro-active code */
|
||||
struct ieee80211_mesh_route *rtorig = NULL;
|
||||
struct ieee80211_mesh_route *rttarg = NULL;
|
||||
struct ieee80211_hwmp_route *hrorig = NULL;
|
||||
@ -963,31 +965,44 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
|
||||
/*
|
||||
* Check if the PREQ is addressed to us.
|
||||
* or a Proxy currently supplied by us.
|
||||
*/
|
||||
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
|
||||
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
|
||||
(rttarg != NULL &&
|
||||
rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
|
||||
rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
|
||||
/*
|
||||
* When we are the target we shall update our own HWMP seq
|
||||
* number with max of (current and preq->seq) + 1
|
||||
*/
|
||||
hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1;
|
||||
|
||||
prep.prep_flags = 0;
|
||||
if (rttarg != NULL && /* if NULL it means we are the target */
|
||||
rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"reply to %6D", preq->preq_origaddr, ":");
|
||||
"reply for proxy %6D", rttarg->rt_dest, ":");
|
||||
prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE;
|
||||
IEEE80211_ADDR_COPY(prep.prep_target_ext_addr,
|
||||
rttarg->rt_dest);
|
||||
/* update proxy seqno to HWMP seqno */
|
||||
rttarg->rt_ext_seq = hs->hs_seq;
|
||||
}
|
||||
/*
|
||||
* Build and send a PREP frame.
|
||||
*/
|
||||
prep.prep_flags = 0;
|
||||
prep.prep_hopcount = 0;
|
||||
prep.prep_ttl = ms->ms_ttl;
|
||||
IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
|
||||
prep.prep_targetseq = ++hs->hs_seq;
|
||||
prep.prep_targetseq = hs->hs_seq;
|
||||
prep.prep_lifetime = preq->preq_lifetime;
|
||||
prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
|
||||
IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
|
||||
prep.prep_origseq = preq->preq_origseq;
|
||||
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"reply to %6D", preq->preq_origaddr, ":");
|
||||
hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
|
||||
/*
|
||||
* Build the reverse path, if we don't have it already.
|
||||
*/
|
||||
rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
|
||||
if (rt == NULL)
|
||||
hwmp_discover(vap, preq->preq_origaddr, NULL);
|
||||
else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
|
||||
hwmp_discover(vap, rt->rt_dest, NULL);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@ -1179,15 +1194,19 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
|
||||
struct ieee80211_mesh_route *rt = NULL;
|
||||
struct ieee80211_mesh_route *rtorig = NULL;
|
||||
struct ieee80211_mesh_route *rtext = NULL;
|
||||
struct ieee80211_hwmp_route *hr;
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
struct ifnet *ifp = vap->iv_ifp;
|
||||
struct mbuf *m, *next;
|
||||
uint32_t metric = 0;
|
||||
const uint8_t *addr;
|
||||
|
||||
/*
|
||||
* Acceptance criteria: if the corresponding PREQ was not generated
|
||||
* by us and forwarding is disabled, discard this PREP.
|
||||
* Acceptance criteria: If the corresponding PREP was not generated
|
||||
* by us or generated by an external mac that is proxied by us
|
||||
* and forwarding is disabled, discard this PREP.
|
||||
*/
|
||||
if (ni == vap->iv_bss ||
|
||||
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
|
||||
@ -1195,10 +1214,21 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
|
||||
!(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
|
||||
return;
|
||||
rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
|
||||
if (rtorig != NULL &&
|
||||
!(rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"received PREP(%u) for an orig(%6D) not proxied by us",
|
||||
prep->prep_origseq, prep->prep_origaddr, ":");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PREP ACCEPTED */
|
||||
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"received PREP from %6D", prep->prep_targetaddr, ":");
|
||||
|
||||
#if 0
|
||||
rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
|
||||
if (rt == NULL) {
|
||||
/*
|
||||
@ -1228,10 +1258,30 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sequence number validation.
|
||||
* If accepted shall create or update the active forwarding information
|
||||
* it maintains for the target mesh STA of the PREP (according to the
|
||||
* rules defined in 13.10.8.4). If the conditions for creating or
|
||||
* updating the forwarding information have not been met in those
|
||||
* rules, no further steps are applied to the PREP.
|
||||
* [OPTIONAL]: update forwarding information to TA if metric improves.
|
||||
*/
|
||||
rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
|
||||
if (rt == NULL) {
|
||||
rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
|
||||
if (rt == NULL) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"unable to add PREP path to %6D",
|
||||
prep->prep_targetaddr, ":");
|
||||
vap->iv_stats.is_mesh_rtaddfailed++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
||||
/* update path metric */
|
||||
metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
|
||||
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
|
||||
if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
@ -1240,7 +1290,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
prep->prep_targetseq, hr->hr_seq);
|
||||
return;
|
||||
} else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) &&
|
||||
prep->prep_metric > rt->rt_metric) {
|
||||
metric > rt->rt_metric) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"discard PREP from %6D, new metric %u > %u",
|
||||
prep->prep_targetaddr, ":",
|
||||
@ -1249,7 +1299,21 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
}
|
||||
}
|
||||
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"%s path to %6D, hopcount %d:%d metric %d:%d",
|
||||
rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
|
||||
"prefer" : "update",
|
||||
prep->prep_targetaddr, ":",
|
||||
rt->rt_nhops, prep->prep_hopcount,
|
||||
rt->rt_metric, metric);
|
||||
|
||||
hr->hr_seq = prep->prep_targetseq;
|
||||
IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr);
|
||||
rt->rt_metric = metric;
|
||||
rt->rt_nhops = prep->prep_hopcount + 1;
|
||||
ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
|
||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */
|
||||
|
||||
/*
|
||||
* If it's NOT for us, propagate the PREP.
|
||||
*/
|
||||
@ -1265,53 +1329,45 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
pprep.prep_ttl -= 1;
|
||||
pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
|
||||
hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
|
||||
|
||||
/* may store target external address if recevied PREP w/ AE */
|
||||
/* precursor list for the Target Mesh STA Address is updated */
|
||||
}
|
||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
||||
if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
|
||||
/* NB: never clobber a proxy entry */;
|
||||
/* check if we received a PREP for a proxy address */
|
||||
else if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
|
||||
rtext = ieee80211_mesh_rt_find(vap,
|
||||
prep->prep_target_ext_addr);
|
||||
if (rtext == NULL) {
|
||||
rtext = ieee80211_mesh_rt_add(vap,
|
||||
prep->prep_target_ext_addr);
|
||||
if (rtext == NULL) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"discard PREP for %6D, route is marked PROXY",
|
||||
"unable to add PREP path to proxy %6D",
|
||||
prep->prep_targetaddr, ":");
|
||||
vap->iv_stats.is_hwmp_proxy++;
|
||||
/* NB: first path discovery always fails */
|
||||
} else if (hr->hr_origseq == 0 ||
|
||||
prep->prep_origseq == hr->hr_origseq) {
|
||||
/*
|
||||
* Check if we already have a path to this node.
|
||||
* If we do, check if this path reply contains a
|
||||
* better route.
|
||||
*/
|
||||
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
|
||||
(prep->prep_hopcount < rt->rt_nhops ||
|
||||
prep->prep_metric < rt->rt_metric)) {
|
||||
hr->hr_origseq = prep->prep_origseq;
|
||||
metric = prep->prep_metric +
|
||||
ms->ms_pmetric->mpm_metric(ni);
|
||||
vap->iv_stats.is_mesh_rtaddfailed++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"%s path to %6D, hopcount %d:%d metric %d:%d",
|
||||
rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
|
||||
rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
|
||||
"prefer" : "update",
|
||||
prep->prep_origaddr, ":",
|
||||
rt->rt_nhops, prep->prep_hopcount,
|
||||
rt->rt_metric, prep->prep_metric);
|
||||
IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
|
||||
rt->rt_nhops = prep->prep_hopcount + 1;
|
||||
ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
|
||||
rt->rt_metric = metric;
|
||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
|
||||
} else {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"ignore PREP for %6D, hopcount %d:%d metric %d:%d",
|
||||
prep->prep_targetaddr, ":",
|
||||
rt->rt_nhops, prep->prep_hopcount,
|
||||
rt->rt_metric, prep->prep_metric);
|
||||
}
|
||||
} else {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"discard PREP for %6D, wrong orig seqno %u != %u",
|
||||
prep->prep_targetaddr, ":", prep->prep_origseq,
|
||||
hr->hr_origseq);
|
||||
vap->iv_stats.is_hwmp_wrongseq++;
|
||||
prep->prep_target_ext_addr, ":",
|
||||
rtext->rt_nhops, prep->prep_hopcount,
|
||||
rtext->rt_metric, metric);
|
||||
|
||||
rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
|
||||
IEEE80211_MESHRT_FLAGS_VALID;
|
||||
IEEE80211_ADDR_COPY(rtext->rt_dest,
|
||||
prep->prep_target_ext_addr);
|
||||
IEEE80211_ADDR_COPY(rtext->rt_mesh_gate,
|
||||
prep->prep_targetaddr);
|
||||
IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2);
|
||||
rtext->rt_metric = metric;
|
||||
rtext->rt_lifetime = prep->prep_lifetime;
|
||||
rtext->rt_nhops = prep->prep_hopcount + 1;
|
||||
rtext->rt_ext_seq = prep->prep_origseq; /* proxy seq */
|
||||
/* proxy entries have no HWMP priv data, nullify them to be sure? */
|
||||
}
|
||||
/*
|
||||
* Check for frames queued awaiting path discovery.
|
||||
@ -1320,9 +1376,11 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
* stuck back on the stageq because there won't be
|
||||
* a path.
|
||||
*/
|
||||
addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
|
||||
prep->prep_target_ext_addr : prep->prep_targetaddr;
|
||||
m = ieee80211_ageq_remove(&ic->ic_stageq,
|
||||
(struct ieee80211_node *)(uintptr_t)
|
||||
ieee80211_mac_hash(ic, rt->rt_dest));
|
||||
ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */
|
||||
for (; m != NULL; m = next) {
|
||||
next = m->m_nextpkt;
|
||||
m->m_nextpkt = NULL;
|
||||
|
@ -284,12 +284,14 @@ ieee80211_mesh_proxy_check(struct ieee80211vap *vap,
|
||||
} else {
|
||||
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
|
||||
"%s", "add proxy entry");
|
||||
IEEE80211_ADDR_COPY(rt->rt_mesh_gate, vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
|
||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
|
||||
| IEEE80211_MESHRT_FLAGS_PROXY;
|
||||
}
|
||||
/* XXX assert PROXY? */
|
||||
} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
|
||||
KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
|
||||
("no proxy flag for poxy entry"));
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
/*
|
||||
* Fix existing entry created by received frames from
|
||||
@ -910,9 +912,14 @@ mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
|
||||
struct ieee80211_node *ni;
|
||||
int err;
|
||||
|
||||
if (mc->mc_ttl == 0) {
|
||||
/*
|
||||
* mesh ttl of 1 means we are the last one receving it,
|
||||
* according to amendment we decrement and then check if
|
||||
* 0, if so we dont forward.
|
||||
*/
|
||||
if (mc->mc_ttl < 1) {
|
||||
IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
|
||||
"%s", "frame not fwd'd, ttl 0");
|
||||
"%s", "frame not fwd'd, ttl 1");
|
||||
vap->iv_stats.is_mesh_fwd_ttl++;
|
||||
return;
|
||||
}
|
||||
@ -952,6 +959,12 @@ mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
|
||||
} else {
|
||||
ni = mesh_find_txnode(vap, whcopy->i_addr3);
|
||||
if (ni == NULL) {
|
||||
/*
|
||||
* [Optional] any of the following three actions:
|
||||
* o silently discard
|
||||
* o trigger a path discovery
|
||||
* o inform TA that meshDA is unreachable.
|
||||
*/
|
||||
IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
|
||||
"%s", "frame not fwd'd, no path");
|
||||
vap->iv_stats.is_mesh_fwd_nopath++;
|
||||
@ -981,8 +994,9 @@ static struct mbuf *
|
||||
mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
|
||||
{
|
||||
#define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
|
||||
#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
|
||||
uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
|
||||
sizeof(struct ieee80211_meshcntl_ae11)];
|
||||
sizeof(struct ieee80211_meshcntl_ae10)];
|
||||
const struct ieee80211_qosframe_addr4 *wh;
|
||||
const struct ieee80211_meshcntl_ae10 *mc;
|
||||
struct ether_header *eh;
|
||||
@ -1016,13 +1030,14 @@ mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
|
||||
m_adj(m, hdrlen - sizeof(*eh));
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
ae = mc->mc_flags & 3;
|
||||
ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
|
||||
if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
|
||||
if (ae == 0) {
|
||||
if (ae == IEEE80211_MESH_AE_00) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
|
||||
} else if (ae == 1) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
|
||||
} else if (ae == IEEE80211_MESH_AE_01) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost,
|
||||
MC01(mc)->mc_addr4);
|
||||
} else {
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
|
||||
(const struct ieee80211_frame *)wh, NULL,
|
||||
@ -1032,12 +1047,12 @@ mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (ae == 0) {
|
||||
if (ae == IEEE80211_MESH_AE_00) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
|
||||
} else if (ae == 2) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
|
||||
} else if (ae == IEEE80211_MESH_AE_10) {
|
||||
IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr5);
|
||||
IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr6);
|
||||
} else {
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
|
||||
(const struct ieee80211_frame *)wh, NULL,
|
||||
@ -1060,6 +1075,7 @@ mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
|
||||
}
|
||||
return m;
|
||||
#undef WDIR
|
||||
#undef MC01
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1075,12 +1091,13 @@ mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
|
||||
|
||||
KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
|
||||
("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
|
||||
KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
|
||||
if (ae == 2) { /* ucast w/ proxy */
|
||||
KASSERT(ae == IEEE80211_MESH_AE_00 || ae == IEEE80211_MESH_AE_10,
|
||||
("bad AE %d", ae));
|
||||
if (ae == IEEE80211_MESH_AE_10) { /* ucast w/ proxy */
|
||||
const struct ieee80211_meshcntl_ae10 *mc10 =
|
||||
(const struct ieee80211_meshcntl_ae10 *) mc;
|
||||
struct ieee80211_mesh_route *rt =
|
||||
ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
|
||||
ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
|
||||
/* check for proxy route to ourself */
|
||||
return (rt != NULL &&
|
||||
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
|
||||
@ -1088,19 +1105,139 @@ mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
|
||||
return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies transmitter, updates lifetime, precursor list and forwards data.
|
||||
* > 0 means we have forwarded data and no need to process locally
|
||||
* == 0 means we want to process locally (and we may have forwarded data
|
||||
* < 0 means there was an error and data should be discarded
|
||||
*/
|
||||
static int
|
||||
mesh_recv_indiv_data_to_fwrd(struct ieee80211vap *vap, struct mbuf *m,
|
||||
struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
|
||||
{
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* o verify addr2 is a legitimate transmitter
|
||||
* o set lifetime of addr3 to initial value
|
||||
* o set lifetime of addr4 to initial value
|
||||
* o lifetime of precursor of addr3 (addr2) is max(init, curr)
|
||||
* o lifetime of precursor of addr4 (nexthop) is max(init, curr)
|
||||
*/
|
||||
|
||||
mesh_forward(vap, m, mc);
|
||||
return (1); /* dont process locally */
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies transmitter, updates lifetime, precursor list and process data
|
||||
* locally, if data is is proxy with AE = 10 it could mean data should go
|
||||
* on another mesh path or data should be forwarded to the DS.
|
||||
*
|
||||
* > 0 means we have forwarded data and no need to process locally
|
||||
* == 0 means we want to process locally (and we may have forwarded data
|
||||
* < 0 means there was an error and data should be discarded
|
||||
*/
|
||||
static int
|
||||
mesh_recv_indiv_data_to_me(struct ieee80211vap *vap, struct mbuf *m,
|
||||
struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
|
||||
{
|
||||
struct ieee80211_qosframe_addr4 *qwh;
|
||||
const struct ieee80211_meshcntl_ae10 *mc10;
|
||||
struct ieee80211_mesh_route *rt;
|
||||
int ae;
|
||||
|
||||
qwh = (struct ieee80211_qosframe_addr4 *)wh;
|
||||
mc10 = (const struct ieee80211_meshcntl_ae10 *)mc;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* o verify addr2 is a legitimate transmitter
|
||||
* o set lifetime of addr4 to initial value
|
||||
* o lifetime of precursor entry is max(init, curr)
|
||||
*/
|
||||
|
||||
ae = mc10->mc_flags & IEEE80211_MESH_AE_MASK;
|
||||
KASSERT(ae == IEEE80211_MESH_AE_00 ||
|
||||
ae == IEEE80211_MESH_AE_10, ("bad AE %d", ae));
|
||||
if (ae == IEEE80211_MESH_AE_10) {
|
||||
if (IEEE80211_ADDR_EQ(mc10->mc_addr5, qwh->i_addr3)) {
|
||||
return (0); /* process locally */
|
||||
}
|
||||
|
||||
rt = ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
|
||||
if (rt != NULL &&
|
||||
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
|
||||
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) == 0) {
|
||||
/*
|
||||
* Forward on another mesh-path, according to
|
||||
* amendment as specified in 9.32.4.1
|
||||
*/
|
||||
IEEE80211_ADDR_COPY(qwh->i_addr3, mc10->mc_addr5);
|
||||
mesh_forward(vap, m,
|
||||
(const struct ieee80211_meshcntl *)mc10);
|
||||
return (1); /* dont process locally */
|
||||
}
|
||||
/*
|
||||
* All other cases: forward of MSDUs from the MBSS to DS indiv.
|
||||
* addressed according to 13.11.3.2.
|
||||
*/
|
||||
}
|
||||
return (0); /* process locally */
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to forward the group addressed data on to other mesh STAs, and
|
||||
* also to the DS.
|
||||
*
|
||||
* > 0 means we have forwarded data and no need to process locally
|
||||
* == 0 means we want to process locally (and we may have forwarded data
|
||||
* < 0 means there was an error and data should be discarded
|
||||
*/
|
||||
static int
|
||||
mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
|
||||
struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
|
||||
{
|
||||
#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
|
||||
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||
|
||||
mesh_forward(vap, m, mc);
|
||||
|
||||
if(mc->mc_ttl > 0) {
|
||||
if (mc->mc_flags & IEEE80211_MESH_AE_01) {
|
||||
/*
|
||||
* Forward of MSDUs from the MBSS to DS group addressed
|
||||
* (according to 13.11.3.2)
|
||||
* This happens by delivering the packet, and a bridge
|
||||
* will sent it on another port member.
|
||||
*/
|
||||
if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL &&
|
||||
ms->ms_flags & IEEE80211_MESHFLAGS_FWD)
|
||||
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH,
|
||||
MC01(mc)->mc_addr4, "%s",
|
||||
"forward from MBSS to the DS");
|
||||
}
|
||||
}
|
||||
return (0); /* process locally */
|
||||
#undef MC01
|
||||
}
|
||||
|
||||
static int
|
||||
mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
|
||||
{
|
||||
#define HAS_SEQ(type) ((type & 0x4) == 0)
|
||||
#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
|
||||
#define MC10(mc) ((const struct ieee80211_meshcntl_ae10 *)mc)
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct ieee80211com *ic = ni->ni_ic;
|
||||
struct ifnet *ifp = vap->iv_ifp;
|
||||
struct ieee80211_frame *wh;
|
||||
const struct ieee80211_meshcntl *mc;
|
||||
int hdrspace, meshdrlen, need_tap;
|
||||
uint8_t dir, type, subtype;
|
||||
int hdrspace, meshdrlen, need_tap, error;
|
||||
uint8_t dir, type, subtype, ae;
|
||||
uint32_t seq;
|
||||
uint8_t *addr, qos[2];
|
||||
const uint8_t *addr;
|
||||
uint8_t qos[2];
|
||||
ieee80211_seq rxseq;
|
||||
|
||||
KASSERT(ni != NULL, ("null node"));
|
||||
@ -1271,12 +1408,28 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
|
||||
*/
|
||||
mc = (const struct ieee80211_meshcntl *)
|
||||
(mtod(m, const uint8_t *) + hdrspace);
|
||||
ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
|
||||
meshdrlen = sizeof(struct ieee80211_meshcntl) +
|
||||
(mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
|
||||
ae * IEEE80211_ADDR_LEN;
|
||||
hdrspace += meshdrlen;
|
||||
|
||||
/* pull complete hdrspace = ieee80211_hdrspace + meshcontrol */
|
||||
if ((meshdrlen > sizeof(struct ieee80211_meshcntl)) &&
|
||||
(m->m_len < hdrspace) &&
|
||||
((m = m_pullup(m, hdrspace)) == NULL)) {
|
||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
|
||||
ni->ni_macaddr, NULL,
|
||||
"data too short: expecting %u", hdrspace);
|
||||
vap->iv_stats.is_rx_tooshort++;
|
||||
goto out; /* XXX */
|
||||
}
|
||||
/* XXX: are we sure there is no reallocating after m_pullup? */
|
||||
|
||||
seq = LE_READ_4(mc->mc_seq);
|
||||
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
|
||||
addr = wh->i_addr3;
|
||||
else if (ae == IEEE80211_MESH_AE_01)
|
||||
addr = MC01(mc)->mc_addr4;
|
||||
else
|
||||
addr = ((struct ieee80211_qosframe_addr4 *)wh)->i_addr4;
|
||||
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, addr)) {
|
||||
@ -1290,17 +1443,22 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Potentially forward packet. See table s36 (p140)
|
||||
* for the rules. XXX tap fwd'd packets not for us?
|
||||
*/
|
||||
if (dir == IEEE80211_FC1_DIR_FROMDS ||
|
||||
!mesh_isucastforme(vap, wh, mc)) {
|
||||
mesh_forward(vap, m, mc);
|
||||
if (dir == IEEE80211_FC1_DIR_DSTODS)
|
||||
/* This code "routes" the frame to the right control path */
|
||||
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
|
||||
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr3))
|
||||
error =
|
||||
mesh_recv_indiv_data_to_me(vap, m, wh, mc);
|
||||
else if (IEEE80211_IS_MULTICAST(wh->i_addr3))
|
||||
error = mesh_recv_group_data(vap, m, wh, mc);
|
||||
else
|
||||
error = mesh_recv_indiv_data_to_fwrd(vap, m,
|
||||
wh, mc);
|
||||
} else
|
||||
error = mesh_recv_group_data(vap, m, wh, mc);
|
||||
if (error < 0)
|
||||
goto err;
|
||||
else if (error > 0)
|
||||
goto out;
|
||||
/* NB: fall thru to deliver mcast frames locally */
|
||||
}
|
||||
|
||||
if (ieee80211_radiotap_active_vap(vap))
|
||||
ieee80211_radiotap_rx(vap, m);
|
||||
@ -1382,6 +1540,9 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
|
||||
m_freem(m);
|
||||
}
|
||||
return type;
|
||||
#undef HAS_SEQ
|
||||
#undef MC01
|
||||
#undef MC10
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2616,7 +2777,7 @@ ieee80211_add_meshpeer(uint8_t *frm, uint8_t subtype, uint16_t localid,
|
||||
*/
|
||||
#define IEEE80211_MESH_MAXOVERHEAD \
|
||||
(sizeof(struct ieee80211_qosframe_addr4) \
|
||||
+ sizeof(struct ieee80211_meshcntl_ae11) \
|
||||
+ sizeof(struct ieee80211_meshcntl_ae10) \
|
||||
+ sizeof(struct llc) \
|
||||
+ IEEE80211_ADDR_LEN \
|
||||
+ IEEE80211_WEP_IVLEN \
|
||||
|
@ -390,19 +390,18 @@ struct ieee80211_meshcntl_ae10 {
|
||||
uint8_t mc_flags; /* Address Extension 10 */
|
||||
uint8_t mc_ttl; /* TTL */
|
||||
uint8_t mc_seq[4]; /* Sequence No. */
|
||||
uint8_t mc_addr4[IEEE80211_ADDR_LEN];
|
||||
uint8_t mc_addr5[IEEE80211_ADDR_LEN];
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_meshcntl_ae11 {
|
||||
uint8_t mc_flags; /* Address Extension 11 */
|
||||
uint8_t mc_ttl; /* TTL */
|
||||
uint8_t mc_seq[4]; /* Sequence No. */
|
||||
uint8_t mc_addr4[IEEE80211_ADDR_LEN];
|
||||
uint8_t mc_addr5[IEEE80211_ADDR_LEN];
|
||||
uint8_t mc_addr6[IEEE80211_ADDR_LEN];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_MESH_AE_MASK 0x03
|
||||
enum {
|
||||
IEEE80211_MESH_AE_00 = 0, /* MC has no AE subfield */
|
||||
IEEE80211_MESH_AE_01 = 1, /* MC contain addr4 */
|
||||
IEEE80211_MESH_AE_10 = 2, /* MC contain addr5 & addr6 */
|
||||
IEEE80211_MESH_AE_11 = 3, /* RESERVED */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
MALLOC_DECLARE(M_80211_MESH_PREQ);
|
||||
MALLOC_DECLARE(M_80211_MESH_PREP);
|
||||
@ -423,6 +422,7 @@ struct ieee80211_mesh_route {
|
||||
struct mtx rt_lock; /* fine grained route lock */
|
||||
int rt_updtime; /* last update time */
|
||||
uint8_t rt_dest[IEEE80211_ADDR_LEN];
|
||||
uint8_t rt_mesh_gate[IEEE80211_ADDR_LEN]; /* meshDA */
|
||||
uint8_t rt_nexthop[IEEE80211_ADDR_LEN];
|
||||
uint32_t rt_metric; /* path metric */
|
||||
uint16_t rt_nhops; /* number of hops */
|
||||
@ -431,6 +431,7 @@ struct ieee80211_mesh_route {
|
||||
#define IEEE80211_MESHRT_FLAGS_PROXY 0x02 /* proxy entry */
|
||||
uint32_t rt_lifetime; /* route timeout */
|
||||
uint32_t rt_lastmseq; /* last seq# seen dest */
|
||||
uint32_t rt_ext_seq; /* proxy seq number */
|
||||
void *rt_priv; /* private data */
|
||||
};
|
||||
#define IEEE80211_MESH_ROUTE_PRIV(rt, cast) ((cast *)rt->rt_priv)
|
||||
|
@ -363,7 +363,6 @@ ieee80211_start(struct ifnet *ifp)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
error = parent->if_transmit(parent, m);
|
||||
if (error != 0) {
|
||||
/* NB: IFQ_HANDOFF reclaims mbuf */
|
||||
@ -556,7 +555,6 @@ ieee80211_send_setup(
|
||||
break;
|
||||
case IEEE80211_M_MBSS:
|
||||
#ifdef IEEE80211_SUPPORT_MESH
|
||||
/* XXX add support for proxied addresses */
|
||||
if (IEEE80211_IS_MULTICAST(da)) {
|
||||
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
|
||||
/* XXX next hop */
|
||||
@ -1016,10 +1014,13 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
struct mbuf *m)
|
||||
{
|
||||
#define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh))
|
||||
#define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc)
|
||||
struct ieee80211com *ic = ni->ni_ic;
|
||||
#ifdef IEEE80211_SUPPORT_MESH
|
||||
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||
struct ieee80211_meshcntl_ae10 *mc;
|
||||
struct ieee80211_mesh_route *rt = NULL;
|
||||
int dir = -1;
|
||||
#endif
|
||||
struct ether_header eh;
|
||||
struct ieee80211_frame *wh;
|
||||
@ -1100,21 +1101,40 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
* w/ 4-address format and address extension mode 10
|
||||
*/
|
||||
is4addr = 0; /* NB: don't use, disable */
|
||||
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
|
||||
hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */
|
||||
meshhdrsize = sizeof(struct ieee80211_meshcntl);
|
||||
/* XXX defines for AE modes */
|
||||
if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
|
||||
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
|
||||
meshae = 0;
|
||||
else
|
||||
meshae = 4; /* NB: pseudo */
|
||||
} else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
|
||||
meshae = 1;
|
||||
meshhdrsize += 1*IEEE80211_ADDR_LEN;
|
||||
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
|
||||
rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost);
|
||||
KASSERT(rt != NULL, ("route is NULL"));
|
||||
dir = IEEE80211_FC1_DIR_DSTODS;
|
||||
hdrsize += IEEE80211_ADDR_LEN;
|
||||
if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
|
||||
if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate,
|
||||
vap->iv_myaddr)) {
|
||||
IEEE80211_NOTE_MAC(vap,
|
||||
IEEE80211_MSG_MESH,
|
||||
eh.ether_dhost,
|
||||
"%s", "trying to send to ourself");
|
||||
goto bad;
|
||||
}
|
||||
meshae = IEEE80211_MESH_AE_10;
|
||||
meshhdrsize =
|
||||
sizeof(struct ieee80211_meshcntl_ae10);
|
||||
} else {
|
||||
meshae = 2;
|
||||
meshhdrsize += 2*IEEE80211_ADDR_LEN;
|
||||
meshae = IEEE80211_MESH_AE_00;
|
||||
meshhdrsize =
|
||||
sizeof(struct ieee80211_meshcntl);
|
||||
}
|
||||
} else {
|
||||
dir = IEEE80211_FC1_DIR_FROMDS;
|
||||
if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
|
||||
/* proxy group */
|
||||
meshae = IEEE80211_MESH_AE_01;
|
||||
meshhdrsize =
|
||||
sizeof(struct ieee80211_meshcntl_ae01);
|
||||
} else {
|
||||
/* group */
|
||||
meshae = IEEE80211_MESH_AE_00;
|
||||
meshhdrsize = sizeof(struct ieee80211_meshcntl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
@ -1215,44 +1235,52 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
/* NB: offset by hdrspace to deal with DATAPAD */
|
||||
mc = (struct ieee80211_meshcntl_ae10 *)
|
||||
(mtod(m, uint8_t *) + hdrspace);
|
||||
wh->i_fc[1] = dir;
|
||||
switch (meshae) {
|
||||
case 0: /* ucast, no proxy */
|
||||
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
|
||||
case IEEE80211_MESH_AE_00: /* no proxy */
|
||||
mc->mc_flags = 0;
|
||||
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
|
||||
if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1,
|
||||
ni->ni_macaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2,
|
||||
vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3,
|
||||
eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4,
|
||||
eh.ether_shost);
|
||||
qos =((struct ieee80211_qosframe_addr4 *)
|
||||
wh)->i_qos;
|
||||
} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
|
||||
/* mcast */
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1,
|
||||
eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2,
|
||||
vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3,
|
||||
eh.ether_shost);
|
||||
qos = ((struct ieee80211_qosframe *)
|
||||
wh)->i_qos;
|
||||
}
|
||||
break;
|
||||
case 4: /* mcast, no proxy */
|
||||
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
|
||||
mc->mc_flags = 0; /* NB: AE is really 0 */
|
||||
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
|
||||
break;
|
||||
case 1: /* mcast, proxy */
|
||||
case IEEE80211_MESH_AE_01: /* mcast, proxy */
|
||||
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
|
||||
mc->mc_flags = 1;
|
||||
IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost);
|
||||
IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4,
|
||||
eh.ether_shost);
|
||||
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
|
||||
break;
|
||||
case 2: /* ucast, proxy */
|
||||
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
|
||||
case IEEE80211_MESH_AE_10: /* ucast, proxy */
|
||||
KASSERT(rt != NULL, ("route is NULL"));
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
|
||||
/* XXX not right, need MeshDA */
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
|
||||
/* XXX assume are MeshSA */
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate);
|
||||
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
|
||||
mc->mc_flags = 2;
|
||||
IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost);
|
||||
mc->mc_flags = IEEE80211_MESH_AE_10;
|
||||
IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost);
|
||||
IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
|
||||
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
|
||||
break;
|
||||
default:
|
||||
@ -1363,6 +1391,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
#undef WH4
|
||||
#undef MC01
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user