]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_hwmp.c
Change the hwmp debugging to use %6D rather than ether_sprintf().
[FreeBSD/FreeBSD.git] / sys / net80211 / 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 #include <sys/cdefs.h>
30 #ifdef __FreeBSD__
31 __FBSDID("$FreeBSD$");
32 #endif
33
34 /*
35  * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
36  *
37  * Based on March 2009, D3.0 802.11s draft spec.
38  */
39 #include "opt_inet.h"
40 #include "opt_wlan.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/mbuf.h>
45 #include <sys/malloc.h>
46 #include <sys/kernel.h>
47
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/endian.h>
51 #include <sys/errno.h>
52 #include <sys/proc.h>
53 #include <sys/sysctl.h>
54
55 #include <net/if.h>
56 #include <net/if_media.h>
57 #include <net/if_llc.h>
58 #include <net/ethernet.h>
59
60 #include <net/bpf.h>
61
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_action.h>
64 #include <net80211/ieee80211_input.h>
65 #include <net80211/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 static 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 = malloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP,
241             M_NOWAIT | M_ZERO);
242         if (hs == NULL) {
243                 printf("%s: couldn't alloc HWMP state\n", __func__);
244                 return;
245         }
246         hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
247         callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE);
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_drain(&hs->hs_roottimer);
257         free(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_drain(&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<%s> refcnt %d\n",
418             __func__, __LINE__,
419             ni, ether_sprintf(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), M_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_drain(&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         if (rtorig == NULL) {
711                 /* XXX stat */
712                 return;
713         }
714         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
715         /*
716          * Sequence number validation.
717          */
718         if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
719             HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
720                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
721                     "discard PREQ from %6D, old seq no %u <= %u",
722                     preq->preq_origaddr, ":",
723                     preq->preq_origseq, hrorig->hr_seq);
724                 return;
725         }
726         hrorig->hr_preqid = preq->preq_id;
727         hrorig->hr_seq = preq->preq_origseq;
728
729         /*
730          * Check if the PREQ is addressed to us.
731          */
732         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
733                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
734                     "reply to %6D", preq->preq_origaddr, ":");
735                 /*
736                  * Build and send a PREP frame.
737                  */
738                 prep.prep_flags = 0;
739                 prep.prep_hopcount = 0;
740                 prep.prep_ttl = ms->ms_ttl;
741                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
742                 prep.prep_targetseq = ++hs->hs_seq;
743                 prep.prep_lifetime = preq->preq_lifetime;
744                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
745                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
746                 prep.prep_origseq = preq->preq_origseq;
747                 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
748                 /*
749                  * Build the reverse path, if we don't have it already.
750                  */
751                 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
752                 if (rt == NULL)
753                         hwmp_discover(vap, preq->preq_origaddr, NULL);
754                 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
755                         hwmp_discover(vap, rt->rt_dest, NULL);
756                 return;
757         }
758         /*
759          * Proactive PREQ: reply with a proactive PREP to the
760          * root STA if requested.
761          */
762         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
763             (PREQ_TFLAGS(0) &
764             ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
765             (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
766                 uint8_t rootmac[IEEE80211_ADDR_LEN];
767
768                 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
769                 rt = ieee80211_mesh_rt_find(vap, rootmac);
770                 if (rt == NULL) {
771                         rt = ieee80211_mesh_rt_add(vap, rootmac);
772                         if (rt == NULL) {
773                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
774                                     "unable to add root mesh path to %6D",
775                                     rootmac, ":");
776                                 vap->iv_stats.is_mesh_rtaddfailed++;
777                                 return;
778                         }
779                 }
780                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
781                     "root mesh station @ %6D", rootmac, ":");
782
783                 /*
784                  * Reply with a PREP if we don't have a path to the root
785                  * or if the root sent us a proactive PREQ.
786                  */
787                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
788                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
789                         prep.prep_flags = 0;
790                         prep.prep_hopcount = 0;
791                         prep.prep_ttl = ms->ms_ttl;
792                         IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
793                         prep.prep_origseq = preq->preq_origseq;
794                         prep.prep_lifetime = preq->preq_lifetime;
795                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
796                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
797                             vap->iv_myaddr);
798                         prep.prep_targetseq = ++hs->hs_seq;
799                         hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
800                             broadcastaddr, &prep);
801                 }
802                 hwmp_discover(vap, rootmac, NULL);
803                 return;
804         }
805         rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
806
807         /*
808          * Forwarding and Intermediate reply for PREQs with 1 target.
809          */
810         if (preq->preq_tcount == 1) {
811                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
812
813                 memcpy(&ppreq, preq, sizeof(ppreq));
814                 /*
815                  * We have a valid route to this node.
816                  */
817                 if (rt != NULL &&
818                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
819                         if (preq->preq_ttl > 1 &&
820                             preq->preq_hopcount < hs->hs_maxhops) {
821                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
822                                     "forward PREQ from %6D",
823                                     preq->preq_origaddr, ":");
824                                 /*
825                                  * Propagate the original PREQ.
826                                  */
827                                 ppreq.preq_hopcount += 1;
828                                 ppreq.preq_ttl -= 1;
829                                 ppreq.preq_metric +=
830                                     ms->ms_pmetric->mpm_metric(ni);
831                                 /*
832                                  * Set TO and unset RF bits because we are going
833                                  * to send a PREP next.
834                                  */
835                                 ppreq.preq_targets[0].target_flags |=
836                                     IEEE80211_MESHPREQ_TFLAGS_TO;
837                                 ppreq.preq_targets[0].target_flags &=
838                                     ~IEEE80211_MESHPREQ_TFLAGS_RF;
839                                 hwmp_send_preq(ni, vap->iv_myaddr,
840                                     broadcastaddr, &ppreq);
841                         }
842                         /*
843                          * Check if we can send an intermediate Path Reply,
844                          * i.e., Target Only bit is not set.
845                          */
846                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
847                                 struct ieee80211_meshprep_ie prep;
848
849                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
850                                     "intermediate reply for PREQ from %6D",
851                                     preq->preq_origaddr, ":");
852                                 prep.prep_flags = 0;
853                                 prep.prep_hopcount = rt->rt_nhops + 1;
854                                 prep.prep_ttl = ms->ms_ttl;
855                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
856                                     PREQ_TADDR(0));
857                                 prep.prep_targetseq = hrorig->hr_seq;
858                                 prep.prep_lifetime = preq->preq_lifetime;
859                                 prep.prep_metric = rt->rt_metric +
860                                     ms->ms_pmetric->mpm_metric(ni);
861                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
862                                     preq->preq_origaddr);
863                                 prep.prep_origseq = hrorig->hr_seq;
864                                 hwmp_send_prep(ni, vap->iv_myaddr,
865                                     broadcastaddr, &prep);
866                         }
867                 /*
868                  * We have no information about this path,
869                  * propagate the PREQ.
870                  */
871                 } else if (preq->preq_ttl > 1 &&
872                     preq->preq_hopcount < hs->hs_maxhops) {
873                         if (rt == NULL) {
874                                 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
875                                 if (rt == NULL) {
876                                         IEEE80211_NOTE(vap,
877                                             IEEE80211_MSG_HWMP, ni,
878                                             "unable to add PREQ path to %6D",
879                                             PREQ_TADDR(0), ":");
880                                         vap->iv_stats.is_mesh_rtaddfailed++;
881                                         return;
882                                 }
883                         }
884                         rt->rt_metric = preq->preq_metric;
885                         rt->rt_lifetime = preq->preq_lifetime;
886                         hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
887                             struct ieee80211_hwmp_route);
888                         hrorig->hr_seq = preq->preq_origseq;
889                         hrorig->hr_preqid = preq->preq_id;
890
891                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
892                             "forward PREQ from %6D",
893                             preq->preq_origaddr, ":");
894                         ppreq.preq_hopcount += 1;
895                         ppreq.preq_ttl -= 1;
896                         ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
897                         hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
898                             &ppreq);
899                 }
900         }
901
902 }
903 #undef  PREQ_TFLAGS
904 #undef  PREQ_TADDR
905 #undef  PREQ_TSEQ
906
907 static int
908 hwmp_send_preq(struct ieee80211_node *ni,
909     const uint8_t sa[IEEE80211_ADDR_LEN],
910     const uint8_t da[IEEE80211_ADDR_LEN],
911     struct ieee80211_meshpreq_ie *preq)
912 {
913         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
914
915         /*
916          * Enforce PREQ interval.
917          */
918         if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
919                 return EALREADY;
920         getmicrouptime(&hs->hs_lastpreq);
921
922         /*
923          * mesh preq action frame format
924          *     [6] da
925          *     [6] sa 
926          *     [6] addr3 = sa
927          *     [1] action
928          *     [1] category
929          *     [tlv] mesh path request
930          */
931         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
932         return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
933             sizeof(struct ieee80211_meshpreq_ie));
934 }
935
936 static void
937 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
938     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
939 {
940         struct ieee80211_mesh_state *ms = vap->iv_mesh;
941         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
942         struct ieee80211_mesh_route *rt = NULL;
943         struct ieee80211_hwmp_route *hr;
944         struct ieee80211com *ic = vap->iv_ic;
945         struct ifnet *ifp = vap->iv_ifp;
946         struct mbuf *m, *next;
947
948         /*
949          * Acceptance criteria: if the corresponding PREQ was not generated
950          * by us and forwarding is disabled, discard this PREP.
951          */
952         if (ni == vap->iv_bss ||
953             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
954                 return;
955         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
956             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
957                 return;
958
959         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
960             "received PREP from %6D", prep->prep_targetaddr, ":");
961
962         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
963         if (rt == NULL) {
964                 /*
965                  * If we have no entry this could be a reply to a root PREQ.
966                  */
967                 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
968                         rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
969                         if (rt == NULL) {
970                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
971                                     ni, "unable to add PREP path to %6D",
972                                     prep->prep_targetaddr, ":");
973                                 vap->iv_stats.is_mesh_rtaddfailed++;
974                                 return;
975                         }
976                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
977                         rt->rt_nhops = prep->prep_hopcount;
978                         rt->rt_lifetime = prep->prep_lifetime;
979                         rt->rt_metric = prep->prep_metric;
980                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
981                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
982                             "add root path to %s nhops %d metric %d (PREP)",
983                             ether_sprintf(prep->prep_targetaddr),
984                             rt->rt_nhops, rt->rt_metric);
985                         return;
986                 } 
987                 return;
988         }
989         /*
990          * Sequence number validation.
991          */
992         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
993         if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
994                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
995                     "discard PREP from %6D, old seq no %u <= %u",
996                     prep->prep_targetaddr, ":",
997                     prep->prep_targetseq, hr->hr_seq);
998                 return;
999         }
1000         hr->hr_seq = prep->prep_targetseq;
1001         /*
1002          * If it's NOT for us, propagate the PREP.
1003          */
1004         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1005             prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
1006                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1007
1008                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1009                     "propagate PREP from %6D",
1010                     prep->prep_targetaddr, ":");
1011
1012                 memcpy(&pprep, prep, sizeof(pprep));
1013                 pprep.prep_hopcount += 1;
1014                 pprep.prep_ttl -= 1;
1015                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1016                 IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
1017                 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
1018         }
1019         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1020         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1021                 /* NB: never clobber a proxy entry */;
1022                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1023                     "discard PREP for %6D, route is marked PROXY",
1024                     prep->prep_targetaddr, ":");
1025                 vap->iv_stats.is_hwmp_proxy++;
1026         } else if (prep->prep_origseq == hr->hr_origseq) {
1027                 /*
1028                  * Check if we already have a path to this node.
1029                  * If we do, check if this path reply contains a
1030                  * better route.
1031                  */
1032                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1033                     (prep->prep_hopcount < rt->rt_nhops ||
1034                      prep->prep_metric < rt->rt_metric)) {
1035                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1036                             "%s path to %6D, hopcount %d:%d metric %d:%d",
1037                             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1038                                 "prefer" : "update",
1039                             prep->prep_origaddr, ":",
1040                             rt->rt_nhops, prep->prep_hopcount,
1041                             rt->rt_metric, prep->prep_metric);
1042                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
1043                         rt->rt_nhops = prep->prep_hopcount;
1044                         rt->rt_lifetime = prep->prep_lifetime;
1045                         rt->rt_metric = prep->prep_metric;
1046                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
1047                 } else {
1048                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1049                             "ignore PREP for %6D, hopcount %d:%d metric %d:%d",
1050                             prep->prep_targetaddr, ":",
1051                             rt->rt_nhops, prep->prep_hopcount,
1052                             rt->rt_metric, prep->prep_metric);
1053                 }
1054         } else {
1055                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1056                     "discard PREP for %s, wrong seqno %u != %u",
1057                     ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
1058                     hr->hr_seq);
1059                 vap->iv_stats.is_hwmp_wrongseq++;
1060         } 
1061         /*
1062          * Check for frames queued awaiting path discovery.
1063          * XXX probably can tell exactly and avoid remove call
1064          * NB: hash may have false matches, if so they will get
1065          *     stuck back on the stageq because there won't be
1066          *     a path.
1067          */
1068         m = ieee80211_ageq_remove(&ic->ic_stageq, 
1069             (struct ieee80211_node *)(uintptr_t)
1070                 ieee80211_mac_hash(ic, rt->rt_dest));
1071         for (; m != NULL; m = next) {
1072                 next = m->m_nextpkt;
1073                 m->m_nextpkt = NULL;
1074                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1075                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1076                 ifp->if_transmit(ifp, m);
1077         }
1078 }
1079
1080 static int
1081 hwmp_send_prep(struct ieee80211_node *ni,
1082     const uint8_t sa[IEEE80211_ADDR_LEN],
1083     const uint8_t da[IEEE80211_ADDR_LEN],
1084     struct ieee80211_meshprep_ie *prep)
1085 {
1086         /* NB: there's no PREP minimum interval. */
1087
1088         /*
1089          * mesh prep action frame format
1090          *     [6] da
1091          *     [6] sa 
1092          *     [6] addr3 = sa
1093          *     [1] action
1094          *     [1] category
1095          *     [tlv] mesh path reply
1096          */
1097         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1098         return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
1099             sizeof(struct ieee80211_meshprep_ie));
1100 }
1101
1102 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1103 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1104 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1105 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1106 static void
1107 hwmp_peerdown(struct ieee80211_node *ni)
1108 {
1109         struct ieee80211vap *vap = ni->ni_vap;
1110         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1111         struct ieee80211_meshperr_ie perr;
1112         struct ieee80211_mesh_route *rt;
1113         struct ieee80211_hwmp_route *hr;
1114
1115         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1116         if (rt == NULL)
1117                 return;
1118         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1119         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1120             "%s", "delete route entry");
1121         perr.perr_ttl = ms->ms_ttl;
1122         perr.perr_ndests = 1;
1123         PERR_DFLAGS(0) = 0;
1124         if (hr->hr_seq == 0)
1125                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1126         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1127         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1128         PERR_DSEQ(0) = hr->hr_seq;
1129         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1130         /* NB: flush everything passing through peer */
1131         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1132         hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
1133 }
1134 #undef  PERR_DFLAGS
1135 #undef  PERR_DADDR
1136 #undef  PERR_DSEQ
1137 #undef  PERR_DRCODE
1138
1139 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
1140 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
1141 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
1142 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
1143 static void
1144 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1145     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1146 {
1147         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1148         struct ieee80211_mesh_route *rt = NULL;
1149         struct ieee80211_hwmp_route *hr;
1150         struct ieee80211_meshperr_ie pperr;
1151         int i, forward = 0;
1152
1153         /*
1154          * Acceptance criteria: check if we received a PERR from a
1155          * neighbor and forwarding is enabled.
1156          */
1157         if (ni == vap->iv_bss ||
1158             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1159             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
1160                 return;
1161         /*
1162          * Find all routing entries that match and delete them.
1163          */
1164         for (i = 0; i < perr->perr_ndests; i++) {
1165                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1166                 if (rt == NULL)
1167                         continue;
1168                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1169                 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 
1170                     HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
1171                         ieee80211_mesh_rt_del(vap, rt->rt_dest);
1172                         ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
1173                         rt = NULL;
1174                         forward = 1;
1175                 }
1176         }
1177         /*
1178          * Propagate the PERR if we previously found it on our routing table.
1179          * XXX handle ndest > 1
1180          */
1181         if (forward && perr->perr_ttl > 1) {
1182                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1183                     "propagate PERR from %6D", wh->i_addr2, ":");
1184                 memcpy(&pperr, perr, sizeof(*perr));
1185                 pperr.perr_ttl--;
1186                 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
1187                     &pperr);
1188         }
1189 }
1190 #undef  PEER_DADDR
1191 #undef  PERR_DSEQ
1192
1193 static int
1194 hwmp_send_perr(struct ieee80211_node *ni,
1195     const uint8_t sa[IEEE80211_ADDR_LEN],
1196     const uint8_t da[IEEE80211_ADDR_LEN],
1197     struct ieee80211_meshperr_ie *perr)
1198 {
1199         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1200
1201         /*
1202          * Enforce PERR interval.
1203          */
1204         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1205                 return EALREADY;
1206         getmicrouptime(&hs->hs_lastperr);
1207
1208         /*
1209          * mesh perr action frame format
1210          *     [6] da
1211          *     [6] sa
1212          *     [6] addr3 = sa
1213          *     [1] action
1214          *     [1] category
1215          *     [tlv] mesh path error
1216          */
1217         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1218         return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
1219             sizeof(struct ieee80211_meshperr_ie));
1220 }
1221
1222 static void
1223 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1224     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1225 {
1226         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1227         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1228         struct ieee80211_mesh_route *rt = NULL;
1229         struct ieee80211_hwmp_route *hr;
1230         struct ieee80211_meshrann_ie prann;
1231
1232         if (ni == vap->iv_bss ||
1233             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1234             IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1235                 return;
1236
1237         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1238         /*
1239          * Discover the path to the root mesh STA.
1240          * If we already know it, propagate the RANN element.
1241          */
1242         if (rt == NULL) {
1243                 hwmp_discover(vap, rann->rann_addr, NULL);
1244                 return;
1245         }
1246         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1247         if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
1248                 hr->hr_seq = rann->rann_seq;
1249                 if (rann->rann_ttl > 1 &&
1250                     rann->rann_hopcount < hs->hs_maxhops &&
1251                     (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1252                         memcpy(&prann, rann, sizeof(prann));
1253                         prann.rann_hopcount += 1;
1254                         prann.rann_ttl -= 1;
1255                         prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1256                         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
1257                             broadcastaddr, &prann);
1258                 }
1259         }
1260 }
1261
1262 static int
1263 hwmp_send_rann(struct ieee80211_node *ni,
1264     const uint8_t sa[IEEE80211_ADDR_LEN],
1265     const uint8_t da[IEEE80211_ADDR_LEN],
1266     struct ieee80211_meshrann_ie *rann)
1267 {
1268         /*
1269          * mesh rann action frame format
1270          *     [6] da
1271          *     [6] sa 
1272          *     [6] addr3 = sa
1273          *     [1] action
1274          *     [1] category
1275          *     [tlv] root annoucement
1276          */
1277         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1278         return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
1279             sizeof(struct ieee80211_meshrann_ie));
1280 }
1281
1282 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1283 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1284 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1285 static struct ieee80211_node *
1286 hwmp_discover(struct ieee80211vap *vap,
1287     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1288 {
1289         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1290         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1291         struct ieee80211_mesh_route *rt = NULL;
1292         struct ieee80211_hwmp_route *hr;
1293         struct ieee80211_meshpreq_ie preq;
1294         struct ieee80211_node *ni;
1295         int sendpreq = 0;
1296
1297         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1298             ("not a mesh vap, opmode %d", vap->iv_opmode));
1299
1300         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1301             ("%s: discovering self!", __func__));
1302
1303         ni = NULL;
1304         if (!IEEE80211_IS_MULTICAST(dest)) {
1305                 rt = ieee80211_mesh_rt_find(vap, dest);
1306                 if (rt == NULL) {
1307                         rt = ieee80211_mesh_rt_add(vap, dest);
1308                         if (rt == NULL) {
1309                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1310                                     ni, "unable to add discovery path to %6D",
1311                                     dest, ":");
1312                                 vap->iv_stats.is_mesh_rtaddfailed++;
1313                                 goto done;
1314                         }
1315                 }
1316                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1317                     struct ieee80211_hwmp_route);
1318                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1319                         if (hr->hr_origseq == 0)
1320                                 hr->hr_origseq = ++hs->hs_seq;
1321                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1322                         rt->rt_lifetime =
1323                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1324                         /* XXX check preq retries */
1325                         sendpreq = 1;
1326                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1327                             "start path discovery (src %s)",
1328                             m == NULL ? "<none>" : ether_sprintf(
1329                                 mtod(m, struct ether_header *)->ether_shost));
1330                         /*
1331                          * Try to discover the path for this node.
1332                          */
1333                         preq.preq_flags = 0;
1334                         preq.preq_hopcount = 0;
1335                         preq.preq_ttl = ms->ms_ttl;
1336                         preq.preq_id = ++hs->hs_preqid;
1337                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1338                         preq.preq_origseq = hr->hr_origseq;
1339                         preq.preq_lifetime = rt->rt_lifetime;
1340                         preq.preq_metric = rt->rt_metric;
1341                         preq.preq_tcount = 1;
1342                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1343                         PREQ_TFLAGS(0) = 0;
1344                         if (ieee80211_hwmp_targetonly)
1345                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1346                         if (ieee80211_hwmp_replyforward)
1347                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
1348                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1349                         PREQ_TSEQ(0) = 0;
1350                         /* XXX check return value */
1351                         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
1352                             broadcastaddr, &preq);
1353                 }
1354                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
1355                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
1356         } else {
1357                 ni = ieee80211_find_txnode(vap, dest);
1358                 /* NB: if null then we leak mbuf */
1359                 KASSERT(ni != NULL, ("leak mcast frame"));
1360                 return ni;
1361         }
1362 done:
1363         if (ni == NULL && m != NULL) {
1364                 if (sendpreq) {
1365                         struct ieee80211com *ic = vap->iv_ic;
1366                         /*
1367                          * Queue packet for transmit when path discovery
1368                          * completes.  If discovery never completes the
1369                          * frame will be flushed by way of the aging timer.
1370                          */
1371                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1372                             "%s", "queue frame until path found");
1373                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
1374                             ieee80211_mac_hash(ic, dest);
1375                         /* XXX age chosen randomly */
1376                         ieee80211_ageq_append(&ic->ic_stageq, m,
1377                             IEEE80211_INACT_WAIT);
1378                 } else {
1379                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
1380                             dest, NULL, "%s", "no valid path to this node");
1381                         m_freem(m);
1382                 }
1383         }
1384         return ni;
1385 }
1386 #undef  PREQ_TFLAGS
1387 #undef  PREQ_TADDR
1388 #undef  PREQ_TSEQ
1389
1390 static int
1391 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1392 {
1393         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1394         int error;
1395  
1396         if (vap->iv_opmode != IEEE80211_M_MBSS)
1397                 return ENOSYS;
1398         error = 0;
1399         switch (ireq->i_type) {
1400         case IEEE80211_IOC_HWMP_ROOTMODE:
1401                 ireq->i_val = hs->hs_rootmode;
1402                 break;
1403         case IEEE80211_IOC_HWMP_MAXHOPS:
1404                 ireq->i_val = hs->hs_maxhops;
1405                 break;
1406         default:
1407                 return ENOSYS;
1408         }
1409         return error;
1410 }
1411 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
1412
1413 static int
1414 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1415 {
1416         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1417         int error;
1418
1419         if (vap->iv_opmode != IEEE80211_M_MBSS)
1420                 return ENOSYS;
1421         error = 0;
1422         switch (ireq->i_type) {
1423         case IEEE80211_IOC_HWMP_ROOTMODE:
1424                 if (ireq->i_val < 0 || ireq->i_val > 3)
1425                         return EINVAL;
1426                 hs->hs_rootmode = ireq->i_val;
1427                 hwmp_rootmode_setup(vap);
1428                 break;
1429         case IEEE80211_IOC_HWMP_MAXHOPS:
1430                 if (ireq->i_val <= 0 || ireq->i_val > 255)
1431                         return EINVAL;
1432                 hs->hs_maxhops = ireq->i_val;
1433                 break;
1434         default:
1435                 return ENOSYS;
1436         }
1437         return error;
1438 }
1439 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);