214c665407eae57d51273be00192f010b1b94478
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_hwmp.c
1 /*- 
2  * Copyright (c) 2009 The FreeBSD Foundation 
3  * All rights reserved. 
4  * 
5  * This software was developed by Rui Paulo under sponsorship from the
6  * FreeBSD Foundation. 
7  *  
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions 
10  * are met: 
11  * 1. Redistributions of source code must retain the above copyright 
12  *    notice, this list of conditions and the following disclaimer. 
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
27  * SUCH DAMAGE. 
28  *
29  * $FreeBSD: head/sys/net80211/ieee80211_hwmp.c 198581 2009-10-29 12:19:10Z rpaulo $
30  * $DragonFly$
31  */ 
32
33 /*
34  * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
35  * 
36  * Based on March 2009, D3.0 802.11s draft spec.
37  */
38 #include "opt_inet.h"
39 #include "opt_wlan.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h> 
43 #include <sys/mbuf.h>   
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/endian.h>
50 #include <sys/errno.h>
51 #include <sys/proc.h>
52 #include <sys/sysctl.h>
53
54 #include <net/if.h>
55 #include <net/if_media.h>
56 #include <net/if_llc.h>
57 #include <net/ethernet.h>
58 #include <net/route.h>
59
60 #include <net/bpf.h>
61
62 #include <netproto/802_11/ieee80211_var.h>
63 #include <netproto/802_11/ieee80211_action.h>
64 #include <netproto/802_11/ieee80211_input.h>
65 #include <netproto/802_11/ieee80211_mesh.h>
66
67 static void     hwmp_vattach(struct ieee80211vap *);
68 static void     hwmp_vdetach(struct ieee80211vap *);
69 static int      hwmp_newstate(struct ieee80211vap *,
70                     enum ieee80211_state, int);
71 static int      hwmp_send_action(struct ieee80211_node *,
72                     const uint8_t [IEEE80211_ADDR_LEN],
73                     const uint8_t [IEEE80211_ADDR_LEN],
74                     uint8_t *, size_t);
75 static uint8_t * hwmp_add_meshpreq(uint8_t *,
76                     const struct ieee80211_meshpreq_ie *);
77 static uint8_t * hwmp_add_meshprep(uint8_t *,
78                     const struct ieee80211_meshprep_ie *);
79 static uint8_t * hwmp_add_meshperr(uint8_t *,
80                     const struct ieee80211_meshperr_ie *);
81 static uint8_t * hwmp_add_meshrann(uint8_t *,
82                     const struct ieee80211_meshrann_ie *);
83 static void     hwmp_rootmode_setup(struct ieee80211vap *);
84 static void     hwmp_rootmode_cb(void *);
85 static void     hwmp_rootmode_rann_cb(void *);
86 static void     hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *,
87                     const struct ieee80211_frame *,
88                     const struct ieee80211_meshpreq_ie *);
89 static int      hwmp_send_preq(struct ieee80211_node *,
90                     const uint8_t [IEEE80211_ADDR_LEN],
91                     const uint8_t [IEEE80211_ADDR_LEN],
92                     struct ieee80211_meshpreq_ie *);
93 static void     hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *,
94                     const struct ieee80211_frame *,
95                     const struct ieee80211_meshprep_ie *);
96 static int      hwmp_send_prep(struct ieee80211_node *,
97                     const uint8_t [IEEE80211_ADDR_LEN],
98                     const uint8_t [IEEE80211_ADDR_LEN],
99                     struct ieee80211_meshprep_ie *);
100 static void     hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *,
101                     const struct ieee80211_frame *,
102                     const struct ieee80211_meshperr_ie *);
103 static int      hwmp_send_perr(struct ieee80211_node *,
104                     const uint8_t [IEEE80211_ADDR_LEN],
105                     const uint8_t [IEEE80211_ADDR_LEN],
106                     struct ieee80211_meshperr_ie *);
107 static void     hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *,
108                    const struct ieee80211_frame *,
109                    const struct ieee80211_meshrann_ie *);
110 static int      hwmp_send_rann(struct ieee80211_node *,
111                     const uint8_t [IEEE80211_ADDR_LEN],
112                     const uint8_t [IEEE80211_ADDR_LEN],
113                     struct ieee80211_meshrann_ie *);
114 static struct ieee80211_node *
115                 hwmp_discover(struct ieee80211vap *,
116                     const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *);
117 static void     hwmp_peerdown(struct ieee80211_node *);
118
119 static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
120 static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
121
122 /* unalligned little endian access */
123 #define LE_WRITE_2(p, v) do {                           \
124         ((uint8_t *)(p))[0] = (v) & 0xff;               \
125         ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;        \
126 } while (0)
127 #define LE_WRITE_4(p, v) do {                           \
128         ((uint8_t *)(p))[0] = (v) & 0xff;               \
129         ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;        \
130         ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff;       \
131         ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff;       \
132 } while (0)
133
134
135 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
136 static const uint8_t    broadcastaddr[IEEE80211_ADDR_LEN] =
137         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
138
139 typedef uint32_t ieee80211_hwmp_seq;
140 #define HWMP_SEQ_LT(a, b)       ((int32_t)((a)-(b)) < 0)
141 #define HWMP_SEQ_LEQ(a, b)      ((int32_t)((a)-(b)) <= 0)
142 #define HWMP_SEQ_GT(a, b)       ((int32_t)((a)-(b)) > 0)
143 #define HWMP_SEQ_GEQ(a, b)      ((int32_t)((a)-(b)) >= 0)
144
145 /*
146  * Private extension of ieee80211_mesh_route.
147  */
148 struct ieee80211_hwmp_route {
149         ieee80211_hwmp_seq      hr_seq;         /* last HWMP seq seen from dst*/
150         ieee80211_hwmp_seq      hr_preqid;      /* last PREQ ID seen from dst */
151         ieee80211_hwmp_seq      hr_origseq;     /* seq. no. on our latest PREQ*/
152         int                     hr_preqretries;
153 };
154 struct ieee80211_hwmp_state {
155         ieee80211_hwmp_seq      hs_seq;         /* next seq to be used */
156         ieee80211_hwmp_seq      hs_preqid;      /* next PREQ ID to be used */
157         struct timeval          hs_lastpreq;    /* last time we sent a PREQ */
158         struct timeval          hs_lastperr;    /* last time we sent a PERR */
159         int                     hs_rootmode;    /* proactive HWMP */
160         struct callout          hs_roottimer;
161         uint8_t                 hs_maxhops;     /* max hop count */
162 };
163
164 SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0,
165     "IEEE 802.11s HWMP parameters");
166 static int      ieee80211_hwmp_targetonly = 0;
167 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW,
168     &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
169 static int      ieee80211_hwmp_replyforward = 1;
170 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW,
171     &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs");
172 static int      ieee80211_hwmp_pathtimeout = -1;
173 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW,
174     &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
175     "path entry lifetime (ms)");
176 static int      ieee80211_hwmp_roottimeout = -1;
177 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW,
178     &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
179     "root PREQ timeout (ms)");
180 static int      ieee80211_hwmp_rootint = -1;
181 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW,
182     &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I",
183     "root interval (ms)");
184 static int      ieee80211_hwmp_rannint = -1;
185 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
186     &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I",
187     "root announcement interval (ms)");
188
189 #define IEEE80211_HWMP_DEFAULT_MAXHOPS  31
190
191 static  ieee80211_recv_action_func hwmp_recv_action_meshpath;
192
193 static struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
194         .mpp_descr      = "HWMP",
195         .mpp_ie         = IEEE80211_MESHCONF_PATH_HWMP,
196         .mpp_discover   = hwmp_discover,
197         .mpp_peerdown   = hwmp_peerdown,
198         .mpp_vattach    = hwmp_vattach,
199         .mpp_vdetach    = hwmp_vdetach,
200         .mpp_newstate   = hwmp_newstate,
201         .mpp_privlen    = sizeof(struct ieee80211_hwmp_route),
202 };
203 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW,
204         &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I",
205         "mesh route inactivity timeout (ms)");
206
207
208 static void
209 ieee80211_hwmp_init(void)
210 {
211         ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
212         ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
213         ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
214         ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
215
216         /*
217          * Register action frame handler.
218          */
219         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
220             IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath);
221
222         /* NB: default is 5 secs per spec */
223         mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
224
225         /*
226          * Register HWMP.
227          */
228         ieee80211_mesh_register_proto_path(&mesh_proto_hwmp);
229 }
230 SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL);
231
232 void
233 hwmp_vattach(struct ieee80211vap *vap)
234 {
235         struct ieee80211_hwmp_state *hs;
236
237         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
238             ("not a mesh vap, opmode %d", vap->iv_opmode));
239
240         hs = kmalloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP,
241             M_NOWAIT | M_ZERO);
242         if (hs == NULL) {
243                 kprintf("%s: couldn't alloc HWMP state\n", __func__);
244                 return;
245         }
246         hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
247         callout_init_mp(&hs->hs_roottimer);
248         vap->iv_hwmp = hs;
249 }
250
251 void
252 hwmp_vdetach(struct ieee80211vap *vap)
253 {
254         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
255
256         callout_stop(&hs->hs_roottimer);
257         kfree(vap->iv_hwmp, M_80211_VAP);
258         vap->iv_hwmp = NULL;
259
260
261 int
262 hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
263 {
264         enum ieee80211_state nstate = vap->iv_state;
265         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
266
267         IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
268             __func__, ieee80211_state_name[ostate],
269             ieee80211_state_name[nstate], arg);
270
271         if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
272                 callout_stop(&hs->hs_roottimer);
273         if (nstate == IEEE80211_S_RUN)
274                 hwmp_rootmode_setup(vap);
275         return 0;
276 }
277
278 static int
279 hwmp_recv_action_meshpath(struct ieee80211_node *ni,
280         const struct ieee80211_frame *wh,
281         const uint8_t *frm, const uint8_t *efrm)
282 {
283         struct ieee80211vap *vap = ni->ni_vap;
284         struct ieee80211_meshpreq_ie preq;
285         struct ieee80211_meshprep_ie prep;
286         struct ieee80211_meshperr_ie perr;
287         struct ieee80211_meshrann_ie rann;
288         const uint8_t *iefrm = frm + 2; /* action + code */
289         int found = 0;
290
291         while (efrm - iefrm > 1) {
292                 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
293                 switch (*iefrm) {
294                 case IEEE80211_ELEMID_MESHPREQ:
295                 {
296                         const struct ieee80211_meshpreq_ie *mpreq =
297                             (const struct ieee80211_meshpreq_ie *) iefrm;
298                         /* XXX > 1 target */
299                         if (mpreq->preq_len !=
300                             sizeof(struct ieee80211_meshpreq_ie) - 2) {
301                                 IEEE80211_DISCARD(vap,
302                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
303                                     wh, NULL, "%s", "PREQ with wrong len");
304                                 vap->iv_stats.is_rx_mgtdiscard++;
305                                 break;
306                         }
307                         memcpy(&preq, mpreq, sizeof(preq));
308                         preq.preq_id = LE_READ_4(&mpreq->preq_id);
309                         preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq);
310                         preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime);
311                         preq.preq_metric = LE_READ_4(&mpreq->preq_metric);
312                         preq.preq_targets[0].target_seq =
313                             LE_READ_4(&mpreq->preq_targets[0].target_seq);
314                         hwmp_recv_preq(vap, ni, wh, &preq);
315                         found++;
316                         break;  
317                 }
318                 case IEEE80211_ELEMID_MESHPREP:
319                 {
320                         const struct ieee80211_meshprep_ie *mprep =
321                             (const struct ieee80211_meshprep_ie *) iefrm;
322                         if (mprep->prep_len !=
323                             sizeof(struct ieee80211_meshprep_ie) - 2) {
324                                 IEEE80211_DISCARD(vap,
325                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
326                                     wh, NULL, "%s", "PREP with wrong len");
327                                 vap->iv_stats.is_rx_mgtdiscard++;
328                                 break;
329                         }
330                         memcpy(&prep, mprep, sizeof(prep));
331                         prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq);
332                         prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime);
333                         prep.prep_metric = LE_READ_4(&mprep->prep_metric);
334                         prep.prep_origseq = LE_READ_4(&mprep->prep_origseq);
335                         hwmp_recv_prep(vap, ni, wh, &prep);
336                         found++;
337                         break;
338                 }
339                 case IEEE80211_ELEMID_MESHPERR:
340                 {
341                         const struct ieee80211_meshperr_ie *mperr =
342                             (const struct ieee80211_meshperr_ie *) iefrm;
343                         /* XXX > 1 target */
344                         if (mperr->perr_len !=
345                             sizeof(struct ieee80211_meshperr_ie) - 2) {
346                                 IEEE80211_DISCARD(vap,
347                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
348                                     wh, NULL, "%s", "PERR with wrong len");
349                                 vap->iv_stats.is_rx_mgtdiscard++;
350                                 break;
351                         }
352                         memcpy(&perr, mperr, sizeof(perr));
353                         perr.perr_dests[0].dest_seq =
354                             LE_READ_4(&mperr->perr_dests[0].dest_seq);
355                         hwmp_recv_perr(vap, ni, wh, &perr);
356                         found++;
357                         break;
358                 }
359                 case IEEE80211_ELEMID_MESHRANN:
360                 {
361                         const struct ieee80211_meshrann_ie *mrann =
362                             (const struct ieee80211_meshrann_ie *) iefrm;
363                         if (mrann->rann_len !=
364                             sizeof(struct ieee80211_meshrann_ie) - 2) {
365                                 IEEE80211_DISCARD(vap,
366                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
367                                     wh, NULL, "%s", "RAN with wrong len");
368                                 vap->iv_stats.is_rx_mgtdiscard++;
369                                 return 1;
370                         }
371                         memcpy(&rann, mrann, sizeof(rann));
372                         rann.rann_seq = LE_READ_4(&mrann->rann_seq);
373                         rann.rann_metric = LE_READ_4(&mrann->rann_metric);
374                         hwmp_recv_rann(vap, ni, wh, &rann);
375                         found++;
376                         break;
377                 }
378                 }
379                 iefrm += iefrm[1] + 2;
380         }
381         if (!found) {
382                 IEEE80211_DISCARD(vap,
383                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
384                     wh, NULL, "%s", "PATH SEL action without IE");
385                 vap->iv_stats.is_rx_mgtdiscard++;
386         }
387         return 0;
388 }
389
390 static int
391 hwmp_send_action(struct ieee80211_node *ni,
392     const uint8_t sa[IEEE80211_ADDR_LEN],
393     const uint8_t da[IEEE80211_ADDR_LEN],
394     uint8_t *ie, size_t len)
395 {
396         struct ieee80211vap *vap = ni->ni_vap;
397         struct ieee80211com *ic = ni->ni_ic;
398         struct ieee80211_bpf_params params;
399         struct mbuf *m;
400         uint8_t *frm;
401
402         if (vap->iv_state == IEEE80211_S_CAC) {
403                 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
404                     "block %s frame in CAC state", "HWMP action");
405                 vap->iv_stats.is_tx_badstate++;
406                 return EIO;     /* XXX */
407         }
408
409         KASSERT(ni != NULL, ("null node"));
410         /*
411          * Hold a reference on the node so it doesn't go away until after
412          * the xmit is complete all the way in the driver.  On error we
413          * will remove our reference.
414          */
415 #ifdef IEEE80211_DEBUG_REFCNT
416         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
417             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n",
418             __func__, __LINE__,
419             ni, ni->ni_macaddr, ":",
420             ieee80211_node_refcnt(ni)+1);
421 #endif
422         ieee80211_ref_node(ni);
423
424         m = ieee80211_getmgtframe(&frm,
425             ic->ic_headroom + sizeof(struct ieee80211_frame),
426             sizeof(struct ieee80211_action) + len
427         );
428         if (m == NULL) {
429                 ieee80211_free_node(ni);
430                 vap->iv_stats.is_tx_nobuf++;
431                 return ENOMEM;
432         }
433         *frm++ = IEEE80211_ACTION_CAT_MESHPATH;
434         *frm++ = IEEE80211_ACTION_MESHPATH_SEL;
435         switch (*ie) {
436         case IEEE80211_ELEMID_MESHPREQ:
437                 frm = hwmp_add_meshpreq(frm,
438                     (struct ieee80211_meshpreq_ie *)ie);
439                 break;
440         case IEEE80211_ELEMID_MESHPREP:
441                 frm = hwmp_add_meshprep(frm,
442                     (struct ieee80211_meshprep_ie *)ie);
443                 break;
444         case IEEE80211_ELEMID_MESHPERR:
445                 frm = hwmp_add_meshperr(frm,
446                     (struct ieee80211_meshperr_ie *)ie);
447                 break;
448         case IEEE80211_ELEMID_MESHRANN:
449                 frm = hwmp_add_meshrann(frm,
450                     (struct ieee80211_meshrann_ie *)ie);
451                 break;
452         }
453
454         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
455         M_PREPEND(m, sizeof(struct ieee80211_frame), MB_DONTWAIT);
456         if (m == NULL) {
457                 ieee80211_free_node(ni);
458                 vap->iv_stats.is_tx_nobuf++;
459                 return ENOMEM;
460         }
461         ieee80211_send_setup(ni, m,
462             IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
463             IEEE80211_NONQOS_TID, sa, da, sa);
464
465         m->m_flags |= M_ENCAP;          /* mark encapsulated */
466         IEEE80211_NODE_STAT(ni, tx_mgmt);
467
468         memset(&params, 0, sizeof(params));
469         params.ibp_pri = WME_AC_VO;
470         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
471         if (IEEE80211_IS_MULTICAST(da))
472                 params.ibp_try0 = 1;
473         else
474                 params.ibp_try0 = ni->ni_txparms->maxretry;
475         params.ibp_power = ni->ni_txpower;
476         return ic->ic_raw_xmit(ni, m, &params);
477 }
478
479 #define ADDSHORT(frm, v) do {           \
480         frm[0] = (v) & 0xff;            \
481         frm[1] = (v) >> 8;              \
482         frm += 2;                       \
483 } while (0)
484 #define ADDWORD(frm, v) do {            \
485         LE_WRITE_4(frm, v);             \
486         frm += 4;                       \
487 } while (0)
488 /*
489  * Add a Mesh Path Request IE to a frame.
490  */
491 static uint8_t *
492 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
493 {
494         int i;
495
496         *frm++ = IEEE80211_ELEMID_MESHPREQ;
497         *frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 +
498             (preq->preq_tcount - 1) * sizeof(*preq->preq_targets);
499         *frm++ = preq->preq_flags;
500         *frm++ = preq->preq_hopcount;
501         *frm++ = preq->preq_ttl;
502         ADDWORD(frm, preq->preq_id);
503         IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
504         ADDWORD(frm, preq->preq_origseq);
505         ADDWORD(frm, preq->preq_lifetime);
506         ADDWORD(frm, preq->preq_metric);
507         *frm++ = preq->preq_tcount;
508         for (i = 0; i < preq->preq_tcount; i++) {
509                 *frm++ = preq->preq_targets[i].target_flags;
510                 IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr);
511                 frm += 6;
512                 ADDWORD(frm, preq->preq_targets[i].target_seq);
513         }
514         return frm;
515 }
516
517 /*
518  * Add a Mesh Path Reply IE to a frame.
519  */
520 static uint8_t *
521 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
522 {
523         *frm++ = IEEE80211_ELEMID_MESHPREP;
524         *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2;
525         *frm++ = prep->prep_flags;
526         *frm++ = prep->prep_hopcount;
527         *frm++ = prep->prep_ttl;
528         IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
529         ADDWORD(frm, prep->prep_targetseq);
530         ADDWORD(frm, prep->prep_lifetime);
531         ADDWORD(frm, prep->prep_metric);
532         IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
533         ADDWORD(frm, prep->prep_origseq);
534         return frm;
535 }
536
537 /*
538  * Add a Mesh Path Error IE to a frame.
539  */
540 static uint8_t *
541 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
542 {
543         int i;
544
545         *frm++ = IEEE80211_ELEMID_MESHPERR;
546         *frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 +
547             (perr->perr_ndests - 1) * sizeof(*perr->perr_dests);
548         *frm++ = perr->perr_ttl;
549         *frm++ = perr->perr_ndests;
550         for (i = 0; i < perr->perr_ndests; i++) {
551                 *frm++ = perr->perr_dests[i].dest_flags;
552                 IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
553                 frm += 6;
554                 ADDWORD(frm, perr->perr_dests[i].dest_seq);
555                 ADDSHORT(frm, perr->perr_dests[i].dest_rcode);
556         }
557         return frm;
558 }
559
560 /*
561  * Add a Root Annoucement IE to a frame.
562  */
563 static uint8_t *
564 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
565 {
566         *frm++ = IEEE80211_ELEMID_MESHRANN;
567         *frm++ = sizeof(struct ieee80211_meshrann_ie) - 2;
568         *frm++ = rann->rann_flags;
569         *frm++ = rann->rann_hopcount;
570         *frm++ = rann->rann_ttl;
571         IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
572         ADDWORD(frm, rann->rann_seq);
573         ADDWORD(frm, rann->rann_metric);
574         return frm;
575 }
576
577 static void
578 hwmp_rootmode_setup(struct ieee80211vap *vap)
579 {
580         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
581
582         switch (hs->hs_rootmode) {
583         case IEEE80211_HWMP_ROOTMODE_DISABLED:
584                 callout_stop(&hs->hs_roottimer);
585                 break;
586         case IEEE80211_HWMP_ROOTMODE_NORMAL:
587         case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
588                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
589                     hwmp_rootmode_cb, vap);
590                 break;
591         case IEEE80211_HWMP_ROOTMODE_RANN:
592                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
593                     hwmp_rootmode_rann_cb, vap);
594                 break;
595         }
596 }
597
598 /*
599  * Send a broadcast Path Request to find all nodes on the mesh. We are
600  * called when the vap is configured as a HWMP root node.
601  */
602 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
603 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
604 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
605 static void
606 hwmp_rootmode_cb(void *arg)
607 {
608         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
609         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
610         struct ieee80211_mesh_state *ms = vap->iv_mesh;
611         struct ieee80211_meshpreq_ie preq;
612
613         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
614             "%s", "send broadcast PREQ");
615
616         preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
617         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
618                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
619         if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
620                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
621         preq.preq_hopcount = 0;
622         preq.preq_ttl = ms->ms_ttl;
623         preq.preq_id = ++hs->hs_preqid;
624         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
625         preq.preq_origseq = ++hs->hs_seq;
626         preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout);
627         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
628         preq.preq_tcount = 1;
629         IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
630         PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
631             IEEE80211_MESHPREQ_TFLAGS_RF;
632         PREQ_TSEQ(0) = 0;
633         vap->iv_stats.is_hwmp_rootreqs++;
634         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
635         hwmp_rootmode_setup(vap);
636 }
637 #undef  PREQ_TFLAGS
638 #undef  PREQ_TADDR
639 #undef  PREQ_TSEQ
640
641 /*
642  * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
643  * called when the vap is configured as a HWMP RANN root node.
644  */
645 static void
646 hwmp_rootmode_rann_cb(void *arg)
647 {
648         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
649         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
650         struct ieee80211_mesh_state *ms = vap->iv_mesh;
651         struct ieee80211_meshrann_ie rann;
652
653         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
654             "%s", "send broadcast RANN");
655
656         rann.rann_flags = 0;
657         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
658                 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
659         rann.rann_hopcount = 0;
660         rann.rann_ttl = ms->ms_ttl;
661         IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
662         rann.rann_seq = ++hs->hs_seq;
663         rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
664
665         vap->iv_stats.is_hwmp_rootrann++;
666         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
667         hwmp_rootmode_setup(vap);
668 }
669
670 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
671 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
672 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
673 static void
674 hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
675     const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
676 {
677         struct ieee80211_mesh_state *ms = vap->iv_mesh;
678         struct ieee80211_mesh_route *rt = NULL;
679         struct ieee80211_mesh_route *rtorig = NULL;
680         struct ieee80211_hwmp_route *hrorig;
681         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
682         struct ieee80211_meshprep_ie prep;
683
684         if (ni == vap->iv_bss ||
685             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
686                 return;
687         /*
688          * Ignore PREQs from us. Could happen because someone forward it
689          * back to us.
690          */
691         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr))
692                 return;
693
694         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
695             "received PREQ, source %6D", preq->preq_origaddr, ":");
696
697         /*
698          * Acceptance criteria: if the PREQ is not for us and
699          * forwarding is disabled, discard this PREQ.
700          */
701         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) &&
702             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
703                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
704                     preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
705                 return;
706         }
707         rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
708         if (rtorig == NULL)
709                 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
710         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
711         /*
712          * Sequence number validation.
713          */
714         if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
715             HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
716                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
717                     "discard PREQ from %6D, old seq no %u <= %u",
718                     preq->preq_origaddr, ":",
719                     preq->preq_origseq, hrorig->hr_seq);
720                 return;
721         }
722         hrorig->hr_preqid = preq->preq_id;
723         hrorig->hr_seq = preq->preq_origseq;
724
725         /*
726          * Check if the PREQ is addressed to us.
727          */
728         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
729                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
730                     "reply to %6D", preq->preq_origaddr, ":");
731                 /*
732                  * Build and send a PREP frame.
733                  */
734                 prep.prep_flags = 0;
735                 prep.prep_hopcount = 0;
736                 prep.prep_ttl = ms->ms_ttl;
737                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
738                 prep.prep_targetseq = ++hs->hs_seq;
739                 prep.prep_lifetime = preq->preq_lifetime;
740                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
741                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
742                 prep.prep_origseq = preq->preq_origseq;
743                 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
744                 /*
745                  * Build the reverse path, if we don't have it already.
746                  */
747                 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
748                 if (rt == NULL)
749                         hwmp_discover(vap, preq->preq_origaddr, NULL);
750                 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
751                         hwmp_discover(vap, rt->rt_dest, NULL);
752                 return;
753         }
754         /*
755          * Proactive PREQ: reply with a proactive PREP to the
756          * root STA if requested.
757          */
758         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
759             (PREQ_TFLAGS(0) &
760             ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
761             (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
762                 uint8_t rootmac[IEEE80211_ADDR_LEN];
763
764                 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
765                 rt = ieee80211_mesh_rt_find(vap, rootmac);
766                 if (rt == NULL) {
767                         rt = ieee80211_mesh_rt_add(vap, rootmac);
768                         if (rt == NULL) {
769                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
770                                     "unable to add root mesh path to %6D",
771                                     rootmac, ":");
772                                 vap->iv_stats.is_mesh_rtaddfailed++;
773                                 return;
774                         }
775                 }
776                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
777                     "root mesh station @ %6D", rootmac, ":");
778
779                 /*
780                  * Reply with a PREP if we don't have a path to the root
781                  * or if the root sent us a proactive PREQ.
782                  */
783                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
784                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
785                         prep.prep_flags = 0;
786                         prep.prep_hopcount = 0;
787                         prep.prep_ttl = ms->ms_ttl;
788                         IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
789                         prep.prep_origseq = preq->preq_origseq;
790                         prep.prep_lifetime = preq->preq_lifetime;
791                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
792                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
793                             vap->iv_myaddr);
794                         prep.prep_targetseq = ++hs->hs_seq;
795                         hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
796                             broadcastaddr, &prep);
797                 }
798                 hwmp_discover(vap, rootmac, NULL);
799                 return;
800         }
801         rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
802
803         /*
804          * Forwarding and Intermediate reply for PREQs with 1 target.
805          */
806         if (preq->preq_tcount == 1) {
807                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
808
809                 memcpy(&ppreq, preq, sizeof(ppreq));
810                 /*
811                  * We have a valid route to this node.
812                  */
813                 if (rt != NULL &&
814                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
815                         if (preq->preq_ttl > 1 &&
816                             preq->preq_hopcount < hs->hs_maxhops) {
817                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
818                                     "forward PREQ from %6D",
819                                     preq->preq_origaddr, ":");
820                                 /*
821                                  * Propagate the original PREQ.
822                                  */
823                                 ppreq.preq_hopcount += 1;
824                                 ppreq.preq_ttl -= 1;
825                                 ppreq.preq_metric +=
826                                     ms->ms_pmetric->mpm_metric(ni);
827                                 /*
828                                  * Set TO and unset RF bits because we are going
829                                  * to send a PREP next.
830                                  */
831                                 ppreq.preq_targets[0].target_flags |=
832                                     IEEE80211_MESHPREQ_TFLAGS_TO;
833                                 ppreq.preq_targets[0].target_flags &=
834                                     ~IEEE80211_MESHPREQ_TFLAGS_RF;
835                                 hwmp_send_preq(ni, vap->iv_myaddr,
836                                     broadcastaddr, &ppreq);
837                         }
838                         /*
839                          * Check if we can send an intermediate Path Reply,
840                          * i.e., Target Only bit is not set.
841                          */
842                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
843                                 struct ieee80211_meshprep_ie prep;
844
845                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
846                                     "intermediate reply for PREQ from %6D",
847                                     preq->preq_origaddr, ":");
848                                 prep.prep_flags = 0;
849                                 prep.prep_hopcount = rt->rt_nhops + 1;
850                                 prep.prep_ttl = ms->ms_ttl;
851                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
852                                     PREQ_TADDR(0));
853                                 prep.prep_targetseq = hrorig->hr_seq;
854                                 prep.prep_lifetime = preq->preq_lifetime;
855                                 prep.prep_metric = rt->rt_metric +
856                                     ms->ms_pmetric->mpm_metric(ni);
857                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
858                                     preq->preq_origaddr);
859                                 prep.prep_origseq = hrorig->hr_seq;
860                                 hwmp_send_prep(ni, vap->iv_myaddr,
861                                     broadcastaddr, &prep);
862                         }
863                 /*
864                  * We have no information about this path,
865                  * propagate the PREQ.
866                  */
867                 } else if (preq->preq_ttl > 1 &&
868                     preq->preq_hopcount < hs->hs_maxhops) {
869                         if (rt == NULL) {
870                                 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
871                                 if (rt == NULL) {
872                                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
873                                             ni, "unable to add PREQ path to %6D",
874                                             PREQ_TADDR(0), ":");
875                                         vap->iv_stats.is_mesh_rtaddfailed++;
876                                         return;
877                                 }
878                         }
879                         rt->rt_metric = preq->preq_metric;
880                         rt->rt_lifetime = preq->preq_lifetime;
881                         hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
882                             struct ieee80211_hwmp_route);
883                         hrorig->hr_seq = preq->preq_origseq;
884                         hrorig->hr_preqid = preq->preq_id;
885
886                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
887                             "forward PREQ from %6D",
888                             preq->preq_origaddr, ":");
889                         ppreq.preq_hopcount += 1;
890                         ppreq.preq_ttl -= 1;
891                         ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
892                         hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
893                             &ppreq);
894                 }
895         }
896
897 }
898 #undef  PREQ_TFLAGS
899 #undef  PREQ_TADDR
900 #undef  PREQ_TSEQ
901
902 static int
903 hwmp_send_preq(struct ieee80211_node *ni,
904     const uint8_t sa[IEEE80211_ADDR_LEN],
905     const uint8_t da[IEEE80211_ADDR_LEN],
906     struct ieee80211_meshpreq_ie *preq)
907 {
908         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
909
910         /*
911          * Enforce PREQ interval.
912          */
913         if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
914                 return EALREADY;
915         getmicrouptime(&hs->hs_lastpreq);
916
917         /*
918          * mesh preq action frame format
919          *     [6] da
920          *     [6] sa 
921          *     [6] addr3 = sa
922          *     [1] action
923          *     [1] category
924          *     [tlv] mesh path request
925          */
926         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
927         return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
928             sizeof(struct ieee80211_meshpreq_ie));
929 }
930
931 static void
932 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
933     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
934 {
935         struct ieee80211_mesh_state *ms = vap->iv_mesh;
936         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
937         struct ieee80211_mesh_route *rt = NULL;
938         struct ieee80211_hwmp_route *hr;
939         struct ieee80211com *ic = vap->iv_ic;
940         struct ifnet *ifp = vap->iv_ifp;
941         struct mbuf *m, *next;
942
943         /*
944          * Acceptance criteria: if the corresponding PREQ was not generated
945          * by us and forwarding is disabled, discard this PREP.
946          */
947         if (ni == vap->iv_bss ||
948             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
949                 return;
950         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
951             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
952                 return;
953
954         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
955             "received PREP from %6D", prep->prep_targetaddr, ":");
956
957         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
958         if (rt == NULL) {
959                 /*
960                  * If we have no entry this could be a reply to a root PREQ.
961                  */
962                 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
963                         rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
964                         if (rt == NULL) {
965                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
966                                     ni, "unable to add PREP path to %6D",
967                                     prep->prep_targetaddr, ":");
968                                 vap->iv_stats.is_mesh_rtaddfailed++;
969                                 return;
970                         }
971                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
972                         rt->rt_nhops = prep->prep_hopcount;
973                         rt->rt_lifetime = prep->prep_lifetime;
974                         rt->rt_metric = prep->prep_metric;
975                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
976                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
977                             "add root path to %6D nhops %d metric %d (PREP)",
978                             prep->prep_targetaddr, ":", 
979                             rt->rt_nhops, rt->rt_metric);
980                         return;
981                 } 
982                 return;
983         }
984         /*
985          * Sequence number validation.
986          */
987         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
988         if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
989                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
990                     "discard PREP from %6D, old seq no %u <= %u",
991                     prep->prep_targetaddr, ":",
992                     prep->prep_targetseq, hr->hr_seq);
993                 return;
994         }
995         hr->hr_seq = prep->prep_targetseq;
996         /*
997          * If it's NOT for us, propagate the PREP.
998          */
999         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1000             prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
1001                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1002
1003                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1004                     "propagate PREP from %6D",
1005                     prep->prep_targetaddr, ":");
1006
1007                 memcpy(&pprep, prep, sizeof(pprep));
1008                 pprep.prep_hopcount += 1;
1009                 pprep.prep_ttl -= 1;
1010                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1011                 IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
1012                 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
1013         }
1014         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1015         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1016                 /* NB: never clobber a proxy entry */;
1017                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1018                     "discard PREP for %6D, route is marked PROXY",
1019                     prep->prep_targetaddr, ":");
1020                 vap->iv_stats.is_hwmp_proxy++;
1021         } else if (prep->prep_origseq == hr->hr_origseq) {
1022                 /*
1023                  * Check if we already have a path to this node.
1024                  * If we do, check if this path reply contains a
1025                  * better route.
1026                  */
1027                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1028                     (prep->prep_hopcount < rt->rt_nhops ||
1029                      prep->prep_metric < rt->rt_metric)) {
1030                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1031                             "%s path to %6D, hopcount %d:%d metric %d:%d",
1032                             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1033                                 "prefer" : "update",
1034                             prep->prep_origaddr, ":",
1035                             rt->rt_nhops, prep->prep_hopcount,
1036                             rt->rt_metric, prep->prep_metric);
1037                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
1038                         rt->rt_nhops = prep->prep_hopcount;
1039                         rt->rt_lifetime = prep->prep_lifetime;
1040                         rt->rt_metric = prep->prep_metric;
1041                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
1042                 } else {
1043                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1044                             "ignore PREP for %6D, hopcount %d:%d metric %d:%d",
1045                             prep->prep_targetaddr, ":",
1046                             rt->rt_nhops, prep->prep_hopcount,
1047                             rt->rt_metric, prep->prep_metric);
1048                 }
1049         } else {
1050                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1051                     "discard PREP for %6D, wrong seqno %u != %u",
1052                     prep->prep_targetaddr, ":", prep->prep_origseq,
1053                     hr->hr_seq);
1054                 vap->iv_stats.is_hwmp_wrongseq++;
1055         } 
1056         /*
1057          * Check for frames queued awaiting path discovery.
1058          * XXX probably can tell exactly and avoid remove call
1059          * NB: hash may have false matches, if so they will get
1060          *     stuck back on the stageq because there won't be
1061          *     a path.
1062          */
1063         m = ieee80211_ageq_remove(&ic->ic_stageq, 
1064             (struct ieee80211_node *)(uintptr_t)
1065                 ieee80211_mac_hash(ic, rt->rt_dest));
1066         for (; m != NULL; m = next) {
1067                 next = m->m_nextpkt;
1068                 m->m_nextpkt = NULL;
1069                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1070                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1071                 ifp->if_transmit(ifp, m);
1072         }
1073 }
1074
1075 static int
1076 hwmp_send_prep(struct ieee80211_node *ni,
1077     const uint8_t sa[IEEE80211_ADDR_LEN],
1078     const uint8_t da[IEEE80211_ADDR_LEN],
1079     struct ieee80211_meshprep_ie *prep)
1080 {
1081         /* NB: there's no PREP minimum interval. */
1082
1083         /*
1084          * mesh prep action frame format
1085          *     [6] da
1086          *     [6] sa 
1087          *     [6] addr3 = sa
1088          *     [1] action
1089          *     [1] category
1090          *     [tlv] mesh path reply
1091          */
1092         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1093         return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
1094             sizeof(struct ieee80211_meshprep_ie));
1095 }
1096
1097 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1098 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1099 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1100 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1101 static void
1102 hwmp_peerdown(struct ieee80211_node *ni)
1103 {
1104         struct ieee80211vap *vap = ni->ni_vap;
1105         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1106         struct ieee80211_meshperr_ie perr;
1107         struct ieee80211_mesh_route *rt;
1108         struct ieee80211_hwmp_route *hr;
1109
1110         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1111         if (rt == NULL)
1112                 return;
1113         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1114         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1115             "%s", "delete route entry");
1116         perr.perr_ttl = ms->ms_ttl;
1117         perr.perr_ndests = 1;
1118         PERR_DFLAGS(0) = 0;
1119         if (hr->hr_seq == 0)
1120                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1121         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1122         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1123         PERR_DSEQ(0) = hr->hr_seq;
1124         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1125         /* NB: flush everything passing through peer */
1126         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1127         hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
1128 }
1129 #undef  PERR_DFLAGS
1130 #undef  PERR_DADDR
1131 #undef  PERR_DSEQ
1132 #undef  PERR_DRCODE
1133
1134 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
1135 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
1136 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
1137 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
1138 static void
1139 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1140     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1141 {
1142         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1143         struct ieee80211_mesh_route *rt = NULL;
1144         struct ieee80211_hwmp_route *hr;
1145         struct ieee80211_meshperr_ie pperr;
1146         int i, forward = 0;
1147
1148         /*
1149          * Acceptance criteria: check if we received a PERR from a
1150          * neighbor and forwarding is enabled.
1151          */
1152         if (ni == vap->iv_bss ||
1153             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1154             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
1155                 return;
1156         /*
1157          * Find all routing entries that match and delete them.
1158          */
1159         for (i = 0; i < perr->perr_ndests; i++) {
1160                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1161                 if (rt == NULL)
1162                         continue;
1163                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1164                 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 
1165                     HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
1166                         ieee80211_mesh_rt_del(vap, rt->rt_dest);
1167                         ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
1168                         rt = NULL;
1169                         forward = 1;
1170                 }
1171         }
1172         /*
1173          * Propagate the PERR if we previously found it on our routing table.
1174          * XXX handle ndest > 1
1175          */
1176         if (forward && perr->perr_ttl > 1) {
1177                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1178                     "propagate PERR from %6D", wh->i_addr2, ":");
1179                 memcpy(&pperr, perr, sizeof(*perr));
1180                 pperr.perr_ttl--;
1181                 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
1182                     &pperr);
1183         }
1184 }
1185 #undef  PEER_DADDR
1186 #undef  PERR_DSEQ
1187
1188 static int
1189 hwmp_send_perr(struct ieee80211_node *ni,
1190     const uint8_t sa[IEEE80211_ADDR_LEN],
1191     const uint8_t da[IEEE80211_ADDR_LEN],
1192     struct ieee80211_meshperr_ie *perr)
1193 {
1194         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1195
1196         /*
1197          * Enforce PERR interval.
1198          */
1199         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1200                 return EALREADY;
1201         getmicrouptime(&hs->hs_lastperr);
1202
1203         /*
1204          * mesh perr action frame format
1205          *     [6] da
1206          *     [6] sa
1207          *     [6] addr3 = sa
1208          *     [1] action
1209          *     [1] category
1210          *     [tlv] mesh path error
1211          */
1212         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1213         return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
1214             sizeof(struct ieee80211_meshperr_ie));
1215 }
1216
1217 static void
1218 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1219     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1220 {
1221         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1222         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1223         struct ieee80211_mesh_route *rt = NULL;
1224         struct ieee80211_hwmp_route *hr;
1225         struct ieee80211_meshrann_ie prann;
1226
1227         if (ni == vap->iv_bss ||
1228             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1229             IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1230                 return;
1231
1232         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1233         /*
1234          * Discover the path to the root mesh STA.
1235          * If we already know it, propagate the RANN element.
1236          */
1237         if (rt == NULL) {
1238                 hwmp_discover(vap, rann->rann_addr, NULL);
1239                 return;
1240         }
1241         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1242         if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
1243                 hr->hr_seq = rann->rann_seq;
1244                 if (rann->rann_ttl > 1 &&
1245                     rann->rann_hopcount < hs->hs_maxhops &&
1246                     (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1247                         memcpy(&prann, rann, sizeof(prann));
1248                         prann.rann_hopcount += 1;
1249                         prann.rann_ttl -= 1;
1250                         prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1251                         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
1252                             broadcastaddr, &prann);
1253                 }
1254         }
1255 }
1256
1257 static int
1258 hwmp_send_rann(struct ieee80211_node *ni,
1259     const uint8_t sa[IEEE80211_ADDR_LEN],
1260     const uint8_t da[IEEE80211_ADDR_LEN],
1261     struct ieee80211_meshrann_ie *rann)
1262 {
1263         /*
1264          * mesh rann action frame format
1265          *     [6] da
1266          *     [6] sa 
1267          *     [6] addr3 = sa
1268          *     [1] action
1269          *     [1] category
1270          *     [tlv] root annoucement
1271          */
1272         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1273         return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
1274             sizeof(struct ieee80211_meshrann_ie));
1275 }
1276
1277 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1278 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1279 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1280 static struct ieee80211_node *
1281 hwmp_discover(struct ieee80211vap *vap,
1282     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1283 {
1284         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1285         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1286         struct ieee80211_mesh_route *rt = NULL;
1287         struct ieee80211_hwmp_route *hr;
1288         struct ieee80211_meshpreq_ie preq;
1289         struct ieee80211_node *ni;
1290         int sendpreq = 0;
1291
1292         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1293             ("not a mesh vap, opmode %d", vap->iv_opmode));
1294
1295         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1296             ("%s: discovering self!", __func__));
1297
1298         ni = NULL;
1299         if (!IEEE80211_IS_MULTICAST(dest)) {
1300                 rt = ieee80211_mesh_rt_find(vap, dest);
1301                 if (rt == NULL) {
1302                         rt = ieee80211_mesh_rt_add(vap, dest);
1303                         if (rt == NULL) {
1304                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1305                                     ni, "unable to add discovery path to %6D",
1306                                     dest, ":");
1307                                 vap->iv_stats.is_mesh_rtaddfailed++;
1308                                 goto done;
1309                         }
1310                 }
1311                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1312                     struct ieee80211_hwmp_route);
1313                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1314                         if (hr->hr_origseq == 0)
1315                                 hr->hr_origseq = ++hs->hs_seq;
1316                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1317                         rt->rt_lifetime =
1318                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1319                         /* XXX check preq retries */
1320                         sendpreq = 1;
1321                         if (m != NULL) {
1322                                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
1323                                     dest, "%s",
1324                                     "start path discovery (src <none>)");
1325                         } else {
1326                                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
1327                                     dest,
1328                                     "start path discovery (src %6D)",
1329                                     mtod(m, struct ether_header *)->ether_shost,
1330                                     ":");
1331                         }
1332                         /*
1333                          * Try to discover the path for this node.
1334                          */
1335                         preq.preq_flags = 0;
1336                         preq.preq_hopcount = 0;
1337                         preq.preq_ttl = ms->ms_ttl;
1338                         preq.preq_id = ++hs->hs_preqid;
1339                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1340                         preq.preq_origseq = hr->hr_origseq;
1341                         preq.preq_lifetime = rt->rt_lifetime;
1342                         preq.preq_metric = rt->rt_metric;
1343                         preq.preq_tcount = 1;
1344                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1345                         PREQ_TFLAGS(0) = 0;
1346                         if (ieee80211_hwmp_targetonly)
1347                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1348                         if (ieee80211_hwmp_replyforward)
1349                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
1350                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1351                         PREQ_TSEQ(0) = 0;
1352                         /* XXX check return value */
1353                         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
1354                             broadcastaddr, &preq);
1355                 }
1356                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
1357                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
1358         } else {
1359                 ni = ieee80211_find_txnode(vap, dest);
1360                 /* NB: if null then we leak mbuf */
1361                 KASSERT(ni != NULL, ("leak mcast frame"));
1362                 return ni;
1363         }
1364 done:
1365         if (ni == NULL && m != NULL) {
1366                 if (sendpreq) {
1367                         struct ieee80211com *ic = vap->iv_ic;
1368                         /*
1369                          * Queue packet for transmit when path discovery
1370                          * completes.  If discovery never completes the
1371                          * frame will be flushed by way of the aging timer.
1372                          */
1373                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1374                             "%s", "queue frame until path found");
1375                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
1376                             ieee80211_mac_hash(ic, dest);
1377                         /* XXX age chosen randomly */
1378                         ieee80211_ageq_append(&ic->ic_stageq, m,
1379                             IEEE80211_INACT_WAIT);
1380                 } else {
1381                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
1382                             dest, NULL, "%s", "no valid path to this node");
1383                         m_freem(m);
1384                 }
1385         }
1386         return ni;
1387 }
1388 #undef  PREQ_TFLAGS
1389 #undef  PREQ_TADDR
1390 #undef  PREQ_TSEQ
1391
1392 static int
1393 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1394 {
1395         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1396         int error;
1397  
1398         if (vap->iv_opmode != IEEE80211_M_MBSS)
1399                 return ENOSYS;
1400         error = 0;
1401         switch (ireq->i_type) {
1402         case IEEE80211_IOC_HWMP_ROOTMODE:
1403                 ireq->i_val = hs->hs_rootmode;
1404                 break;
1405         case IEEE80211_IOC_HWMP_MAXHOPS:
1406                 ireq->i_val = hs->hs_maxhops;
1407                 break;
1408         default:
1409                 return ENOSYS;
1410         }
1411         return error;
1412 }
1413 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
1414
1415 static int
1416 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1417 {
1418         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1419         int error;
1420
1421         if (vap->iv_opmode != IEEE80211_M_MBSS)
1422                 return ENOSYS;
1423         error = 0;
1424         switch (ireq->i_type) {
1425         case IEEE80211_IOC_HWMP_ROOTMODE:
1426                 if (ireq->i_val < 0 || ireq->i_val > 3)
1427                         return EINVAL;
1428                 hs->hs_rootmode = ireq->i_val;
1429                 hwmp_rootmode_setup(vap);
1430                 break;
1431         case IEEE80211_IOC_HWMP_MAXHOPS:
1432                 if (ireq->i_val <= 0 || ireq->i_val > 255)
1433                         return EINVAL;
1434                 hs->hs_maxhops = ireq->i_val;
1435                 break;
1436         default:
1437                 return ENOSYS;
1438         }
1439         return error;
1440 }
1441 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);