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