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