xref: /freebsd/sys/net80211/ieee80211_hwmp.c (revision 6419bb52)
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);
2094