Index: projects/mesh11s/sys/net80211/ieee80211_hwmp.c =================================================================== --- projects/mesh11s/sys/net80211/ieee80211_hwmp.c (revision 192865) +++ projects/mesh11s/sys/net80211/ieee80211_hwmp.c (revision 192866) @@ -1,388 +1,435 @@ /*- * Copyright (c) 2009 The FreeBSD Foundation * All rights reserved. * * This software was developed by Rui Paulo under sponsorship from the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifdef __FreeBSD__ __FBSDID("$FreeBSD$"); #endif /* * IEEE 802.11s Hybrid Wireless Mesh Protocol. * * Based on March 2009, D3.0 802.11s draft spec. */ #include "opt_inet.h" #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * HWMP Forwarding Information table. */ struct ieee80211_hwmp_forwardinfo { TAILQ_ENTRY(ieee80211_hwmp_path) hp_list; uint8_t hp_target[IEEE80211_ADDR_LEN]; ieee80211_seq hp_seq; /* HWMP sequence number */ uint8_t hp_mnxthop[IEEE80211_ADDR_LEN]; uint32_t hp_metric; /* Path Metric */ uint32_t hp_nhops; /* Number of Hops */ /* XXX percursor list */ uint32_t hp_lifetime; }; static void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *, const struct ieee80211_meshpreq_ie *); static void hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *, const struct ieee80211_meshprep_ie *); static void hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *, const struct ieee80211_meshperr_ie *); static int ieee80211_hwmp_maxhops = 31; #ifdef notyet static int ieee80211_hwmp_maxhopstime = 500; static int ieee80211_hwmp_maxprepretries = 3; static int ieee80211_hwmp_prepminint = 100; static int ieee80211_hwmp_perrminint = 100; static int ieee80211_hwmp_roottimeout = 5000; static int ieee80211_hwmp_pathtimeout = 5000; static int ieee80211_hwmp_rootmode = 0; static int ieee80211_hwmp_pathtoroottimeout = 5000; static int ieee80211_hmwp_rootint = 2000; static int ieee80211_hwmp_rannint = 1000; #endif static int ieee80211_hwmp_targetonly = 1;/* reply to PREQs automatically */ static int ieee80211_hwmp_replyforward = 1; /* propagate PREQs */ #ifdef notyet static int ieee80211_hwmp_pathmaintenance = 2000; static int ieee80211_hwmp_confirmint = 2000; #endif /* * Target Address set in a Proactive PREQ. */ static const uint8_t proactiveaddr[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, "IEEE 802.11s HWMP parameters"); SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, maxhops, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_maxhops, 0, "Maximum number of hops for paths"); SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_targetonly, 0, "TBD"); SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_replyforward, 0, "TBD"); #ifdef notyet SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, rootmode, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_rootmode, 0, "Root Mesh Point Node"); #endif extern int ieee80211_mesh_ttl; extern int ieee80211_mesh_forwarding; void ieee80211_hwmp_recv_action(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m0) { struct ieee80211_frame *wh; struct ieee80211_action *ia; uint8_t *frm, *efrm; struct ieee80211_meshpreq_ie *meshpreq = NULL; struct ieee80211_meshprep_ie *meshprep = NULL; struct ieee80211_meshperr_ie *meshperr = NULL; wh = mtod(m0, struct ieee80211_frame *); ia = (struct ieee80211_action *) &wh[1]; frm = (uint8_t *)&wh[1] + sizeof(struct ieee80211_action); efrm = mtod(m0, uint8_t *) + m0->m_len; KASSERT(ia->ia_category == IEEE80211_ACTION_CAT_MESHPATH, ("wrong category")); while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); switch (*frm) { case IEEE80211_ELEMID_MESHPREQ: meshpreq = (struct ieee80211_meshpreq_ie *) frm; meshpreq->preq_id = LE_READ_4(&meshpreq->preq_id); meshpreq->preq_origseq = LE_READ_4(&meshpreq->preq_origseq); meshpreq->preq_lifetime = LE_READ_4(&meshpreq->preq_lifetime); meshpreq->preq_metric = LE_READ_4(&meshpreq->preq_metric); break; case IEEE80211_ELEMID_MESHPREP: meshprep = (struct ieee80211_meshprep_ie *) frm; meshprep->prep_targetseq = LE_READ_4(&meshprep->prep_targetseq); meshprep->prep_lifetime = LE_READ_4(&meshprep->prep_lifetime); meshprep->prep_metric = LE_READ_4(&meshprep->prep_metric); meshprep->prep_origseq = LE_READ_4(&meshprep->prep_origseq); break; case IEEE80211_ELEMID_MESHPERR: meshperr = (struct ieee80211_meshperr_ie *) frm; break; } frm += frm[1] + 2; } switch (ia->ia_action) { case IEEE80211_ACTION_MESHPATH_REQ: if (meshpreq == NULL) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, wh, NULL, "%s", "PREQ without IE"); vap->iv_stats.is_rx_mgtdiscard++; return; } hwmp_recv_preq(vap, ni, meshpreq); break; case IEEE80211_ACTION_MESHPATH_REP: if (meshprep == NULL) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, wh, NULL, "%s", "PREP without IE"); vap->iv_stats.is_rx_mgtdiscard++; return; } hwmp_recv_prep(vap, ni, meshprep); break; case IEEE80211_ACTION_MESHPATH_ERR: if (meshperr == NULL) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, wh, NULL, "%s", "PERR without IE"); vap->iv_stats.is_rx_mgtdiscard++; return; } hwmp_recv_perr(vap, ni, meshperr); break; default: IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, ni->ni_macaddr, NULL, "unknown path action 0x%x", ia->ia_action); } } #define ADDWORD(frm, v) do { \ frm[0] = (v) & 0xff; \ frm[1] = ((v) >> 8) & 0xff; \ frm[2] = ((v) >> 16) & 0xff; \ frm[3] = ((v) >> 24) & 0xff; \ frm += 4; \ } while (0) /* * Add a Mesh Path Reply IE to a frame. */ uint8_t * ieee80211_add_meshprep(uint8_t *frm, struct ieee80211_meshprep_ie *prep) { *frm++ = IEEE80211_ELEMID_MESHPREP; *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2; *frm++ = prep->prep_flags; *frm++ = prep->prep_hopcount; *frm++ = prep->prep_ttl; IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6; ADDWORD(frm, prep->prep_targetseq); ADDWORD(frm, prep->prep_lifetime); ADDWORD(frm, prep->prep_metric); IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6; ADDWORD(frm, prep->prep_origseq); return frm; } #define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags #define PREQ_TADDR(n) preq->preq_targets[n].target_addr #define PREQ_TSEQ(n) preq->preq_targets[n].target_seq static void hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_meshpreq_ie *preq) { union ieee80211_send_action_args vargs; /* * Acceptance criteria: if the PREQ is not for us and * forwarding is disabled, discard this PREQ. */ if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) && !ieee80211_mesh_forwarding) return; /* * Step 1. Record the PREQ ID and the originator MAC address. */ /* * Step 2. */ /* * Step 3. Check if the PREQ is addressed to us. * XXX: check if this is part of a proxy address. */ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { struct ieee80211_meshprep_ie prep; /* * Build and send a PREP frame. */ prep.prep_flags = 0; prep.prep_hopcount = 0; prep.prep_ttl = ieee80211_mesh_ttl; IEEE80211_ADDR_COPY(prep.prep_targetaddr, preq->preq_targets[0].target_addr); prep.prep_targetseq = preq->preq_origseq; prep.prep_lifetime = preq->preq_lifetime; prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; IEEE80211_ADDR_COPY(prep.prep_origaddr, vap->iv_myaddr); /* XXX */ prep.prep_origseq = 1; vargs.ptrarg = &prep; - ieee80211_send_action(ni, - IEEE80211_ACTION_CAT_MESHPATH, - IEEE80211_ACTION_MESHPATH_REP, - vargs); + ieee80211_send_action(ni, IEEE80211_ACTION_CAT_MESHPATH, + IEEE80211_ACTION_MESHPATH_REP, vargs); return; } /* XXX: Step 4. Check for AE bit and update proxy information */ /* * Step 5. Intermediate reply: check if we have this path on our * table and the TO bit is unset. */ if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) { /* * XXX: Step 6. Update the percursor table */ } /* * XXX: Step 8. Proactive PREQ: reply with a proactive PREP to the * root STA if requested. */ if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), proactiveaddr) && (PREQ_TFLAGS(0) & ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) == (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) { /* * Does the root want a proactive PREP ? */ if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP) { } } } #undef PREQ_TFLAGS #undef PREQ_TADDR #undef PREQ_TSEQ static void hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_meshprep_ie *prep) { + union ieee80211_send_action_args vargs; + + /* + * Acceptance criteria: if the PREP was not generated by us and + * forwarding is disabled, discard this PREP. + */ + if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && + !ieee80211_mesh_forwarding) + return; + + /* + * Step 1: Update the Forwarding Information. + */ + + /* + * Step 2: If it's NOT for us, propagate the PREP if TTL is + * greater than 1. + */ + if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_targetaddr) && + prep->prep_ttl > 1) { + struct ieee80211_meshprep_ie pprep; /* propagated PREP */ + + memcpy(&pprep, prep, sizeof(pprep)); + pprep.prep_hopcount += 1; + pprep.prep_ttl -= 1; + pprep.prep_metric += ieee80211_airtime_calc(vap, ni); + IEEE80211_ADDR_COPY(pprep.prep_origaddr, vap->iv_myaddr); + pprep.prep_origseq = 1; /* XXX */ + + vargs.ptrarg = &pprep; + ieee80211_send_action(ni, IEEE80211_ACTION_CAT_MESHPATH, + IEEE80211_ACTION_MESHPATH_REQ, vargs); + + /* + * XXX: Step 5: update the precursor list. + */ + return; + } + + /* + * XXX: Step 3: If it's for us and the AE bit is set, update the + * proxy information table. + */ + + /* + * XXX: Step 4: If it's NOT for us and the AE bit is set, + * update the proxy information table. + */ + } static void hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_meshperr_ie *perr) { } static int hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) { int error; error = 0; switch (ireq->i_type) { #ifdef notyet case IEEE80211_IOC_HWMPFI: if (vap->iv_opmode != IEEE80211_M_MBSS) return EINVAL; #endif default: return ENOSYS; } return error; } IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211); static int hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) { int error; error = 0; switch (ireq->i_type) { #ifdef notyet case IEEE80211_IOC_HWMPFI: #endif default: return ENOSYS; } return error; } IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);