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