2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2009 The FreeBSD Foundation
6 * This software was developed by Rui Paulo under sponsorship from the
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
32 * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
34 * Based on March 2009, D3.0 802.11s draft spec.
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <sys/endian.h>
48 #include <sys/errno.h>
50 #include <sys/sysctl.h>
53 #include <net/if_media.h>
54 #include <net/if_llc.h>
55 #include <net/ethernet.h>
59 #include <net80211/ieee80211_var.h>
60 #include <net80211/ieee80211_action.h>
61 #include <net80211/ieee80211_input.h>
62 #include <net80211/ieee80211_mesh.h>
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
],
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
*);
115 static struct timeval ieee80211_hwmp_preqminint
= { 0, 100000 };
116 static struct timeval ieee80211_hwmp_perrminint
= { 0, 100000 };
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 };
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)
128 #define HWMP_SEQ_MAX(a, b) (a > b ? a : b)
131 * Private extension of ieee80211_mesh_route.
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 */
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 */
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)");
194 #define IEEE80211_HWMP_DEFAULT_MAXHOPS 31
196 static ieee80211_recv_action_func hwmp_recv_action_meshpath
;
198 static struct ieee80211_mesh_proto_path mesh_proto_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
),
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)");
215 ieee80211_hwmp_init(void)
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;
225 * (TU): A measurement of time equal to 1024 μs,
228 ieee80211_hwmp_net_diameter_traversaltime
= msecs_to_ticks(512);
231 * NB: I dont know how to make SYSCTL_PROC that calls ms to ticks
232 * and return a struct timeval...
234 ieee80211_hwmp_rootconfint
.tv_usec
=
235 ieee80211_hwmp_rootconfint_internal
* 1000;
238 * Register action frame handler.
240 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH
,
241 IEEE80211_ACTION_MESH_HWMP
, hwmp_recv_action_meshpath
);
243 /* NB: default is 5 secs per spec */
244 mesh_proto_hwmp
.mpp_inact
= msecs_to_ticks(5*1000);
249 ieee80211_mesh_register_proto_path(&mesh_proto_hwmp
);
251 SYSINIT(wlan_hwmp
, SI_SUB_DRIVERS
, SI_ORDER_SECOND
, ieee80211_hwmp_init
, NULL
);
254 hwmp_vattach(struct ieee80211vap
*vap
)
256 struct ieee80211_hwmp_state
*hs
;
258 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
,
259 ("not a mesh vap, opmode %d", vap
->iv_opmode
));
261 hs
= IEEE80211_MALLOC(sizeof(struct ieee80211_hwmp_state
), M_80211_VAP
,
262 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
264 printf("%s: couldn't alloc HWMP state\n", __func__
);
267 hs
->hs_maxhops
= IEEE80211_HWMP_DEFAULT_MAXHOPS
;
268 callout_init(&hs
->hs_roottimer
, 1);
273 hwmp_vdetach(struct ieee80211vap
*vap
)
275 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
277 callout_drain(&hs
->hs_roottimer
);
278 IEEE80211_FREE(vap
->iv_hwmp
, M_80211_VAP
);
283 hwmp_newstate(struct ieee80211vap
*vap
, enum ieee80211_state ostate
, int arg
)
285 enum ieee80211_state nstate
= vap
->iv_state
;
286 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
288 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
289 __func__
, ieee80211_state_name
[ostate
],
290 ieee80211_state_name
[nstate
], arg
);
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
);
300 * Verify the length of an HWMP PREQ and return the number
301 * of destinations >= 1, if verification fails -1 is returned.
304 verify_mesh_preq_len(struct ieee80211vap
*vap
,
305 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
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
];
314 /* w/o Originator External Address */
315 alloc_sz
= IEEE80211_MESHPREQ_BASE_SZ
;
316 ndest
= iefrm
[IEEE80211_MESHPREQ_TCNT_OFFSET
];
318 alloc_sz
+= ndest
* IEEE80211_MESHPREQ_TRGT_SZ
;
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");
331 * Verify the length of an HWMP PREP and returns 1 on success,
335 verify_mesh_prep_len(struct ieee80211vap
*vap
,
336 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
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
;
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");
355 * Verify the length of an HWMP PERR and return the number
356 * of destinations >= 1, if verification fails -1 is returned.
359 verify_mesh_perr_len(struct ieee80211vap
*vap
,
360 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
363 const uint8_t *iefrm_t
= iefrm
;
364 uint8_t ndest
= iefrm_t
[IEEE80211_MESHPERR_NDEST_OFFSET
];
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",
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
;
381 iefrm_t
+= IEEE80211_MESHPERR_DEST_SZ
;
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");
395 hwmp_recv_action_meshpath(struct ieee80211_node
*ni
,
396 const struct ieee80211_frame
*wh
,
397 const uint8_t *frm
, const uint8_t *efrm
)
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 */
409 while (efrm
- iefrm
> 1) {
410 IEEE80211_VERIFY_LENGTH(efrm
- iefrm
, iefrm
[1] + 2, return 0);
412 case IEEE80211_ELEMID_MESHPREQ
:
417 ndest
= verify_mesh_preq_len(vap
, wh
, iefrm_t
);
419 vap
->iv_stats
.is_rx_mgtdiscard
++;
422 preq
= IEEE80211_MALLOC(sizeof(*preq
) +
423 (ndest
- 1) * sizeof(*preq
->preq_targets
),
425 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
426 KASSERT(preq
!= NULL
, ("preq == NULL"));
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
);
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
) {
440 preq
->preq_orig_ext_addr
, iefrm_t
);
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
++;
447 for (i
= 0; i
< preq
->preq_tcount
; i
++) {
448 preq
->preq_targets
[i
].target_flags
= *iefrm_t
++;
450 preq
->preq_targets
[i
].target_addr
, iefrm_t
);
452 preq
->preq_targets
[i
].target_seq
=
457 hwmp_recv_preq(vap
, ni
, wh
, preq
);
458 IEEE80211_FREE(preq
, M_80211_MESH_PREQ
);
462 case IEEE80211_ELEMID_MESHPREP
:
465 ndest
= verify_mesh_prep_len(vap
, wh
, iefrm_t
);
467 vap
->iv_stats
.is_rx_mgtdiscard
++;
470 prep
= IEEE80211_MALLOC(sizeof(*prep
),
472 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
473 KASSERT(prep
!= NULL
, ("prep == NULL"));
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
);
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
) {
486 prep
->prep_target_ext_addr
, iefrm_t
);
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
);
493 prep
->prep_origseq
= le32dec(iefrm_t
); iefrm_t
+= 4;
495 hwmp_recv_prep(vap
, ni
, wh
, prep
);
496 IEEE80211_FREE(prep
, M_80211_MESH_PREP
);
500 case IEEE80211_ELEMID_MESHPERR
:
505 ndest
= verify_mesh_perr_len(vap
, wh
, iefrm_t
);
507 vap
->iv_stats
.is_rx_mgtdiscard
++;
510 perr
= IEEE80211_MALLOC(sizeof(*perr
) +
511 (ndest
- 1) * sizeof(*perr
->perr_dests
),
513 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
514 KASSERT(perr
!= NULL
, ("perr == NULL"));
516 perr
->perr_ie
= *iefrm_t
++;
517 perr
->perr_len
= *iefrm_t
++;
518 perr
->perr_ttl
= *iefrm_t
++;
519 perr
->perr_ndests
= *iefrm_t
++;
521 for (i
= 0; i
<perr
->perr_ndests
; i
++) {
522 perr
->perr_dests
[i
].dest_flags
= *iefrm_t
++;
524 perr
->perr_dests
[i
].dest_addr
, iefrm_t
);
526 perr
->perr_dests
[i
].dest_seq
= le32dec(iefrm_t
);
528 /* NB: May have Target Proxied Address */
529 if (perr
->perr_dests
[i
].dest_flags
&
530 IEEE80211_MESHPERR_FLAGS_AE
) {
532 perr
->perr_dests
[i
].dest_ext_addr
,
536 perr
->perr_dests
[i
].dest_rcode
=
541 hwmp_recv_perr(vap
, ni
, wh
, perr
);
542 IEEE80211_FREE(perr
, M_80211_MESH_PERR
);
546 case IEEE80211_ELEMID_MESHRANN
:
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
++;
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
);
567 iefrm
+= iefrm
[1] + 2;
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
++;
579 hwmp_send_action(struct ieee80211vap
*vap
,
580 const uint8_t da
[IEEE80211_ADDR_LEN
],
581 uint8_t *ie
, size_t len
)
583 struct ieee80211_node
*ni
;
584 struct ieee80211com
*ic
;
585 struct ieee80211_bpf_params params
;
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",
596 ni
, ether_sprintf(ni
->ni_macaddr
),
597 ieee80211_node_refcnt(ni
)+1);
599 ieee80211_ref_node(ni
);
602 ni
= ieee80211_mesh_find_txnode(vap
, da
);
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 */
611 KASSERT(ni
!= NULL
, ("null node"));
614 m
= ieee80211_getmgtframe(&frm
,
615 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
616 sizeof(struct ieee80211_action
) + len
619 ieee80211_free_node(ni
);
620 vap
->iv_stats
.is_tx_nobuf
++;
623 *frm
++ = IEEE80211_ACTION_CAT_MESH
;
624 *frm
++ = IEEE80211_ACTION_MESH_HWMP
;
626 case IEEE80211_ELEMID_MESHPREQ
:
627 frm
= hwmp_add_meshpreq(frm
,
628 (struct ieee80211_meshpreq_ie
*)ie
);
630 case IEEE80211_ELEMID_MESHPREP
:
631 frm
= hwmp_add_meshprep(frm
,
632 (struct ieee80211_meshprep_ie
*)ie
);
634 case IEEE80211_ELEMID_MESHPERR
:
635 frm
= hwmp_add_meshperr(frm
,
636 (struct ieee80211_meshperr_ie
*)ie
);
638 case IEEE80211_ELEMID_MESHRANN
:
639 frm
= hwmp_add_meshrann(frm
,
640 (struct ieee80211_meshrann_ie
*)ie
);
644 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
645 M_PREPEND(m
, sizeof(struct ieee80211_frame
), IEEE80211_M_NOWAIT
);
647 ieee80211_free_node(ni
);
648 vap
->iv_stats
.is_tx_nobuf
++;
652 IEEE80211_TX_LOCK(ic
);
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
);
658 m
->m_flags
|= M_ENCAP
; /* mark encapsulated */
659 IEEE80211_NODE_STAT(ni
, tx_mgmt
);
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
))
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
);
674 #define ADDSHORT(frm, v) do { \
678 #define ADDWORD(frm, v) do { \
683 * Add a Mesh Path Request IE to a frame.
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
689 hwmp_add_meshpreq(uint8_t *frm
, const struct ieee80211_meshpreq_ie
*preq
)
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
);
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
));
712 ADDWORD(frm
, PREQ_TSEQ(i
));
721 * Add a Mesh Path Reply IE to a frame.
724 hwmp_add_meshprep(uint8_t *frm
, const struct ieee80211_meshprep_ie
*prep
)
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
);
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
);
745 * Add a Mesh Path Error IE to a frame.
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
753 hwmp_add_meshperr(uint8_t *frm
, const struct ieee80211_meshperr_ie
*perr
)
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
));
765 ADDWORD(frm
, PERR_DSEQ(i
));
766 if (PERR_DFLAGS(i
) & IEEE80211_MESHPERR_FLAGS_AE
) {
767 IEEE80211_ADDR_COPY(frm
, PERR_EXTADDR(i
));
770 ADDSHORT(frm
, PERR_DRCODE(i
));
781 * Add a Root Annoucement IE to a frame.
784 hwmp_add_meshrann(uint8_t *frm
, const struct ieee80211_meshrann_ie
*rann
)
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
);
799 hwmp_rootmode_setup(struct ieee80211vap
*vap
)
801 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
802 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
804 switch (hs
->hs_rootmode
) {
805 case IEEE80211_HWMP_ROOTMODE_DISABLED
:
806 callout_drain(&hs
->hs_roottimer
);
807 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_ROOT
;
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
;
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
;
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.
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
831 hwmp_rootmode_cb(void *arg
)
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
;
838 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, vap
->iv_bss
,
839 "%s", "send broadcast PREQ");
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
;
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
);
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.
872 hwmp_rootmode_rann_cb(void *arg
)
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
;
879 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, vap
->iv_bss
,
880 "%s", "send broadcast RANN");
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
;
892 vap
->iv_stats
.is_hwmp_rootrann
++;
893 hwmp_send_rann(vap
, broadcastaddr
, &rann
);
894 hwmp_rootmode_setup(vap
);
898 * Update forwarding information to TA if metric improves.
901 hwmp_update_transmitter(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
902 const char *hwmp_frame
)
904 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
905 struct ieee80211_mesh_route
*rttran
= NULL
; /* Transmitter */
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
++;
919 metric
= ms
->ms_pmetric
->mpm_metric(ni
);
920 if (!(rttran
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) ||
921 rttran
->rt_metric
> metric
)
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
;
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
940 hwmp_recv_preq(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
941 const struct ieee80211_frame
*wh
, const struct ieee80211_meshpreq_ie
*preq
)
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 */
954 * Ignore PREQs from us. Could happen because someone forward it
957 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, preq
->preq_origaddr
))
960 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
961 "received PREQ, orig %6D, targ(0) %6D", preq
->preq_origaddr
, ":",
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.
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)) ||
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");
981 * Acceptance criteria: if unicast addressed
982 * AND no valid forwarding for Target of PREQ, discard this PREQ.
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
&&
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",
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
++;
1010 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1011 "adding originator %6D", preq
->preq_origaddr
, ":");
1013 hrorig
= IEEE80211_MESH_ROUTE_PRIV(rtorig
, struct ieee80211_hwmp_route
);
1015 /* record last seen preqid */
1016 preqid
= hrorig
->hr_preqid
;
1017 hrorig
->hr_preqid
= HWMP_SEQ_MAX(hrorig
->hr_preqid
, preq
->preq_id
);
1019 /* Data creation and update of forwarding information
1020 * according to Table 11C-8 for originator mesh STA.
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.
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
);
1049 /* Update forwarding information to TA if metric improves. */
1050 hwmp_update_transmitter(vap
, ni
, "PREQ");
1053 * Check if the PREQ is addressed to us.
1054 * or a Proxy currently gated by us.
1056 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, PREQ_TADDR(0)) ||
1057 (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
&&
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
;
1065 * When we are the target we shall update our own HWMP seq
1066 * number with max of (current and preq->seq) + 1
1068 hs
->hs_seq
= HWMP_SEQ_MAX(hs
->hs_seq
, PREQ_TSEQ(0)) + 1;
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
,
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
);
1088 * Build and send a PREP frame.
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
;
1096 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1097 "reply to %6D", preq
->preq_origaddr
, ":");
1098 hwmp_send_prep(vap
, wh
->i_addr2
, &prep
);
1101 /* we may update our proxy information for the orig external */
1102 else if (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AE
) {
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
++;
1115 IEEE80211_ADDR_COPY(rtorig_ext
->rt_mesh_gate
,
1116 preq
->preq_origaddr
);
1118 rtorig_ext
->rt_ext_seq
= preq
->preq_origseq
;
1119 ieee80211_mesh_rt_update(rtorig_ext
, preq
->preq_lifetime
);
1122 * Proactive PREQ: reply with a proactive PREP to the
1123 * root STA if requested.
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
, ":");
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
;
1134 rtorig
->rt_flags
|= IEEE80211_MESHRT_FLAGS_GATE
;
1135 gr
= ieee80211_mesh_mark_gate(vap
, preq
->preq_origaddr
,
1137 gr
->gr_lastseq
= 0; /* NOT GANN */
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.
1144 if ((rtorig
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0 ||
1145 (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_PP
)) {
1146 struct ieee80211_meshprep_ie prep
;
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
,
1158 prep
.prep_targetseq
= ++hs
->hs_seq
;
1159 hwmp_send_prep(vap
, rtorig
->rt_nexthop
, &prep
);
1164 * Forwarding and Intermediate reply for PREQs with 1 target.
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 */
1170 memcpy(&ppreq
, preq
, sizeof(ppreq
));
1173 * We have a valid route to this node.
1174 * NB: if target is proxy dont reply.
1176 if (rttarg
!= NULL
&&
1177 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
&&
1178 !(rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
)) {
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.
1184 if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO
) &&
1185 !IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr
)) {
1186 struct ieee80211_meshprep_ie prep
;
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
,
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
);
1205 * Set TO and unset RF bits because we have
1208 ppreq
.preq_targets
[0].target_flags
|=
1209 IEEE80211_MESHPREQ_TFLAGS_TO
;
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
);
1220 /* don't do PREQ ratecheck when we propagate */
1221 hwmp_send_preq(vap
, broadcastaddr
, &ppreq
, NULL
, NULL
);
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
)
1236 * Enforce PREQ interval.
1237 * NB: Proactive ROOT PREQs rate is handled by cb task.
1239 if (last
!= NULL
&& minint
!= NULL
) {
1240 if (ratecheck(last
, minint
) == 0)
1241 return EALREADY
; /* XXX: we should postpone */
1242 getmicrouptime(last
);
1246 * mesh preq action frame format
1252 * [tlv] mesh path request
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);
1262 hwmp_recv_prep(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1263 const struct ieee80211_frame
*wh
, const struct ieee80211_meshprep_ie
*prep
)
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
;
1279 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1280 "received PREP, orig %6D, targ %6D", prep
->prep_origaddr
, ":",
1281 prep
->prep_targetaddr
, ":");
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.
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
, ":");
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.
1307 rt
= ieee80211_mesh_rt_find(vap
, prep
->prep_targetaddr
);
1309 rt
= ieee80211_mesh_rt_add(vap
, prep
->prep_targetaddr
);
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
++;
1317 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1318 "adding target %6D", prep
->prep_targetaddr
, ":");
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
);
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
);
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
);
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
;
1358 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
; /* mark valid */
1360 /* Update forwarding information to TA if metric improves */
1361 hwmp_update_transmitter(vap
, ni
, "PREP");
1364 * If it's NOT for us, propagate the PREP
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 */
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.
1376 if (rtorig
== NULL
) {
1377 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1378 "received PREP for an unknown orig(%6D)",
1379 prep
->prep_origaddr
, ":");
1383 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1384 "propagate PREP from %6D",
1385 prep
->prep_targetaddr
, ":");
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
);
1393 /* precursor list for the Target Mesh STA Address is updated */
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
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
++;
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
);
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 */
1435 * XXX: proxy entries have no HWMP priv data,
1436 * nullify them to be sure?
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
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 */
1453 * All frames in the stageq here should be non-M_ENCAP; or things
1454 * will get very unhappy.
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
);
1462 * If the mbuf has M_ENCAP set, ensure we free it.
1463 * Note that after if_transmit() is called, m is invalid.
1465 (void) ieee80211_vap_xmitpkt(vap
, m
);
1468 #undef PROXIED_BY_US
1472 hwmp_send_prep(struct ieee80211vap
*vap
,
1473 const uint8_t da
[IEEE80211_ADDR_LEN
],
1474 struct ieee80211_meshprep_ie
*prep
)
1476 /* NB: there's no PREP minimum interval. */
1479 * mesh prep action frame format
1485 * [tlv] mesh path reply
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);
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
1498 hwmp_peerdown(struct ieee80211_node
*ni
)
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
;
1506 rt
= ieee80211_mesh_rt_find(vap
, ni
->ni_macaddr
);
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;
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
);
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
1535 hwmp_recv_perr(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1536 const struct ieee80211_frame
*wh
, const struct ieee80211_meshperr_ie
*perr
)
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;
1545 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1546 "received PERR from %6D", wh
->i_addr2
, ":");
1549 * if forwarding is true, prepare pperr
1551 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) {
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 */
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.
1562 for (i
= 0; i
< perr
->perr_ndests
; i
++) {
1563 rt
= ieee80211_mesh_rt_find(vap
, PERR_DADDR(i
));
1566 if (!IEEE80211_ADDR_EQ(rt
->rt_nexthop
, wh
->i_addr2
))
1569 /* found and accepted a PERR ndest element, process it... */
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) {
1579 pperr
->perr_dests
[j
].dest_seq
=
1583 hr
->hr_seq
= PERR_DSEQ(i
);
1585 rt
->rt_flags
&= ~IEEE80211_MESHRT_FLAGS_VALID
;
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
;
1595 case (IEEE80211_REASON_MESH_PERR_NO_PROXY
):
1596 rt_ext
= ieee80211_mesh_rt_find(vap
, PERR_DEXTADDR(i
));
1597 if (rt_ext
!= NULL
) {
1599 ~IEEE80211_MESHRT_FLAGS_VALID
;
1604 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1605 "PERR, unknown reason code %u\n", PERR_DFLAGS(i
));
1606 goto done
; /* XXX: stats?? */
1608 ieee80211_mesh_rt_flush_peer(vap
, PERR_DADDR(i
));
1609 KASSERT(j
< 32, ("PERR, error ndest >= 32 (%u)", j
));
1612 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
, "%s",
1613 "PERR not accepted");
1614 goto done
; /* XXX: stats?? */
1618 * Propagate the PERR if we previously found it on our routing table.
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
;
1625 hwmp_send_perr(vap
, broadcastaddr
, pperr
);
1629 IEEE80211_FREE(pperr
, M_80211_MESH_PERR
);
1634 #undef PERR_DEXTADDR
1637 hwmp_send_perr(struct ieee80211vap
*vap
,
1638 const uint8_t da
[IEEE80211_ADDR_LEN
],
1639 struct ieee80211_meshperr_ie
*perr
)
1641 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
1646 * Enforce PERR interval.
1648 if (ratecheck(&hs
->hs_lastperr
, &ieee80211_hwmp_perrminint
) == 0)
1650 getmicrouptime(&hs
->hs_lastperr
);
1653 * mesh perr action frame format
1659 * [tlv] mesh path error
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
;
1669 length
+= IEEE80211_MESHPERR_DEST_SZ
;
1671 perr
->perr_len
=length
;
1672 return hwmp_send_action(vap
, da
, (uint8_t *)perr
, perr
->perr_len
+2);
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.
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
1686 hwmp_senderror(struct ieee80211vap
*vap
,
1687 const uint8_t addr
[IEEE80211_ADDR_LEN
],
1688 struct ieee80211_mesh_route
*rt
, int rcode
)
1690 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1691 struct ieee80211_hwmp_route
*hr
= NULL
;
1692 struct ieee80211_meshperr_ie perr
;
1695 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
,
1696 struct ieee80211_hwmp_route
);
1698 perr
.perr_ndests
= 1;
1699 perr
.perr_ttl
= ms
->ms_ttl
;
1701 PERR_DRCODE(0) = rcode
;
1704 case IEEE80211_REASON_MESH_PERR_NO_FI
:
1705 IEEE80211_ADDR_COPY(PERR_DADDR(0), addr
);
1706 PERR_DSEQ(0) = 0; /* reserved */
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
);
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
;
1723 KASSERT(0, ("unknown reason code for HWMP PERR (%u)", rcode
));
1725 hwmp_send_perr(vap
, broadcastaddr
, &perr
);
1730 #undef PERR_DEXTADDR
1734 hwmp_recv_rann(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1735 const struct ieee80211_frame
*wh
, const struct ieee80211_meshrann_ie
*rann
)
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
;
1744 if (IEEE80211_ADDR_EQ(rann
->rann_addr
, vap
->iv_myaddr
))
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
);
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
);
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
);
1770 ieee80211_hwmp_rannint
= rann
->rann_interval
; /* XXX: mtx lock? */
1773 rt
= ieee80211_mesh_rt_add(vap
, rann
->rann_addr
);
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
++;
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
;
1787 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_GATE
;
1788 gr
= ieee80211_mesh_mark_gate(vap
, rann
->rann_addr
,
1790 gr
->gr_lastseq
= 0; /* NOT GANN */
1792 /* discovery timeout */
1793 ieee80211_mesh_rt_update(rt
,
1794 ticks_to_msecs(ieee80211_hwmp_roottimeout
));
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
);
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
);
1827 hwmp_send_rann(struct ieee80211vap
*vap
,
1828 const uint8_t da
[IEEE80211_ADDR_LEN
],
1829 struct ieee80211_meshrann_ie
*rann
)
1832 * mesh rann action frame format
1838 * [tlv] root announcement
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);
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
1849 hwmp_rediscover_cb(void *arg
)
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? */
1858 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
))
1859 return ; /* nothing to do */
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
,
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? */
1872 hr
->hr_preqretries
++;
1874 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
, rt
->rt_dest
,
1875 "start path rediscovery , target seq %u", hr
->hr_seq
);
1877 * Try to discover the path for this node.
1878 * Group addressed PREQ Case A
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
);
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
);
1903 static struct ieee80211_node
*
1904 hwmp_discover(struct ieee80211vap
*vap
,
1905 const uint8_t dest
[IEEE80211_ADDR_LEN
], struct mbuf
*m
)
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
;
1915 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
,
1916 ("not a mesh vap, opmode %d", vap
->iv_opmode
));
1918 KASSERT(!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, dest
),
1919 ("%s: discovering self!", __func__
));
1922 if (!IEEE80211_IS_MULTICAST(dest
)) {
1923 rt
= ieee80211_mesh_rt_find(vap
, dest
);
1925 rt
= ieee80211_mesh_rt_add(vap
, dest
);
1927 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_HWMP
,
1928 "unable to add discovery path to %6D",
1930 vap
->iv_stats
.is_mesh_rtaddfailed
++;
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");
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
,
1948 "too frequent discovery requeust");
1952 hr
->hr_lastdiscovery
= ticks
;
1953 if (hr
->hr_preqretries
>=
1954 ieee80211_hwmp_maxpreq_retries
) {
1955 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1957 "no valid path , max number of discovery");
1958 vap
->iv_stats
.is_mesh_fwd_nopath
++;
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
;
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
),
1973 * Try to discover the path for this node.
1974 * Group addressed PREQ Case A
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
);
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
);
1999 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
)
2000 ni
= ieee80211_find_txnode(vap
, rt
->rt_nexthop
);
2002 ni
= ieee80211_find_txnode(vap
, dest
);
2003 /* NB: if null then we leak mbuf */
2004 KASSERT(ni
!= NULL
, ("leak mcast frame"));
2008 if (ni
== NULL
&& m
!= NULL
) {
2010 struct ieee80211com
*ic
= vap
->iv_ic
;
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.
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
);
2025 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_HWMP
,
2026 dest
, NULL
, "%s", "no valid path to this node");
2037 hwmp_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2039 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2042 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2045 switch (ireq
->i_type
) {
2046 case IEEE80211_IOC_HWMP_ROOTMODE
:
2047 ireq
->i_val
= hs
->hs_rootmode
;
2049 case IEEE80211_IOC_HWMP_MAXHOPS
:
2050 ireq
->i_val
= hs
->hs_maxhops
;
2057 IEEE80211_IOCTL_GET(hwmp
, hwmp_ioctl_get80211
);
2060 hwmp_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2062 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2065 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2068 switch (ireq
->i_type
) {
2069 case IEEE80211_IOC_HWMP_ROOTMODE
:
2070 if (ireq
->i_val
< 0 || ireq
->i_val
> 3)
2072 hs
->hs_rootmode
= ireq
->i_val
;
2073 hwmp_rootmode_setup(vap
);
2075 case IEEE80211_IOC_HWMP_MAXHOPS
:
2076 if (ireq
->i_val
<= 0 || ireq
->i_val
> 255)
2078 hs
->hs_maxhops
= ireq
->i_val
;
2085 IEEE80211_IOCTL_SET(hwmp
, hwmp_ioctl_set80211
);