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