diff options
author | monthadar <monthadar@FreeBSD.org> | 2012-05-01 15:56:26 +0000 |
---|---|---|
committer | monthadar <monthadar@FreeBSD.org> | 2012-05-01 15:56:26 +0000 |
commit | 66eb02c1dc5e68076bf50a497792f81f047e74ea (patch) | |
tree | 7789c09019e4a96470216c276b33223cdf9db176 /sys/net80211/ieee80211_mesh.c | |
parent | 661f0aa0b474eeb0e2188d7c75ce16dbe34a0229 (diff) | |
download | FreeBSD-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/ieee80211_mesh.c')
-rw-r--r-- | sys/net80211/ieee80211_mesh.c | 229 |
1 files changed, 195 insertions, 34 deletions
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 \ |