]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_hwmp.c
net80211 / ifconfig: cleanup the use of IEEE80211_FVHT_USEVHT*
[FreeBSD/FreeBSD.git] / sys / net80211 / ieee80211_hwmp.c
1 /*- 
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009 The FreeBSD Foundation 
5  * All rights reserved. 
6  * 
7  * This software was developed by Rui Paulo under sponsorship from the
8  * FreeBSD Foundation. 
9  *  
10  * Redistribution and use in source and binary forms, with or without 
11  * modification, are permitted provided that the following conditions 
12  * are met: 
13  * 1. Redistributions of source code must retain the above copyright 
14  *    notice, this list of conditions and the following disclaimer. 
15  * 2. Redistributions in binary form must reproduce the above copyright 
16  *    notice, this list of conditions and the following disclaimer in the 
17  *    documentation and/or other materials provided with the distribution. 
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
29  * SUCH DAMAGE. 
30  */ 
31 #include <sys/cdefs.h>
32 #ifdef __FreeBSD__
33 __FBSDID("$FreeBSD$");
34 #endif
35
36 /*
37  * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
38  *
39  * Based on March 2009, D3.0 802.11s draft spec.
40  */
41 #include "opt_inet.h"
42 #include "opt_wlan.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/mbuf.h>
47 #include <sys/malloc.h>
48 #include <sys/kernel.h>
49
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <sys/endian.h>
53 #include <sys/errno.h>
54 #include <sys/proc.h>
55 #include <sys/sysctl.h>
56
57 #include <net/if.h>
58 #include <net/if_media.h>
59 #include <net/if_llc.h>
60 #include <net/ethernet.h>
61
62 #include <net/bpf.h>
63
64 #include <net80211/ieee80211_var.h>
65 #include <net80211/ieee80211_action.h>
66 #include <net80211/ieee80211_input.h>
67 #include <net80211/ieee80211_mesh.h>
68
69 static void     hwmp_vattach(struct ieee80211vap *);
70 static void     hwmp_vdetach(struct ieee80211vap *);
71 static int      hwmp_newstate(struct ieee80211vap *,
72                     enum ieee80211_state, int);
73 static int      hwmp_send_action(struct ieee80211vap *,
74                     const uint8_t [IEEE80211_ADDR_LEN],
75                     uint8_t *, size_t);
76 static uint8_t * hwmp_add_meshpreq(uint8_t *,
77                     const struct ieee80211_meshpreq_ie *);
78 static uint8_t * hwmp_add_meshprep(uint8_t *,
79                     const struct ieee80211_meshprep_ie *);
80 static uint8_t * hwmp_add_meshperr(uint8_t *,
81                     const struct ieee80211_meshperr_ie *);
82 static uint8_t * hwmp_add_meshrann(uint8_t *,
83                     const struct ieee80211_meshrann_ie *);
84 static void     hwmp_rootmode_setup(struct ieee80211vap *);
85 static void     hwmp_rootmode_cb(void *);
86 static void     hwmp_rootmode_rann_cb(void *);
87 static void     hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *,
88                     const struct ieee80211_frame *,
89                     const struct ieee80211_meshpreq_ie *);
90 static int      hwmp_send_preq(struct ieee80211vap *,
91                     const uint8_t [IEEE80211_ADDR_LEN],
92                     struct ieee80211_meshpreq_ie *,
93                     struct timeval *, struct timeval *);
94 static void     hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *,
95                     const struct ieee80211_frame *,
96                     const struct ieee80211_meshprep_ie *);
97 static int      hwmp_send_prep(struct ieee80211vap *,
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 ieee80211vap *,
104                     const uint8_t [IEEE80211_ADDR_LEN],
105                     struct ieee80211_meshperr_ie *);
106 static void     hwmp_senderror(struct ieee80211vap *,
107                     const uint8_t [IEEE80211_ADDR_LEN],
108                     struct ieee80211_mesh_route *, int);
109 static void     hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *,
110                    const struct ieee80211_frame *,
111                    const struct ieee80211_meshrann_ie *);
112 static int      hwmp_send_rann(struct ieee80211vap *,
113                     const uint8_t [IEEE80211_ADDR_LEN],
114                     struct ieee80211_meshrann_ie *);
115 static struct ieee80211_node *
116                 hwmp_discover(struct ieee80211vap *,
117                     const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *);
118 static void     hwmp_peerdown(struct ieee80211_node *);
119
120 static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
121 static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
122
123
124 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
125 static const uint8_t    broadcastaddr[IEEE80211_ADDR_LEN] =
126         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
127
128 typedef uint32_t ieee80211_hwmp_seq;
129 #define HWMP_SEQ_LT(a, b)       ((int32_t)((a)-(b)) < 0)
130 #define HWMP_SEQ_LEQ(a, b)      ((int32_t)((a)-(b)) <= 0)
131 #define HWMP_SEQ_EQ(a, b)       ((int32_t)((a)-(b)) == 0)
132 #define HWMP_SEQ_GT(a, b)       ((int32_t)((a)-(b)) > 0)
133
134 #define HWMP_SEQ_MAX(a, b)      (a > b ? a : b)
135
136 /*
137  * Private extension of ieee80211_mesh_route.
138  */
139 struct ieee80211_hwmp_route {
140         ieee80211_hwmp_seq      hr_seq;         /* last HWMP seq seen from dst*/
141         ieee80211_hwmp_seq      hr_preqid;      /* last PREQ ID seen from dst */
142         ieee80211_hwmp_seq      hr_origseq;     /* seq. no. on our latest PREQ*/
143         struct timeval          hr_lastpreq;    /* last time we sent a PREQ */
144         struct timeval          hr_lastrootconf; /* last sent PREQ root conf */
145         int                     hr_preqretries; /* number of discoveries */
146         int                     hr_lastdiscovery; /* last discovery in ticks */
147 };
148 struct ieee80211_hwmp_state {
149         ieee80211_hwmp_seq      hs_seq;         /* next seq to be used */
150         ieee80211_hwmp_seq      hs_preqid;      /* next PREQ ID to be used */
151         int                     hs_rootmode;    /* proactive HWMP */
152         struct timeval          hs_lastperr;    /* last time we sent a PERR */
153         struct callout          hs_roottimer;
154         uint8_t                 hs_maxhops;     /* max hop count */
155 };
156
157 static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
158     "IEEE 802.11s HWMP parameters");
159 static int      ieee80211_hwmp_targetonly = 0;
160 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLFLAG_RW,
161     &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
162 static int      ieee80211_hwmp_pathtimeout = -1;
163 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime,
164     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
165     &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
166     "path entry lifetime (ms)");
167 static int      ieee80211_hwmp_maxpreq_retries = -1;
168 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, maxpreq_retries,
169     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
170     &ieee80211_hwmp_maxpreq_retries, 0, ieee80211_sysctl_msecs_ticks, "I",
171     "maximum number of preq retries");
172 static int      ieee80211_hwmp_net_diameter_traversaltime = -1;
173 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, net_diameter_traversal_time,
174     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
175     &ieee80211_hwmp_net_diameter_traversaltime, 0,
176     ieee80211_sysctl_msecs_ticks, "I",
177     "estimate travelse time across the MBSS (ms)");
178 static int      ieee80211_hwmp_roottimeout = -1;
179 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout,
180     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
181     &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
182     "root PREQ timeout (ms)");
183 static int      ieee80211_hwmp_rootint = -1;
184 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint,
185     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
186     &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I",
187     "root interval (ms)");
188 static int      ieee80211_hwmp_rannint = -1;
189 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint,
190     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
191     &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I",
192     "root announcement interval (ms)");
193 static struct timeval ieee80211_hwmp_rootconfint = { 0, 0 };
194 static int      ieee80211_hwmp_rootconfint_internal = -1;
195 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootconfint,
196     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
197     &ieee80211_hwmp_rootconfint_internal, 0, ieee80211_sysctl_msecs_ticks, "I",
198     "root confirmation interval (ms) (read-only)");
199
200 #define IEEE80211_HWMP_DEFAULT_MAXHOPS  31
201
202 static  ieee80211_recv_action_func hwmp_recv_action_meshpath;
203
204 static struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
205         .mpp_descr      = "HWMP",
206         .mpp_ie         = IEEE80211_MESHCONF_PATH_HWMP,
207         .mpp_discover   = hwmp_discover,
208         .mpp_peerdown   = hwmp_peerdown,
209         .mpp_senderror  = hwmp_senderror,
210         .mpp_vattach    = hwmp_vattach,
211         .mpp_vdetach    = hwmp_vdetach,
212         .mpp_newstate   = hwmp_newstate,
213         .mpp_privlen    = sizeof(struct ieee80211_hwmp_route),
214 };
215 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact,
216     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
217     &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I",
218     "mesh route inactivity timeout (ms)");
219
220
221 static void
222 ieee80211_hwmp_init(void)
223 {
224         /* Default values as per amendment */
225         ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
226         ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
227         ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
228         ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
229         ieee80211_hwmp_rootconfint_internal = msecs_to_ticks(2*1000);
230         ieee80211_hwmp_maxpreq_retries = 3;
231         /*
232          * (TU): A measurement of time equal to 1024 Î¼s,
233          * 500 TU is 512 ms.
234          */
235         ieee80211_hwmp_net_diameter_traversaltime = msecs_to_ticks(512);
236
237         /*
238          * NB: I dont know how to make SYSCTL_PROC that calls ms to ticks
239          * and return a struct timeval...
240          */
241         ieee80211_hwmp_rootconfint.tv_usec =
242             ieee80211_hwmp_rootconfint_internal * 1000;
243
244         /*
245          * Register action frame handler.
246          */
247         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
248             IEEE80211_ACTION_MESH_HWMP, hwmp_recv_action_meshpath);
249
250         /* NB: default is 5 secs per spec */
251         mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
252
253         /*
254          * Register HWMP.
255          */
256         ieee80211_mesh_register_proto_path(&mesh_proto_hwmp);
257 }
258 SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL);
259
260 static void
261 hwmp_vattach(struct ieee80211vap *vap)
262 {
263         struct ieee80211_hwmp_state *hs;
264
265         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
266             ("not a mesh vap, opmode %d", vap->iv_opmode));
267
268         hs = IEEE80211_MALLOC(sizeof(struct ieee80211_hwmp_state), M_80211_VAP,
269             IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
270         if (hs == NULL) {
271                 printf("%s: couldn't alloc HWMP state\n", __func__);
272                 return;
273         }
274         hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
275         callout_init(&hs->hs_roottimer, 1);
276         vap->iv_hwmp = hs;
277 }
278
279 static void
280 hwmp_vdetach(struct ieee80211vap *vap)
281 {
282         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
283
284         callout_drain(&hs->hs_roottimer);
285         IEEE80211_FREE(vap->iv_hwmp, M_80211_VAP);
286         vap->iv_hwmp = NULL;
287
288
289 static int
290 hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
291 {
292         enum ieee80211_state nstate = vap->iv_state;
293         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
294
295         IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
296             __func__, ieee80211_state_name[ostate],
297             ieee80211_state_name[nstate], arg);
298
299         if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
300                 callout_drain(&hs->hs_roottimer);
301         if (nstate == IEEE80211_S_RUN)
302                 hwmp_rootmode_setup(vap);
303         return 0;
304 }
305
306 /*
307  * Verify the length of an HWMP PREQ and return the number
308  * of destinations >= 1, if verification fails -1 is returned.
309  */
310 static int
311 verify_mesh_preq_len(struct ieee80211vap *vap,
312     const struct ieee80211_frame *wh, const uint8_t *iefrm)
313 {
314         int alloc_sz = -1;
315         int ndest = -1;
316         if (iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE) {
317                 /* Originator External Address  present */
318                 alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ_AE;
319                 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET_AE];
320         } else {
321                 /* w/o Originator External Address */
322                 alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ;
323                 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET];
324         }
325         alloc_sz += ndest * IEEE80211_MESHPREQ_TRGT_SZ;
326
327         if(iefrm[1] != (alloc_sz)) {
328                 IEEE80211_DISCARD(vap,
329                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
330                     wh, NULL, "PREQ (AE=%s) with wrong len",
331                     iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE ? "1" : "0");
332                 return (-1);
333         }
334         return ndest;
335 }
336
337 /*
338  * Verify the length of an HWMP PREP and returns 1 on success,
339  * otherwise -1.
340  */
341 static int
342 verify_mesh_prep_len(struct ieee80211vap *vap,
343     const struct ieee80211_frame *wh, const uint8_t *iefrm)
344 {
345         int alloc_sz = -1;
346         if (iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE) {
347                 if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ_AE)
348                         alloc_sz = IEEE80211_MESHPREP_BASE_SZ_AE;
349         } else if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ)
350                 alloc_sz = IEEE80211_MESHPREP_BASE_SZ;
351         if(alloc_sz < 0) {
352                 IEEE80211_DISCARD(vap,
353                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
354                     wh, NULL, "PREP (AE=%s) with wrong len",
355                     iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE ? "1" : "0");
356                 return (-1);
357         }
358         return (1);
359 }
360
361 /*
362  * Verify the length of an HWMP PERR and return the number
363  * of destinations >= 1, if verification fails -1 is returned.
364  */
365 static int
366 verify_mesh_perr_len(struct ieee80211vap *vap,
367     const struct ieee80211_frame *wh, const uint8_t *iefrm)
368 {
369         int alloc_sz = -1;
370         const uint8_t *iefrm_t = iefrm;
371         uint8_t ndest = iefrm_t[IEEE80211_MESHPERR_NDEST_OFFSET];
372         int i;
373
374         if(ndest > IEEE80211_MESHPERR_MAXDEST) {
375                 IEEE80211_DISCARD(vap,
376                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
377                     wh, NULL, "PERR with wrong number of destionat (>19), %u",
378                     ndest);
379                 return (-1);
380         }
381
382         iefrm_t += IEEE80211_MESHPERR_NDEST_OFFSET + 1; /* flag is next field */
383         /* We need to check each destionation flag to know size */
384         for(i = 0; i<ndest; i++) {
385                 if ((*iefrm_t) & IEEE80211_MESHPERR_FLAGS_AE)
386                         iefrm_t += IEEE80211_MESHPERR_DEST_SZ_AE;
387                 else
388                         iefrm_t += IEEE80211_MESHPERR_DEST_SZ;
389         }
390
391         alloc_sz = (iefrm_t - iefrm) - 2; /* action + code */
392         if(alloc_sz !=  iefrm[1]) {
393                 IEEE80211_DISCARD(vap,
394                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
395                     wh, NULL, "%s", "PERR with wrong len");
396                 return (-1);
397         }
398         return ndest;
399 }
400
401 static int
402 hwmp_recv_action_meshpath(struct ieee80211_node *ni,
403         const struct ieee80211_frame *wh,
404         const uint8_t *frm, const uint8_t *efrm)
405 {
406         struct ieee80211vap *vap = ni->ni_vap;
407         struct ieee80211_meshpreq_ie *preq;
408         struct ieee80211_meshprep_ie *prep;
409         struct ieee80211_meshperr_ie *perr;
410         struct ieee80211_meshrann_ie rann;
411         const uint8_t *iefrm = frm + 2; /* action + code */
412         const uint8_t *iefrm_t = iefrm; /* temporary pointer */
413         int ndest = -1;
414         int found = 0;
415
416         while (efrm - iefrm > 1) {
417                 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
418                 switch (*iefrm) {
419                 case IEEE80211_ELEMID_MESHPREQ:
420                 {
421                         int i = 0;
422
423                         iefrm_t = iefrm;
424                         ndest = verify_mesh_preq_len(vap, wh, iefrm_t);
425                         if (ndest < 0) {
426                                 vap->iv_stats.is_rx_mgtdiscard++;
427                                 break;
428                         }
429                         preq = IEEE80211_MALLOC(sizeof(*preq) +
430                             (ndest - 1) * sizeof(*preq->preq_targets),
431                             M_80211_MESH_PREQ,
432                             IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
433                         KASSERT(preq != NULL, ("preq == NULL"));
434
435                         preq->preq_ie = *iefrm_t++;
436                         preq->preq_len = *iefrm_t++;
437                         preq->preq_flags = *iefrm_t++;
438                         preq->preq_hopcount = *iefrm_t++;
439                         preq->preq_ttl = *iefrm_t++;
440                         preq->preq_id = le32dec(iefrm_t); iefrm_t += 4;
441                         IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm_t);
442                         iefrm_t += 6;
443                         preq->preq_origseq = le32dec(iefrm_t); iefrm_t += 4;
444                         /* NB: may have Originator Proxied Address */
445                         if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE)  {
446                                 IEEE80211_ADDR_COPY(
447                                     preq->preq_orig_ext_addr, iefrm_t);
448                                 iefrm_t += 6;
449                         }
450                         preq->preq_lifetime = le32dec(iefrm_t); iefrm_t += 4;
451                         preq->preq_metric = le32dec(iefrm_t); iefrm_t += 4;
452                         preq->preq_tcount = *iefrm_t++;
453                         
454                         for (i = 0; i < preq->preq_tcount; i++) {
455                                 preq->preq_targets[i].target_flags = *iefrm_t++;
456                                 IEEE80211_ADDR_COPY(
457                                     preq->preq_targets[i].target_addr, iefrm_t);
458                                 iefrm_t += 6;
459                                 preq->preq_targets[i].target_seq =
460                                     le32dec(iefrm_t);
461                                 iefrm_t += 4;
462                         }
463
464                         hwmp_recv_preq(vap, ni, wh, preq);
465                         IEEE80211_FREE(preq, M_80211_MESH_PREQ);
466                         found++;
467                         break;
468                 }
469                 case IEEE80211_ELEMID_MESHPREP:
470                 {
471                         iefrm_t = iefrm;
472                         ndest = verify_mesh_prep_len(vap, wh, iefrm_t);
473                         if (ndest < 0) {
474                                 vap->iv_stats.is_rx_mgtdiscard++;
475                                 break;
476                         }
477                         prep = IEEE80211_MALLOC(sizeof(*prep),
478                             M_80211_MESH_PREP,
479                             IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
480                         KASSERT(prep != NULL, ("prep == NULL"));
481
482                         prep->prep_ie = *iefrm_t++;
483                         prep->prep_len = *iefrm_t++;
484                         prep->prep_flags = *iefrm_t++;
485                         prep->prep_hopcount = *iefrm_t++;
486                         prep->prep_ttl = *iefrm_t++;
487                         IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm_t);
488                         iefrm_t += 6;
489                         prep->prep_targetseq = le32dec(iefrm_t); iefrm_t += 4;
490                         /* NB: May have Target Proxied Address */
491                         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE)  {
492                                 IEEE80211_ADDR_COPY(
493                                     prep->prep_target_ext_addr, iefrm_t);
494                                 iefrm_t += 6;
495                         }
496                         prep->prep_lifetime = le32dec(iefrm_t); iefrm_t += 4;
497                         prep->prep_metric = le32dec(iefrm_t); iefrm_t += 4;
498                         IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm_t);
499                         iefrm_t += 6;
500                         prep->prep_origseq = le32dec(iefrm_t); iefrm_t += 4;
501
502                         hwmp_recv_prep(vap, ni, wh, prep);
503                         IEEE80211_FREE(prep, M_80211_MESH_PREP);
504                         found++;
505                         break;
506                 }
507                 case IEEE80211_ELEMID_MESHPERR:
508                 {
509                         int i = 0;
510
511                         iefrm_t = iefrm;
512                         ndest = verify_mesh_perr_len(vap, wh, iefrm_t);
513                         if (ndest < 0) {
514                                 vap->iv_stats.is_rx_mgtdiscard++;
515                                 break;
516                         }
517                         perr = IEEE80211_MALLOC(sizeof(*perr) +
518                             (ndest - 1) * sizeof(*perr->perr_dests),
519                             M_80211_MESH_PERR,
520                             IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
521                         KASSERT(perr != NULL, ("perr == NULL"));
522
523                         perr->perr_ie = *iefrm_t++;
524                         perr->perr_len = *iefrm_t++;
525                         perr->perr_ttl = *iefrm_t++;
526                         perr->perr_ndests = *iefrm_t++;
527
528                         for (i = 0; i<perr->perr_ndests; i++) {
529                                 perr->perr_dests[i].dest_flags = *iefrm_t++;
530                                 IEEE80211_ADDR_COPY(
531                                     perr->perr_dests[i].dest_addr, iefrm_t);
532                                 iefrm_t += 6;
533                                 perr->perr_dests[i].dest_seq = le32dec(iefrm_t);
534                                 iefrm_t += 4;
535                                 /* NB: May have Target Proxied Address */
536                                 if (perr->perr_dests[i].dest_flags &
537                                     IEEE80211_MESHPERR_FLAGS_AE) {
538                                         IEEE80211_ADDR_COPY(
539                                             perr->perr_dests[i].dest_ext_addr,
540                                             iefrm_t);
541                                         iefrm_t += 6;
542                                 }
543                                 perr->perr_dests[i].dest_rcode =
544                                     le16dec(iefrm_t);
545                                 iefrm_t += 2;
546                         }
547
548                         hwmp_recv_perr(vap, ni, wh, perr);
549                         IEEE80211_FREE(perr, M_80211_MESH_PERR);
550                         found++;
551                         break;
552                 }
553                 case IEEE80211_ELEMID_MESHRANN:
554                 {
555                         const struct ieee80211_meshrann_ie *mrann =
556                             (const struct ieee80211_meshrann_ie *) iefrm;
557                         if (mrann->rann_len !=
558                             sizeof(struct ieee80211_meshrann_ie) - 2) {
559                                 IEEE80211_DISCARD(vap,
560                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
561                                     wh, NULL, "%s", "RAN with wrong len");
562                                     vap->iv_stats.is_rx_mgtdiscard++;
563                                 return 1;
564                         }
565                         memcpy(&rann, mrann, sizeof(rann));
566                         rann.rann_seq = le32dec(&mrann->rann_seq);
567                         rann.rann_interval = le32dec(&mrann->rann_interval);
568                         rann.rann_metric = le32dec(&mrann->rann_metric);
569                         hwmp_recv_rann(vap, ni, wh, &rann);
570                         found++;
571                         break;
572                 }
573                 }
574                 iefrm += iefrm[1] + 2;
575         }
576         if (!found) {
577                 IEEE80211_DISCARD(vap,
578                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
579                     wh, NULL, "%s", "PATH SEL action without IE");
580                 vap->iv_stats.is_rx_mgtdiscard++;
581         }
582         return 0;
583 }
584
585 static int
586 hwmp_send_action(struct ieee80211vap *vap,
587     const uint8_t da[IEEE80211_ADDR_LEN],
588     uint8_t *ie, size_t len)
589 {
590         struct ieee80211_node *ni;
591         struct ieee80211com *ic;
592         struct ieee80211_bpf_params params;
593         struct mbuf *m;
594         uint8_t *frm;
595         int ret;
596
597         if (IEEE80211_IS_MULTICAST(da)) {
598                 ni = ieee80211_ref_node(vap->iv_bss);
599 #ifdef IEEE80211_DEBUG_REFCNT
600                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
601                 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
602                 __func__, __LINE__,
603                 ni, ether_sprintf(ni->ni_macaddr),
604                 ieee80211_node_refcnt(ni)+1);
605 #endif
606                 ieee80211_ref_node(ni);
607         }
608         else
609                 ni = ieee80211_mesh_find_txnode(vap, da);
610
611         if (vap->iv_state == IEEE80211_S_CAC) {
612                 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
613                     "block %s frame in CAC state", "HWMP action");
614                 vap->iv_stats.is_tx_badstate++;
615                 return EIO;     /* XXX */
616         }
617
618         KASSERT(ni != NULL, ("null node"));
619         ic = ni->ni_ic;
620
621         m = ieee80211_getmgtframe(&frm,
622             ic->ic_headroom + sizeof(struct ieee80211_frame),
623             sizeof(struct ieee80211_action) + len
624         );
625         if (m == NULL) {
626                 ieee80211_free_node(ni);
627                 vap->iv_stats.is_tx_nobuf++;
628                 return ENOMEM;
629         }
630         *frm++ = IEEE80211_ACTION_CAT_MESH;
631         *frm++ = IEEE80211_ACTION_MESH_HWMP;
632         switch (*ie) {
633         case IEEE80211_ELEMID_MESHPREQ:
634                 frm = hwmp_add_meshpreq(frm,
635                     (struct ieee80211_meshpreq_ie *)ie);
636                 break;
637         case IEEE80211_ELEMID_MESHPREP:
638                 frm = hwmp_add_meshprep(frm,
639                     (struct ieee80211_meshprep_ie *)ie);
640                 break;
641         case IEEE80211_ELEMID_MESHPERR:
642                 frm = hwmp_add_meshperr(frm,
643                     (struct ieee80211_meshperr_ie *)ie);
644                 break;
645         case IEEE80211_ELEMID_MESHRANN:
646                 frm = hwmp_add_meshrann(frm,
647                     (struct ieee80211_meshrann_ie *)ie);
648                 break;
649         }
650
651         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
652         M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
653         if (m == NULL) {
654                 ieee80211_free_node(ni);
655                 vap->iv_stats.is_tx_nobuf++;
656                 return ENOMEM;
657         }
658
659         IEEE80211_TX_LOCK(ic);
660
661         ieee80211_send_setup(ni, m,
662             IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
663             IEEE80211_NONQOS_TID, vap->iv_myaddr, da, vap->iv_myaddr);
664
665         m->m_flags |= M_ENCAP;          /* mark encapsulated */
666         IEEE80211_NODE_STAT(ni, tx_mgmt);
667
668         memset(&params, 0, sizeof(params));
669         params.ibp_pri = WME_AC_VO;
670         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
671         if (IEEE80211_IS_MULTICAST(da))
672                 params.ibp_try0 = 1;
673         else
674                 params.ibp_try0 = ni->ni_txparms->maxretry;
675         params.ibp_power = ni->ni_txpower;
676         ret = ieee80211_raw_output(vap, ni, m, &params);
677         IEEE80211_TX_UNLOCK(ic);
678         return (ret);
679 }
680
681 #define ADDSHORT(frm, v) do {           \
682         le16enc(frm, v);                \
683         frm += 2;                       \
684 } while (0)
685 #define ADDWORD(frm, v) do {            \
686         le32enc(frm, v);                \
687         frm += 4;                       \
688 } while (0)
689 /*
690  * Add a Mesh Path Request IE to a frame.
691  */
692 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
693 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
694 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
695 static uint8_t *
696 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
697 {
698         int i;
699
700         *frm++ = IEEE80211_ELEMID_MESHPREQ;
701         *frm++ = preq->preq_len;        /* len already calculated */
702         *frm++ = preq->preq_flags;
703         *frm++ = preq->preq_hopcount;
704         *frm++ = preq->preq_ttl;
705         ADDWORD(frm, preq->preq_id);
706         IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
707         ADDWORD(frm, preq->preq_origseq);
708         if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
709                 IEEE80211_ADDR_COPY(frm, preq->preq_orig_ext_addr);
710                 frm += 6;
711         }
712         ADDWORD(frm, preq->preq_lifetime);
713         ADDWORD(frm, preq->preq_metric);
714         *frm++ = preq->preq_tcount;
715         for (i = 0; i < preq->preq_tcount; i++) {
716                 *frm++ = PREQ_TFLAGS(i);
717                 IEEE80211_ADDR_COPY(frm, PREQ_TADDR(i));
718                 frm += 6;
719                 ADDWORD(frm, PREQ_TSEQ(i));
720         }
721         return frm;
722 }
723 #undef  PREQ_TFLAGS
724 #undef  PREQ_TADDR
725 #undef  PREQ_TSEQ
726
727 /*
728  * Add a Mesh Path Reply IE to a frame.
729  */
730 static uint8_t *
731 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
732 {
733         *frm++ = IEEE80211_ELEMID_MESHPREP;
734         *frm++ = prep->prep_len;        /* len already calculated */
735         *frm++ = prep->prep_flags;
736         *frm++ = prep->prep_hopcount;
737         *frm++ = prep->prep_ttl;
738         IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
739         ADDWORD(frm, prep->prep_targetseq);
740         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
741                 IEEE80211_ADDR_COPY(frm, prep->prep_target_ext_addr);
742                 frm += 6;
743         }
744         ADDWORD(frm, prep->prep_lifetime);
745         ADDWORD(frm, prep->prep_metric);
746         IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
747         ADDWORD(frm, prep->prep_origseq);
748         return frm;
749 }
750
751 /*
752  * Add a Mesh Path Error IE to a frame.
753  */
754 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
755 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
756 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
757 #define PERR_EXTADDR(n) perr->perr_dests[n].dest_ext_addr
758 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
759 static uint8_t *
760 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
761 {
762         int i;
763
764         *frm++ = IEEE80211_ELEMID_MESHPERR;
765         *frm++ = perr->perr_len;        /* len already calculated */
766         *frm++ = perr->perr_ttl;
767         *frm++ = perr->perr_ndests;
768         for (i = 0; i < perr->perr_ndests; i++) {
769                 *frm++ = PERR_DFLAGS(i);
770                 IEEE80211_ADDR_COPY(frm, PERR_DADDR(i));
771                 frm += 6;
772                 ADDWORD(frm, PERR_DSEQ(i));
773                 if (PERR_DFLAGS(i) & IEEE80211_MESHPERR_FLAGS_AE) {
774                         IEEE80211_ADDR_COPY(frm, PERR_EXTADDR(i));
775                         frm += 6;
776                 }
777                 ADDSHORT(frm, PERR_DRCODE(i));
778         }
779         return frm;
780 }
781 #undef  PERR_DFLAGS
782 #undef  PERR_DADDR
783 #undef  PERR_DSEQ
784 #undef  PERR_EXTADDR
785 #undef  PERR_DRCODE
786
787 /*
788  * Add a Root Annoucement IE to a frame.
789  */
790 static uint8_t *
791 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
792 {
793         *frm++ = IEEE80211_ELEMID_MESHRANN;
794         *frm++ = rann->rann_len;
795         *frm++ = rann->rann_flags;
796         *frm++ = rann->rann_hopcount;
797         *frm++ = rann->rann_ttl;
798         IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
799         ADDWORD(frm, rann->rann_seq);
800         ADDWORD(frm, rann->rann_interval);
801         ADDWORD(frm, rann->rann_metric);
802         return frm;
803 }
804
805 static void
806 hwmp_rootmode_setup(struct ieee80211vap *vap)
807 {
808         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
809         struct ieee80211_mesh_state *ms = vap->iv_mesh;
810
811         switch (hs->hs_rootmode) {
812         case IEEE80211_HWMP_ROOTMODE_DISABLED:
813                 callout_drain(&hs->hs_roottimer);
814                 ms->ms_flags &= ~IEEE80211_MESHFLAGS_ROOT;
815                 break;
816         case IEEE80211_HWMP_ROOTMODE_NORMAL:
817         case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
818                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
819                     hwmp_rootmode_cb, vap);
820                 ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
821                 break;
822         case IEEE80211_HWMP_ROOTMODE_RANN:
823                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
824                     hwmp_rootmode_rann_cb, vap);
825                 ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
826                 break;
827         }
828 }
829
830 /*
831  * Send a broadcast Path Request to find all nodes on the mesh. We are
832  * called when the vap is configured as a HWMP root node.
833  */
834 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
835 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
836 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
837 static void
838 hwmp_rootmode_cb(void *arg)
839 {
840         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
841         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
842         struct ieee80211_mesh_state *ms = vap->iv_mesh;
843         struct ieee80211_meshpreq_ie preq;
844
845         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
846             "%s", "send broadcast PREQ");
847
848         preq.preq_flags = 0;
849         if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE)
850                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_GATE;
851         if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
852                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
853         preq.preq_hopcount = 0;
854         preq.preq_ttl = ms->ms_ttl;
855         preq.preq_id = ++hs->hs_preqid;
856         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
857         preq.preq_origseq = ++hs->hs_seq;
858         preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout);
859         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
860         preq.preq_tcount = 1;
861         IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
862         PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
863             IEEE80211_MESHPREQ_TFLAGS_USN;
864         PREQ_TSEQ(0) = 0;
865         vap->iv_stats.is_hwmp_rootreqs++;
866         /* NB: we enforce rate check ourself */
867         hwmp_send_preq(vap, broadcastaddr, &preq, NULL, NULL);
868         hwmp_rootmode_setup(vap);
869 }
870 #undef  PREQ_TFLAGS
871 #undef  PREQ_TADDR
872 #undef  PREQ_TSEQ
873
874 /*
875  * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
876  * called when the vap is configured as a HWMP RANN root node.
877  */
878 static void
879 hwmp_rootmode_rann_cb(void *arg)
880 {
881         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
882         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
883         struct ieee80211_mesh_state *ms = vap->iv_mesh;
884         struct ieee80211_meshrann_ie rann;
885
886         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
887             "%s", "send broadcast RANN");
888
889         rann.rann_flags = 0;
890         if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE)
891                 rann.rann_flags |= IEEE80211_MESHFLAGS_GATE;
892         rann.rann_hopcount = 0;
893         rann.rann_ttl = ms->ms_ttl;
894         IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
895         rann.rann_seq = ++hs->hs_seq;
896         rann.rann_interval = ieee80211_hwmp_rannint;
897         rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
898
899         vap->iv_stats.is_hwmp_rootrann++;
900         hwmp_send_rann(vap, broadcastaddr, &rann);
901         hwmp_rootmode_setup(vap);
902 }
903
904 /*
905  * Update forwarding information to TA if metric improves.
906  */
907 static void
908 hwmp_update_transmitter(struct ieee80211vap *vap, struct ieee80211_node *ni,
909     const char *hwmp_frame)
910 {
911         struct ieee80211_mesh_state *ms = vap->iv_mesh;
912         struct ieee80211_mesh_route *rttran = NULL;     /* Transmitter */
913         int metric = 0;
914
915         rttran = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
916         if (rttran == NULL) {
917                 rttran = ieee80211_mesh_rt_add(vap, ni->ni_macaddr);
918                 if (rttran == NULL) {
919                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
920                             "unable to add path to transmitter %6D of %s",
921                             ni->ni_macaddr, ":", hwmp_frame);
922                         vap->iv_stats.is_mesh_rtaddfailed++;
923                         return;
924                 }
925         }
926         metric = ms->ms_pmetric->mpm_metric(ni);
927         if (!(rttran->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) ||
928             rttran->rt_metric > metric)
929         {
930                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
931                     "%s path to transmitter %6D of %s, metric %d:%d",
932                     rttran->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
933                     "prefer" : "update", ni->ni_macaddr, ":", hwmp_frame,
934                     rttran->rt_metric, metric);
935                 IEEE80211_ADDR_COPY(rttran->rt_nexthop, ni->ni_macaddr);
936                 rttran->rt_metric = metric;
937                 rttran->rt_nhops  = 1;
938                 ieee80211_mesh_rt_update(rttran, ms->ms_ppath->mpp_inact);
939                 rttran->rt_flags = IEEE80211_MESHRT_FLAGS_VALID;
940         }
941 }
942
943 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
944 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
945 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
946 static void
947 hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
948     const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
949 {
950         struct ieee80211_mesh_state *ms = vap->iv_mesh;
951         struct ieee80211_mesh_route *rtorig = NULL;
952         struct ieee80211_mesh_route *rtorig_ext = NULL;
953         struct ieee80211_mesh_route *rttarg = NULL;
954         struct ieee80211_hwmp_route *hrorig = NULL;
955         struct ieee80211_hwmp_route *hrtarg = NULL;
956         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
957         ieee80211_hwmp_seq preqid;      /* last seen preqid for orig */
958         uint32_t metric = 0;
959
960         /*
961          * Ignore PREQs from us. Could happen because someone forward it
962          * back to us.
963          */
964         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr))
965                 return;
966
967         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
968             "received PREQ, orig %6D, targ(0) %6D", preq->preq_origaddr, ":",
969             PREQ_TADDR(0), ":");
970
971         /*
972          * Acceptance criteria: (if the PREQ is not for us or not broadcast,
973          * or an external mac address not proxied by us),
974          * AND forwarding is disabled, discard this PREQ.
975          */
976         rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
977         if (!(ms->ms_flags & IEEE80211_MESHFLAGS_FWD) &&
978             (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
979             !IEEE80211_IS_MULTICAST(PREQ_TADDR(0)) ||
980             (rttarg != NULL &&
981             rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
982             IEEE80211_ADDR_EQ(vap->iv_myaddr, rttarg->rt_mesh_gate)))) {
983                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
984                     preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
985                 return;
986         }
987         /*
988          * Acceptance criteria: if unicast addressed 
989          * AND no valid forwarding for Target of PREQ, discard this PREQ.
990          */
991         if(rttarg != NULL)
992                 hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg,
993                     struct ieee80211_hwmp_route);
994         /* Address mode: ucast */
995         if(preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM &&
996             rttarg == NULL &&
997             !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
998                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
999                     preq->preq_origaddr, NULL,
1000                     "unicast addressed PREQ of unknown target %6D",
1001                     PREQ_TADDR(0), ":");
1002                 return;
1003         }
1004
1005         /* PREQ ACCEPTED */
1006
1007         rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
1008         if (rtorig == NULL) {
1009                 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
1010                 if (rtorig == NULL) {
1011                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1012                             "unable to add orig path to %6D",
1013                             preq->preq_origaddr, ":");
1014                         vap->iv_stats.is_mesh_rtaddfailed++;
1015                         return;
1016                 }
1017                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1018                     "adding originator %6D", preq->preq_origaddr, ":");
1019         }
1020         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
1021
1022         /* record last seen preqid */
1023         preqid = hrorig->hr_preqid;
1024         hrorig->hr_preqid = HWMP_SEQ_MAX(hrorig->hr_preqid, preq->preq_id);
1025
1026         /* Data creation and update of forwarding information
1027          * according to Table 11C-8 for originator mesh STA.
1028          */
1029         metric = preq->preq_metric + ms->ms_pmetric->mpm_metric(ni);
1030         if (HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) ||
1031             (HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) &&
1032             metric < rtorig->rt_metric)) {
1033                 hrorig->hr_seq = preq->preq_origseq;
1034                 IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2);
1035                 rtorig->rt_metric = metric;
1036                 rtorig->rt_nhops  = preq->preq_hopcount + 1;
1037                 ieee80211_mesh_rt_update(rtorig, preq->preq_lifetime);
1038                 /* Path to orig is valid now.
1039                  * NB: we know it can't be Proxy, and if it is GATE
1040                  * it will be marked below.
1041                  */
1042                 rtorig->rt_flags = IEEE80211_MESHRT_FLAGS_VALID;
1043         } else if ((hrtarg != NULL &&
1044             !HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0))) ||
1045             (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
1046             preqid >= preq->preq_id)) {
1047                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1048                     "discard PREQ from %6D, old seqno %u <= %u,"
1049                     " or old preqid %u < %u",
1050                     preq->preq_origaddr, ":",
1051                     preq->preq_origseq, hrorig->hr_seq,
1052                     preq->preq_id, preqid);
1053                 return;
1054         }
1055
1056         /* Update forwarding information to TA if metric improves. */
1057         hwmp_update_transmitter(vap, ni, "PREQ");
1058
1059         /*
1060          * Check if the PREQ is addressed to us.
1061          * or a Proxy currently gated by us.
1062          */
1063         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
1064             (ms->ms_flags & IEEE80211_MESHFLAGS_GATE &&
1065             rttarg != NULL &&
1066             IEEE80211_ADDR_EQ(vap->iv_myaddr, rttarg->rt_mesh_gate) &&
1067             rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
1068             rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
1069                 struct ieee80211_meshprep_ie prep;
1070
1071                 /*
1072                  * When we are the target we shall update our own HWMP seq
1073                  * number with max of (current and preq->seq) + 1
1074                  */
1075                 hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1;
1076
1077                 prep.prep_flags = 0;
1078                 prep.prep_hopcount = 0;
1079                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1080                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
1081                 if (rttarg != NULL && /* if NULL it means we are the target */
1082                     rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1083                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1084                             "reply for proxy %6D", rttarg->rt_dest, ":");
1085                         prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE;
1086                         IEEE80211_ADDR_COPY(prep.prep_target_ext_addr,
1087                             rttarg->rt_dest);
1088                         /* update proxy seqno to HWMP seqno */
1089                         rttarg->rt_ext_seq = hs->hs_seq;
1090                         prep.prep_hopcount = rttarg->rt_nhops;
1091                         prep.prep_metric = rttarg->rt_metric;
1092                         IEEE80211_ADDR_COPY(prep.prep_targetaddr, rttarg->rt_mesh_gate);
1093                 }
1094                 /*
1095                  * Build and send a PREP frame.
1096                  */
1097                 prep.prep_ttl = ms->ms_ttl;
1098                 prep.prep_targetseq = hs->hs_seq;
1099                 prep.prep_lifetime = preq->preq_lifetime;
1100                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
1101                 prep.prep_origseq = preq->preq_origseq;
1102
1103                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1104                     "reply to %6D", preq->preq_origaddr, ":");
1105                 hwmp_send_prep(vap, wh->i_addr2, &prep);
1106                 return;
1107         }
1108         /* we may update our proxy information for the orig external */
1109         else if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
1110                 rtorig_ext =
1111                     ieee80211_mesh_rt_find(vap, preq->preq_orig_ext_addr);
1112                 if (rtorig_ext == NULL) {
1113                         rtorig_ext = ieee80211_mesh_rt_add(vap,
1114                             preq->preq_orig_ext_addr);
1115                         if (rtorig_ext == NULL) {
1116                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1117                                     "unable to add orig ext proxy to %6D",
1118                                     preq->preq_orig_ext_addr, ":");
1119                                 vap->iv_stats.is_mesh_rtaddfailed++;
1120                                 return;
1121                         }
1122                         IEEE80211_ADDR_COPY(rtorig_ext->rt_mesh_gate,
1123                             preq->preq_origaddr);
1124                 }
1125                 rtorig_ext->rt_ext_seq = preq->preq_origseq;
1126                 ieee80211_mesh_rt_update(rtorig_ext, preq->preq_lifetime);
1127         }
1128         /*
1129          * Proactive PREQ: reply with a proactive PREP to the
1130          * root STA if requested.
1131          */
1132         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
1133             (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
1134                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1135                     "root mesh station @ %6D", preq->preq_origaddr, ":");
1136
1137                 /* Check if root is a mesh gate, mark it */
1138                 if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_GATE) {
1139                         struct ieee80211_mesh_gate_route *gr;
1140
1141                         rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
1142                         gr = ieee80211_mesh_mark_gate(vap, preq->preq_origaddr,
1143                             rtorig);
1144                         gr->gr_lastseq = 0; /* NOT GANN */
1145                 }
1146
1147                 /*
1148                  * Reply with a PREP if we don't have a path to the root
1149                  * or if the root sent us a proactive PREQ.
1150                  */
1151                 if ((rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1152                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
1153                         struct ieee80211_meshprep_ie prep;
1154
1155                         prep.prep_flags = 0;
1156                         prep.prep_hopcount = 0;
1157                         prep.prep_ttl = ms->ms_ttl;
1158                         IEEE80211_ADDR_COPY(prep.prep_origaddr,
1159                             preq->preq_origaddr);
1160                         prep.prep_origseq = preq->preq_origseq;
1161                         prep.prep_lifetime = preq->preq_lifetime;
1162                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1163                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
1164                             vap->iv_myaddr);
1165                         prep.prep_targetseq = ++hs->hs_seq;
1166                         hwmp_send_prep(vap, rtorig->rt_nexthop, &prep);
1167                 }
1168         }
1169
1170         /*
1171          * Forwarding and Intermediate reply for PREQs with 1 target.
1172          */
1173         if ((preq->preq_tcount == 1) && (preq->preq_ttl > 1) &&
1174             (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1175                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
1176
1177                 memcpy(&ppreq, preq, sizeof(ppreq));
1178
1179                 /*
1180                  * We have a valid route to this node.
1181                  * NB: if target is proxy dont reply.
1182                  */
1183                 if (rttarg != NULL &&
1184                     rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
1185                     !(rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
1186                         /*
1187                          * Check if we can send an intermediate Path Reply,
1188                          * i.e., Target Only bit is not set and target is not
1189                          * the MAC broadcast address.
1190                          */
1191                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO) &&
1192                             !IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr)) {
1193                                 struct ieee80211_meshprep_ie prep;
1194
1195                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1196                                     "intermediate reply for PREQ from %6D",
1197                                     preq->preq_origaddr, ":");
1198                                 prep.prep_flags = 0;
1199                                 prep.prep_hopcount = rttarg->rt_nhops;
1200                                 prep.prep_ttl = ms->ms_ttl;
1201                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
1202                                     PREQ_TADDR(0));
1203                                 prep.prep_targetseq = hrtarg->hr_seq;
1204                                 prep.prep_lifetime = preq->preq_lifetime;
1205                                 prep.prep_metric =rttarg->rt_metric;
1206                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
1207                                     preq->preq_origaddr);
1208                                 prep.prep_origseq = hrorig->hr_seq;
1209                                 hwmp_send_prep(vap, rtorig->rt_nexthop, &prep);
1210
1211                                 /*
1212                                  * Set TO and unset RF bits because we have
1213                                  * sent a PREP.
1214                                  */
1215                                 ppreq.preq_targets[0].target_flags |=
1216                                     IEEE80211_MESHPREQ_TFLAGS_TO;
1217                         }
1218                 }
1219
1220                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1221                     "forward PREQ from %6D",
1222                     preq->preq_origaddr, ":");
1223                 ppreq.preq_hopcount += 1;
1224                 ppreq.preq_ttl -= 1;
1225                 ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
1226
1227                 /* don't do PREQ ratecheck when we propagate */
1228                 hwmp_send_preq(vap, broadcastaddr, &ppreq, NULL, NULL);
1229         }
1230 }
1231 #undef  PREQ_TFLAGS
1232 #undef  PREQ_TADDR
1233 #undef  PREQ_TSEQ
1234
1235 static int
1236 hwmp_send_preq(struct ieee80211vap *vap,
1237     const uint8_t da[IEEE80211_ADDR_LEN],
1238     struct ieee80211_meshpreq_ie *preq,
1239     struct timeval *last, struct timeval *minint)
1240 {
1241
1242         /*
1243          * Enforce PREQ interval.
1244          * NB: Proactive ROOT PREQs rate is handled by cb task.
1245          */
1246         if (last != NULL && minint != NULL) {
1247                 if (ratecheck(last, minint) == 0)
1248                         return EALREADY; /* XXX: we should postpone */
1249                 getmicrouptime(last);
1250         }
1251
1252         /*
1253          * mesh preq action frame format
1254          *     [6] da
1255          *     [6] sa
1256          *     [6] addr3 = sa
1257          *     [1] action
1258          *     [1] category
1259          *     [tlv] mesh path request
1260          */
1261         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
1262         preq->preq_len = (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE ?
1263             IEEE80211_MESHPREQ_BASE_SZ_AE : IEEE80211_MESHPREQ_BASE_SZ) +
1264             preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ;
1265         return hwmp_send_action(vap, da, (uint8_t *)preq, preq->preq_len+2);
1266 }
1267
1268 static void
1269 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
1270     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
1271 {
1272 #define IS_PROXY(rt)    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)
1273 #define PROXIED_BY_US(rt)               \
1274     (IEEE80211_ADDR_EQ(vap->iv_myaddr, rt->rt_mesh_gate))
1275         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1276         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1277         struct ieee80211_mesh_route *rt = NULL;
1278         struct ieee80211_mesh_route *rtorig = NULL;
1279         struct ieee80211_mesh_route *rtext = NULL;
1280         struct ieee80211_hwmp_route *hr;
1281         struct ieee80211com *ic = vap->iv_ic;
1282         struct mbuf *m, *next;
1283         uint32_t metric = 0;
1284         const uint8_t *addr;
1285
1286         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1287             "received PREP, orig %6D, targ %6D", prep->prep_origaddr, ":",
1288             prep->prep_targetaddr, ":");
1289
1290         /*
1291          * Acceptance criteria: (If the corresponding PREP was not generated
1292          * by us OR not generated by an external mac that is not proxied by us)
1293          * AND forwarding is disabled, discard this PREP.
1294          */
1295         rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
1296         if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) ||
1297             (rtorig != NULL && IS_PROXY(rtorig) && !PROXIED_BY_US(rtorig))) &&
1298             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)){
1299                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1300                     "discard PREP, orig(%6D) not proxied or generated by us",
1301                     prep->prep_origaddr, ":");
1302                 return;
1303         }
1304
1305         /* PREP ACCEPTED */
1306
1307         /*
1308          * If accepted shall create or update the active forwarding information
1309          * it maintains for the target mesh STA of the PREP (according to the
1310          * rules defined in 13.10.8.4). If the conditions for creating or
1311          * updating the forwarding information have not been met in those
1312          * rules, no further steps are applied to the PREP.
1313          */
1314         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
1315         if (rt == NULL) {
1316                 rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
1317                 if (rt == NULL) {
1318                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1319                             "unable to add PREP path to %6D",
1320                             prep->prep_targetaddr, ":");
1321                         vap->iv_stats.is_mesh_rtaddfailed++;
1322                         return;
1323                 }
1324                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1325                     "adding target %6D", prep->prep_targetaddr, ":");
1326         }
1327         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1328         /* update path metric */
1329         metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
1330         if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
1331                 if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
1332                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1333                             "discard PREP from %6D, old seq no %u < %u",
1334                             prep->prep_targetaddr, ":",
1335                             prep->prep_targetseq, hr->hr_seq);
1336                         return;
1337                 } else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) &&
1338                     metric > rt->rt_metric) {
1339                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1340                             "discard PREP from %6D, new metric %u > %u",
1341                             prep->prep_targetaddr, ":",
1342                             metric, rt->rt_metric);
1343                         return;
1344                 }
1345         }
1346
1347         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1348             "%s path to %6D, hopcount %d:%d metric %d:%d",
1349             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1350             "prefer" : "update",
1351             prep->prep_targetaddr, ":",
1352             rt->rt_nhops, prep->prep_hopcount + 1,
1353             rt->rt_metric, metric);
1354
1355         hr->hr_seq = prep->prep_targetseq;
1356         hr->hr_preqretries = 0;
1357         IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr);
1358         rt->rt_metric = metric;
1359         rt->rt_nhops = prep->prep_hopcount + 1;
1360         ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
1361         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) {
1362                 /* discovery complete */
1363                 rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_DISCOVER;
1364         }
1365         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */
1366
1367         /* Update forwarding information to TA if metric improves */
1368         hwmp_update_transmitter(vap, ni, "PREP");
1369
1370         /*
1371          * If it's NOT for us, propagate the PREP
1372          */
1373         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1374             prep->prep_ttl > 1 &&
1375             prep->prep_hopcount < hs->hs_maxhops) {
1376                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1377                 /*
1378                  * NB: We should already have setup the path to orig
1379                  * mesh STA when we propagated PREQ to target mesh STA,
1380                  * no PREP is generated without a corresponding PREQ.
1381                  * XXX: for now just ignore.
1382                  */
1383                 if (rtorig == NULL) {
1384                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1385                             "received PREP for an unknown orig(%6D)",
1386                             prep->prep_origaddr, ":");
1387                         return;
1388                 }
1389
1390                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1391                     "propagate PREP from %6D",
1392                     prep->prep_targetaddr, ":");
1393
1394                 memcpy(&pprep, prep, sizeof(pprep));
1395                 pprep.prep_hopcount += 1;
1396                 pprep.prep_ttl -= 1;
1397                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1398                 hwmp_send_prep(vap, rtorig->rt_nexthop, &pprep);
1399
1400                 /* precursor list for the Target Mesh STA Address is updated */
1401         }
1402
1403         /*
1404          * Check if we received a PREP w/ AE and store target external address.
1405          * We may store target external address if recevied PREP w/ AE
1406          * and we are not final destination
1407          */
1408         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
1409                 rtext = ieee80211_mesh_rt_find(vap,
1410                         prep->prep_target_ext_addr);
1411                 if (rtext == NULL) {
1412                         rtext = ieee80211_mesh_rt_add(vap,
1413                                 prep->prep_target_ext_addr);
1414                         if (rtext == NULL) {
1415                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1416                                     "unable to add PREP path to proxy %6D",
1417                                     prep->prep_targetaddr, ":");
1418                                 vap->iv_stats.is_mesh_rtaddfailed++;
1419                                 return;
1420                         }
1421                 }
1422                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1423                     "%s path to %6D, hopcount %d:%d metric %d:%d",
1424                     rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1425                     "prefer" : "update",
1426                     prep->prep_target_ext_addr, ":",
1427                     rtext->rt_nhops, prep->prep_hopcount + 1,
1428                     rtext->rt_metric, metric);
1429
1430                 rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
1431                         IEEE80211_MESHRT_FLAGS_VALID;
1432                 IEEE80211_ADDR_COPY(rtext->rt_dest,
1433                     prep->prep_target_ext_addr);
1434                 IEEE80211_ADDR_COPY(rtext->rt_mesh_gate,
1435                     prep->prep_targetaddr);
1436                 IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2);
1437                 rtext->rt_metric = metric;
1438                 rtext->rt_lifetime = prep->prep_lifetime;
1439                 rtext->rt_nhops = prep->prep_hopcount + 1;
1440                 rtext->rt_ext_seq = prep->prep_origseq; /* new proxy seq */
1441                 /*
1442                  * XXX: proxy entries have no HWMP priv data,
1443                  * nullify them to be sure?
1444                  */
1445         }
1446         /*
1447          * Check for frames queued awaiting path discovery.
1448          * XXX probably can tell exactly and avoid remove call
1449          * NB: hash may have false matches, if so they will get
1450          *     stuck back on the stageq because there won't be
1451          *     a path.
1452          */
1453         addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
1454             prep->prep_target_ext_addr : prep->prep_targetaddr;
1455         m = ieee80211_ageq_remove(&ic->ic_stageq,
1456             (struct ieee80211_node *)(uintptr_t)
1457             ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */
1458
1459         /*
1460          * All frames in the stageq here should be non-M_ENCAP; or things
1461          * will get very unhappy.
1462          */
1463         for (; m != NULL; m = next) {
1464                 next = m->m_nextpkt;
1465                 m->m_nextpkt = NULL;
1466                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1467                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1468                 /*
1469                  * If the mbuf has M_ENCAP set, ensure we free it.
1470                  * Note that after if_transmit() is called, m is invalid.
1471                  */
1472                 (void) ieee80211_vap_xmitpkt(vap, m);
1473         }
1474 #undef  IS_PROXY
1475 #undef  PROXIED_BY_US
1476 }
1477
1478 static int
1479 hwmp_send_prep(struct ieee80211vap *vap,
1480     const uint8_t da[IEEE80211_ADDR_LEN],
1481     struct ieee80211_meshprep_ie *prep)
1482 {
1483         /* NB: there's no PREP minimum interval. */
1484
1485         /*
1486          * mesh prep action frame format
1487          *     [6] da
1488          *     [6] sa
1489          *     [6] addr3 = sa
1490          *     [1] action
1491          *     [1] category
1492          *     [tlv] mesh path reply
1493          */
1494         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1495         prep->prep_len = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
1496             IEEE80211_MESHPREP_BASE_SZ_AE : IEEE80211_MESHPREP_BASE_SZ;
1497         return hwmp_send_action(vap, da, (uint8_t *)prep, prep->prep_len + 2);
1498 }
1499
1500 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1501 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1502 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1503 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1504 static void
1505 hwmp_peerdown(struct ieee80211_node *ni)
1506 {
1507         struct ieee80211vap *vap = ni->ni_vap;
1508         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1509         struct ieee80211_meshperr_ie perr;
1510         struct ieee80211_mesh_route *rt;
1511         struct ieee80211_hwmp_route *hr;
1512
1513         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1514         if (rt == NULL)
1515                 return;
1516         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1517         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1518             "%s", "delete route entry");
1519         perr.perr_ttl = ms->ms_ttl;
1520         perr.perr_ndests = 1;
1521         PERR_DFLAGS(0) = 0;
1522         if (hr->hr_seq == 0)
1523                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1524         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1525         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1526         PERR_DSEQ(0) = ++hr->hr_seq;
1527         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1528         /* NB: flush everything passing through peer */
1529         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1530         hwmp_send_perr(vap, broadcastaddr, &perr);
1531 }
1532 #undef  PERR_DFLAGS
1533 #undef  PERR_DADDR
1534 #undef  PERR_DSEQ
1535 #undef  PERR_DRCODE
1536
1537 #define PERR_DFLAGS(n)          perr->perr_dests[n].dest_flags
1538 #define PERR_DADDR(n)           perr->perr_dests[n].dest_addr
1539 #define PERR_DSEQ(n)            perr->perr_dests[n].dest_seq
1540 #define PERR_DEXTADDR(n)        perr->perr_dests[n].dest_ext_addr
1541 static void
1542 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1543     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1544 {
1545         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1546         struct ieee80211_mesh_route *rt = NULL;
1547         struct ieee80211_mesh_route *rt_ext = NULL;
1548         struct ieee80211_hwmp_route *hr;
1549         struct ieee80211_meshperr_ie *pperr = NULL;
1550         int i, j = 0, forward = 0;
1551
1552         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1553             "received PERR from %6D", wh->i_addr2, ":");
1554
1555         /*
1556          * if forwarding is true, prepare pperr
1557          */
1558         if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) {
1559                 forward = 1;
1560                 pperr = IEEE80211_MALLOC(sizeof(*perr) + 31*sizeof(*perr->perr_dests),
1561                     M_80211_MESH_PERR, IEEE80211_M_NOWAIT); /* XXX: magic number, 32 err dests */
1562         }
1563
1564         /*
1565          * Acceptance criteria: check if we have forwarding information
1566          * stored about destination, and that nexthop == TA of this PERR.
1567          * NB: we also build a new PERR to propagate in case we should forward.
1568          */
1569         for (i = 0; i < perr->perr_ndests; i++) {
1570                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1571                 if (rt == NULL)
1572                         continue;
1573                 if (!IEEE80211_ADDR_EQ(rt->rt_nexthop, wh->i_addr2))
1574                         continue;
1575
1576                 /* found and accepted a PERR ndest element, process it... */
1577                 if (forward)
1578                         memcpy(&pperr->perr_dests[j], &perr->perr_dests[i],
1579                             sizeof(*perr->perr_dests));
1580                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1581                 switch(PERR_DFLAGS(i)) {
1582                 case (IEEE80211_REASON_MESH_PERR_NO_FI):
1583                         if (PERR_DSEQ(i) == 0) {
1584                                 hr->hr_seq++;
1585                                 if (forward) {
1586                                         pperr->perr_dests[j].dest_seq =
1587                                             hr->hr_seq;
1588                                 }
1589                         } else {
1590                                 hr->hr_seq = PERR_DSEQ(i);
1591                         }
1592                         rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
1593                         j++;
1594                         break;
1595                 case (IEEE80211_REASON_MESH_PERR_DEST_UNREACH):
1596                         if(HWMP_SEQ_GT(PERR_DSEQ(i), hr->hr_seq)) {
1597                                 hr->hr_seq = PERR_DSEQ(i);
1598                                 rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
1599                                 j++;
1600                         }
1601                         break;
1602                 case (IEEE80211_REASON_MESH_PERR_NO_PROXY):
1603                         rt_ext = ieee80211_mesh_rt_find(vap, PERR_DEXTADDR(i));
1604                         if (rt_ext != NULL) {
1605                                 rt_ext->rt_flags &=
1606                                     ~IEEE80211_MESHRT_FLAGS_VALID;
1607                                 j++;
1608                         }
1609                         break;
1610                 default:
1611                         IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
1612                             "PERR, unknown reason code %u\n", PERR_DFLAGS(i));
1613                         goto done; /* XXX: stats?? */
1614                 }
1615                 ieee80211_mesh_rt_flush_peer(vap, PERR_DADDR(i));
1616                 KASSERT(j < 32, ("PERR, error ndest >= 32 (%u)", j));
1617         }
1618         if (j == 0) {
1619                 IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL, "%s",
1620                     "PERR not accepted");
1621                 goto done; /* XXX: stats?? */
1622         }
1623
1624         /*
1625          * Propagate the PERR if we previously found it on our routing table.
1626          */
1627         if (forward && perr->perr_ttl > 1) {
1628                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1629                     "propagate PERR from %6D", wh->i_addr2, ":");
1630                 pperr->perr_ndests = j;
1631                 pperr->perr_ttl--;
1632                 hwmp_send_perr(vap, broadcastaddr, pperr);
1633         }
1634 done:
1635         if (pperr != NULL)
1636                 IEEE80211_FREE(pperr, M_80211_MESH_PERR);
1637 }
1638 #undef  PERR_DFLAGS
1639 #undef  PERR_DADDR
1640 #undef  PERR_DSEQ
1641 #undef  PERR_DEXTADDR
1642
1643 static int
1644 hwmp_send_perr(struct ieee80211vap *vap,
1645     const uint8_t da[IEEE80211_ADDR_LEN],
1646     struct ieee80211_meshperr_ie *perr)
1647 {
1648         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1649         int i;
1650         uint8_t length = 0;
1651
1652         /*
1653          * Enforce PERR interval.
1654          */
1655         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1656                 return EALREADY;
1657         getmicrouptime(&hs->hs_lastperr);
1658
1659         /*
1660          * mesh perr action frame format
1661          *     [6] da
1662          *     [6] sa
1663          *     [6] addr3 = sa
1664          *     [1] action
1665          *     [1] category
1666          *     [tlv] mesh path error
1667          */
1668         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1669         length = IEEE80211_MESHPERR_BASE_SZ;
1670         for (i = 0; i<perr->perr_ndests; i++) {
1671                 if (perr->perr_dests[i].dest_flags &
1672                     IEEE80211_MESHPERR_FLAGS_AE) {
1673                         length += IEEE80211_MESHPERR_DEST_SZ_AE;
1674                         continue ;
1675                 }
1676                 length += IEEE80211_MESHPERR_DEST_SZ;
1677         }
1678         perr->perr_len =length;
1679         return hwmp_send_action(vap, da, (uint8_t *)perr, perr->perr_len+2);
1680 }
1681
1682 /*
1683  * Called from the rest of the net80211 code (mesh code for example).
1684  * NB: IEEE80211_REASON_MESH_PERR_DEST_UNREACH can be trigger by the fact that
1685  * a mesh STA is unable to forward an MSDU/MMPDU to a next-hop mesh STA.
1686  */
1687 #define PERR_DFLAGS(n)          perr.perr_dests[n].dest_flags
1688 #define PERR_DADDR(n)           perr.perr_dests[n].dest_addr
1689 #define PERR_DSEQ(n)            perr.perr_dests[n].dest_seq
1690 #define PERR_DEXTADDR(n)        perr.perr_dests[n].dest_ext_addr
1691 #define PERR_DRCODE(n)          perr.perr_dests[n].dest_rcode
1692 static void
1693 hwmp_senderror(struct ieee80211vap *vap,
1694     const uint8_t addr[IEEE80211_ADDR_LEN],
1695     struct ieee80211_mesh_route *rt, int rcode)
1696 {
1697         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1698         struct ieee80211_hwmp_route *hr = NULL;
1699         struct ieee80211_meshperr_ie perr;
1700
1701         if (rt != NULL)
1702                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1703                     struct ieee80211_hwmp_route);
1704
1705         perr.perr_ndests = 1;
1706         perr.perr_ttl = ms->ms_ttl;
1707         PERR_DFLAGS(0) = 0;
1708         PERR_DRCODE(0) = rcode;
1709
1710         switch (rcode) {
1711         case IEEE80211_REASON_MESH_PERR_NO_FI:
1712                 IEEE80211_ADDR_COPY(PERR_DADDR(0), addr);
1713                 PERR_DSEQ(0) = 0; /* reserved */
1714                 break;
1715         case IEEE80211_REASON_MESH_PERR_NO_PROXY:
1716                 KASSERT(rt != NULL, ("no proxy info for sending PERR"));
1717                 KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
1718                     ("route is not marked proxy"));
1719                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_FLAGS_AE;
1720                 IEEE80211_ADDR_COPY(PERR_DADDR(0), vap->iv_myaddr);
1721                 PERR_DSEQ(0) = rt->rt_ext_seq;
1722                 IEEE80211_ADDR_COPY(PERR_DEXTADDR(0), addr);
1723                 break;
1724         case IEEE80211_REASON_MESH_PERR_DEST_UNREACH:
1725                 KASSERT(rt != NULL, ("no route info for sending PERR"));
1726                 IEEE80211_ADDR_COPY(PERR_DADDR(0), addr);
1727                 PERR_DSEQ(0) = hr->hr_seq;
1728                 break;
1729         default:
1730                 KASSERT(0, ("unknown reason code for HWMP PERR (%u)", rcode));
1731         }
1732         hwmp_send_perr(vap, broadcastaddr, &perr);
1733 }
1734 #undef  PERR_DFLAGS
1735 #undef  PEER_DADDR
1736 #undef  PERR_DSEQ
1737 #undef  PERR_DEXTADDR
1738 #undef  PERR_DRCODE
1739
1740 static void
1741 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1742     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1743 {
1744         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1745         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1746         struct ieee80211_mesh_route *rt = NULL;
1747         struct ieee80211_hwmp_route *hr;
1748         struct ieee80211_meshpreq_ie preq;
1749         struct ieee80211_meshrann_ie prann;
1750
1751         if (IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1752                 return;
1753
1754         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1755         if (rt != NULL && rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) {
1756                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1757
1758                 /* Acceptance criteria: if RANN.seq < stored seq, discard RANN */
1759                 if (HWMP_SEQ_LT(rann->rann_seq, hr->hr_seq)) {
1760                         IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
1761                         "RANN seq %u < %u", rann->rann_seq, hr->hr_seq);
1762                         return;
1763                 }
1764
1765                 /* Acceptance criteria: if RANN.seq == stored seq AND
1766                 * RANN.metric > stored metric, discard RANN */
1767                 if (HWMP_SEQ_EQ(rann->rann_seq, hr->hr_seq) &&
1768                 rann->rann_metric > rt->rt_metric) {
1769                         IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
1770                         "RANN metric %u > %u", rann->rann_metric, rt->rt_metric);
1771                         return;
1772                 }
1773         }
1774
1775         /* RANN ACCEPTED */
1776
1777         ieee80211_hwmp_rannint = rann->rann_interval; /* XXX: mtx lock? */
1778
1779         if (rt == NULL) {
1780                 rt = ieee80211_mesh_rt_add(vap, rann->rann_addr);
1781                 if (rt == NULL) {
1782                         IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
1783                             "unable to add mac for RANN root %6D",
1784                             rann->rann_addr, ":");
1785                             vap->iv_stats.is_mesh_rtaddfailed++;
1786                         return;
1787                 }
1788         }
1789         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1790         /* Check if root is a mesh gate, mark it */
1791         if (rann->rann_flags & IEEE80211_MESHRANN_FLAGS_GATE) {
1792                 struct ieee80211_mesh_gate_route *gr;
1793
1794                 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
1795                 gr = ieee80211_mesh_mark_gate(vap, rann->rann_addr,
1796                         rt);
1797                 gr->gr_lastseq = 0; /* NOT GANN */
1798         }
1799         /* discovery timeout */
1800         ieee80211_mesh_rt_update(rt,
1801             ticks_to_msecs(ieee80211_hwmp_roottimeout));
1802
1803         preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
1804         preq.preq_hopcount = 0;
1805         preq.preq_ttl = ms->ms_ttl;
1806         preq.preq_id = 0; /* reserved */
1807         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1808         preq.preq_origseq = ++hs->hs_seq;
1809         preq.preq_lifetime = ieee80211_hwmp_roottimeout;
1810         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1811         preq.preq_tcount = 1;
1812         preq.preq_targets[0].target_flags = IEEE80211_MESHPREQ_TFLAGS_TO;
1813         /* NB: IEEE80211_MESHPREQ_TFLAGS_USN = 0 implicitly implied */
1814         IEEE80211_ADDR_COPY(preq.preq_targets[0].target_addr, rann->rann_addr);
1815         preq.preq_targets[0].target_seq = rann->rann_seq;
1816         /* XXX: if rootconfint have not passed, we built this preq in vain */
1817         hwmp_send_preq(vap, wh->i_addr2, &preq, &hr->hr_lastrootconf,
1818             &ieee80211_hwmp_rootconfint);
1819
1820         /* propagate a RANN */
1821         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
1822             rann->rann_ttl > 1 &&
1823             ms->ms_flags & IEEE80211_MESHFLAGS_FWD) {
1824                 hr->hr_seq = rann->rann_seq;
1825                 memcpy(&prann, rann, sizeof(prann));
1826                 prann.rann_hopcount += 1;
1827                 prann.rann_ttl -= 1;
1828                 prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1829                 hwmp_send_rann(vap, broadcastaddr, &prann);
1830         }
1831 }
1832
1833 static int
1834 hwmp_send_rann(struct ieee80211vap *vap,
1835     const uint8_t da[IEEE80211_ADDR_LEN],
1836     struct ieee80211_meshrann_ie *rann)
1837 {
1838         /*
1839          * mesh rann action frame format
1840          *     [6] da
1841          *     [6] sa
1842          *     [6] addr3 = sa
1843          *     [1] action
1844          *     [1] category
1845          *     [tlv] root annoucement
1846          */
1847         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1848         rann->rann_len = IEEE80211_MESHRANN_BASE_SZ;
1849         return hwmp_send_action(vap, da, (uint8_t *)rann, rann->rann_len + 2);
1850 }
1851
1852 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1853 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1854 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1855 static void
1856 hwmp_rediscover_cb(void *arg)
1857 {
1858         struct ieee80211_mesh_route *rt = arg;
1859         struct ieee80211vap *vap = rt->rt_vap;
1860         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1861         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1862         struct ieee80211_hwmp_route *hr;
1863         struct ieee80211_meshpreq_ie preq; /* Optimize: storing first preq? */
1864
1865         if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID))
1866                 return ; /* nothing to do */
1867
1868         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1869         if (hr->hr_preqretries >=
1870                 ieee80211_hwmp_maxpreq_retries) {
1871                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY,
1872                         rt->rt_dest, "%s",
1873                         "max number of discovery, send queued frames to GATE");
1874                 ieee80211_mesh_forward_to_gates(vap, rt);
1875                 vap->iv_stats.is_mesh_fwd_nopath++;
1876                 return ; /* XXX: flush queue? */
1877         }
1878
1879         hr->hr_preqretries++;
1880
1881
1882         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, rt->rt_dest,
1883             "start path rediscovery , target seq %u", hr->hr_seq);
1884         /*
1885          * Try to discover the path for this node.
1886          * Group addressed PREQ Case A
1887          */
1888         preq.preq_flags = 0;
1889         preq.preq_hopcount = 0;
1890         preq.preq_ttl = ms->ms_ttl;
1891         preq.preq_id = ++hs->hs_preqid;
1892         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1893         preq.preq_origseq = hr->hr_origseq;
1894         preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1895         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1896         preq.preq_tcount = 1;
1897         IEEE80211_ADDR_COPY(PREQ_TADDR(0), rt->rt_dest);
1898         PREQ_TFLAGS(0) = 0;
1899         if (ieee80211_hwmp_targetonly)
1900                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1901         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1902         PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
1903         /* XXX check return value */
1904         hwmp_send_preq(vap, broadcastaddr, &preq, &hr->hr_lastpreq,
1905             &ieee80211_hwmp_preqminint);
1906         callout_reset(&rt->rt_discovery,
1907                 ieee80211_hwmp_net_diameter_traversaltime * 2,
1908                 hwmp_rediscover_cb, rt);
1909 }
1910
1911 static struct ieee80211_node *
1912 hwmp_discover(struct ieee80211vap *vap,
1913     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1914 {
1915         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1916         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1917         struct ieee80211_mesh_route *rt = NULL;
1918         struct ieee80211_hwmp_route *hr;
1919         struct ieee80211_meshpreq_ie preq;
1920         struct ieee80211_node *ni;
1921         int sendpreq = 0;
1922
1923         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1924             ("not a mesh vap, opmode %d", vap->iv_opmode));
1925
1926         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1927             ("%s: discovering self!", __func__));
1928
1929         ni = NULL;
1930         if (!IEEE80211_IS_MULTICAST(dest)) {
1931                 rt = ieee80211_mesh_rt_find(vap, dest);
1932                 if (rt == NULL) {
1933                         rt = ieee80211_mesh_rt_add(vap, dest);
1934                         if (rt == NULL) {
1935                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1936                                     ni, "unable to add discovery path to %6D",
1937                                     dest, ":");
1938                                 vap->iv_stats.is_mesh_rtaddfailed++;
1939                                 goto done;
1940                         }
1941                 }
1942                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1943                     struct ieee80211_hwmp_route);
1944                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) {
1945                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1946                             "%s", "already discovering queue frame until path found");
1947                         sendpreq = 1;
1948                         goto done;
1949                 }
1950                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1951                         if (hr->hr_lastdiscovery != 0 &&
1952                             (ticks - hr->hr_lastdiscovery <
1953                             (ieee80211_hwmp_net_diameter_traversaltime * 2))) {
1954                                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1955                                     dest, NULL, "%s",
1956                                     "too frequent discovery requeust");
1957                                 sendpreq = 1;
1958                                 goto done;
1959                         }
1960                         hr->hr_lastdiscovery = ticks;
1961                         if (hr->hr_preqretries >=
1962                             ieee80211_hwmp_maxpreq_retries) {
1963                                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1964                                     dest, NULL, "%s",
1965                                     "no valid path , max number of discovery");
1966                                 vap->iv_stats.is_mesh_fwd_nopath++;
1967                                 goto done;
1968                         }
1969                         rt->rt_flags = IEEE80211_MESHRT_FLAGS_DISCOVER;
1970                         hr->hr_preqretries++;
1971                         if (hr->hr_origseq == 0)
1972                                 hr->hr_origseq = ++hs->hs_seq;
1973                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1974                         sendpreq = 1;
1975                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1976                             "start path discovery (src %s), target seq %u",
1977                             m == NULL ? "<none>" : ether_sprintf(
1978                             mtod(m, struct ether_header *)->ether_shost),
1979                             hr->hr_seq);
1980                         /*
1981                          * Try to discover the path for this node.
1982                          * Group addressed PREQ Case A
1983                          */
1984                         preq.preq_flags = 0;
1985                         preq.preq_hopcount = 0;
1986                         preq.preq_ttl = ms->ms_ttl;
1987                         preq.preq_id = ++hs->hs_preqid;
1988                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1989                         preq.preq_origseq = hr->hr_origseq;
1990                         preq.preq_lifetime =
1991                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1992                         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1993                         preq.preq_tcount = 1;
1994                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1995                         PREQ_TFLAGS(0) = 0;
1996                         if (ieee80211_hwmp_targetonly)
1997                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1998                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1999                         PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
2000                         /* XXX check return value */
2001                         hwmp_send_preq(vap, broadcastaddr, &preq,
2002                             &hr->hr_lastpreq, &ieee80211_hwmp_preqminint);
2003                         callout_reset(&rt->rt_discovery,
2004                             ieee80211_hwmp_net_diameter_traversaltime * 2,
2005                             hwmp_rediscover_cb, rt);
2006                 }
2007                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
2008                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
2009         } else {
2010                 ni = ieee80211_find_txnode(vap, dest);
2011                 /* NB: if null then we leak mbuf */
2012                 KASSERT(ni != NULL, ("leak mcast frame"));
2013                 return ni;
2014         }
2015 done:
2016         if (ni == NULL && m != NULL) {
2017                 if (sendpreq) {
2018                         struct ieee80211com *ic = vap->iv_ic;
2019                         /*
2020                          * Queue packet for transmit when path discovery
2021                          * completes.  If discovery never completes the
2022                          * frame will be flushed by way of the aging timer.
2023                          */
2024                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
2025                             "%s", "queue frame until path found");
2026                         MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
2027                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
2028                             ieee80211_mac_hash(ic, dest);
2029                         /* XXX age chosen randomly */
2030                         ieee80211_ageq_append(&ic->ic_stageq, m,
2031                             IEEE80211_INACT_WAIT);
2032                 } else {
2033                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
2034                             dest, NULL, "%s", "no valid path to this node");
2035                         m_freem(m);
2036                 }
2037         }
2038         return ni;
2039 }
2040 #undef  PREQ_TFLAGS
2041 #undef  PREQ_TADDR
2042 #undef  PREQ_TSEQ
2043
2044 static int
2045 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
2046 {
2047         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
2048         int error;
2049
2050         if (vap->iv_opmode != IEEE80211_M_MBSS)
2051                 return ENOSYS;
2052         error = 0;
2053         switch (ireq->i_type) {
2054         case IEEE80211_IOC_HWMP_ROOTMODE:
2055                 ireq->i_val = hs->hs_rootmode;
2056                 break;
2057         case IEEE80211_IOC_HWMP_MAXHOPS:
2058                 ireq->i_val = hs->hs_maxhops;
2059                 break;
2060         default:
2061                 return ENOSYS;
2062         }
2063         return error;
2064 }
2065 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
2066
2067 static int
2068 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
2069 {
2070         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
2071         int error;
2072
2073         if (vap->iv_opmode != IEEE80211_M_MBSS)
2074                 return ENOSYS;
2075         error = 0;
2076         switch (ireq->i_type) {
2077         case IEEE80211_IOC_HWMP_ROOTMODE:
2078                 if (ireq->i_val < 0 || ireq->i_val > 3)
2079                         return EINVAL;
2080                 hs->hs_rootmode = ireq->i_val;
2081                 hwmp_rootmode_setup(vap);
2082                 break;
2083         case IEEE80211_IOC_HWMP_MAXHOPS:
2084                 if (ireq->i_val <= 0 || ireq->i_val > 255)
2085                         return EINVAL;
2086                 hs->hs_maxhops = ireq->i_val;
2087                 break;
2088         default:
2089                 return ENOSYS;
2090         }
2091         return error;
2092 }
2093 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);