summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authormonthadar <monthadar@FreeBSD.org>2012-05-01 15:56:26 +0000
committermonthadar <monthadar@FreeBSD.org>2012-05-01 15:56:26 +0000
commit66eb02c1dc5e68076bf50a497792f81f047e74ea (patch)
tree7789c09019e4a96470216c276b33223cdf9db176 /sys/net80211
parent661f0aa0b474eeb0e2188d7c75ce16dbe34a0229 (diff)
downloadFreeBSD-src-66eb02c1dc5e68076bf50a497792f81f047e74ea.zip
FreeBSD-src-66eb02c1dc5e68076bf50a497792f81f047e74ea.tar.gz
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
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_hwmp.c184
-rw-r--r--sys/net80211/ieee80211_mesh.c229
-rw-r--r--sys/net80211/ieee80211_mesh.h19
-rw-r--r--sys/net80211/ieee80211_output.c115
4 files changed, 398 insertions, 149 deletions
diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c
index 3be6551..334399e 100644
--- a/sys/net80211/ieee80211_hwmp.c
+++ b/sys/net80211/ieee80211_hwmp.c
@@ -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))) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "reply to %6D", preq->preq_origaddr, ":");
+ 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)) {
/*
- * Build and send a PREP frame.
+ * 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 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_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 */;
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP for %6D, route is marked PROXY",
- 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);
- 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_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);
+ /* 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,
+ "unable to add PREP path to proxy %6D",
+ prep->prep_targetaddr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
}
- } 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++;
+ "%s path to %6D, hopcount %d:%d metric %d:%d",
+ rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+ "prefer" : "update",
+ 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;
diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c
index 3b0ff29..de844ab 100644
--- a/sys/net80211/ieee80211_mesh.c
+++ b/sys/net80211/ieee80211_mesh.c
@@ -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++;
@@ -980,9 +993,10 @@ mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
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 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,
@@ -1059,7 +1074,8 @@ mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
}
return m;
-#undef WDIR
+#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"));
@@ -1189,7 +1326,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
ni->ni_mlstate);
vap->iv_stats.is_mesh_nolink++;
goto out;
- }
+ }
if (dir != IEEE80211_FC1_DIR_FROMDS &&
dir != IEEE80211_FC1_DIR_DSTODS) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
@@ -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)
- goto out;
- /* NB: fall thru to deliver mcast frames locally */
- }
+ /* 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;
if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_rx(vap, m);
@@ -1382,6 +1540,9 @@ out:
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 \
diff --git a/sys/net80211/ieee80211_mesh.h b/sys/net80211/ieee80211_mesh.h
index 2d2631d..f28356e 100644
--- a/sys/net80211/ieee80211_mesh.h
+++ b/sys/net80211/ieee80211_mesh.h
@@ -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)
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 7723763..5afd8a1 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -254,7 +254,7 @@ ieee80211_start(struct ifnet *ifp)
if (!ieee80211_mesh_isproxyena(vap)) {
IEEE80211_DISCARD_MAC(vap,
IEEE80211_MSG_OUTPUT |
- IEEE80211_MSG_MESH,
+ IEEE80211_MSG_MESH,
eh->ether_dhost, NULL,
"%s", "proxy not enabled");
vap->iv_stats.is_mesh_notproxy++;
@@ -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 = IEEE80211_MESH_AE_00;
+ meshhdrsize =
+ sizeof(struct ieee80211_meshcntl);
+ }
} else {
- meshae = 2;
- meshhdrsize += 2*IEEE80211_ADDR_LEN;
+ 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;
- 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;
+ 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 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 @@ bad:
m_freem(m);
return NULL;
#undef WH4
+#undef MC01
}
/*
OpenPOWER on IntegriCloud