1
0
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:
Monthadar Al Jaberi 2012-05-01 15:56:26 +00:00
parent b5df85a6fd
commit 3c314f6dc3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=234878
4 changed files with 398 additions and 149 deletions

View File

@ -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;

View File

@ -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 \

View File

@ -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)

View File

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