Date: Tue, 1 May 2012 15:56:26 +0000 (UTC) From: Monthadar Al Jaberi <monthadar@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r234878 - head/sys/net80211 Message-ID: <201205011556.q41FuQP5032993@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: monthadar Date: Tue May 1 15:56:26 2012 New Revision: 234878 URL: http://svn.freebsd.org/changeset/base/234878 Log: 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 Modified: head/sys/net80211/ieee80211_hwmp.c head/sys/net80211/ieee80211_mesh.c head/sys/net80211/ieee80211_mesh.h head/sys/net80211/ieee80211_output.c Modified: head/sys/net80211/ieee80211_hwmp.c ============================================================================== --- head/sys/net80211/ieee80211_hwmp.c Tue May 1 15:47:30 2012 (r234877) +++ head/sys/net80211/ieee80211_hwmp.c Tue May 1 15:56:26 2012 (r234878) @@ -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, 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, /* * 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_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, 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, } 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, 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, } } + 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, 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, * 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; Modified: head/sys/net80211/ieee80211_mesh.c ============================================================================== --- head/sys/net80211/ieee80211_mesh.c Tue May 1 15:47:30 2012 (r234877) +++ head/sys/net80211/ieee80211_mesh.c Tue May 1 15:56:26 2012 (r234878) @@ -284,12 +284,14 @@ ieee80211_mesh_proxy_check(struct ieee80 } 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, s 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, s } 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, s 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, str 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, str 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, str 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 *v 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 *v 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, st 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, st */ 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, st 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, uin */ #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 \ Modified: head/sys/net80211/ieee80211_mesh.h ============================================================================== --- head/sys/net80211/ieee80211_mesh.h Tue May 1 15:47:30 2012 (r234877) +++ head/sys/net80211/ieee80211_mesh.h Tue May 1 15:56:26 2012 (r234878) @@ -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) Modified: head/sys/net80211/ieee80211_output.c ============================================================================== --- head/sys/net80211/ieee80211_output.c Tue May 1 15:47:30 2012 (r234877) +++ head/sys/net80211/ieee80211_output.c Tue May 1 15:56:26 2012 (r234878) @@ -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 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 * 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 /* 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 } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205011556.q41FuQP5032993>