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