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
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to