2 * Copyright (c) 2009 The FreeBSD Foundation
5 * This software was developed by Rui Paulo under sponsorship from the
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
35 * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
37 * Based on March 2009, D3.0 802.11s draft spec.
42 #include <sys/param.h>
43 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/kernel.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/endian.h>
51 #include <sys/errno.h>
53 #include <sys/sysctl.h>
56 #include <net/if_var.h>
57 #include <net/if_media.h>
58 #include <net/if_llc.h>
59 #include <net/ethernet.h>
63 #include <netproto/802_11/ieee80211_var.h>
64 #include <netproto/802_11/ieee80211_action.h>
65 #include <netproto/802_11/ieee80211_input.h>
66 #include <netproto/802_11/ieee80211_mesh.h>
68 static void hwmp_vattach(struct ieee80211vap
*);
69 static void hwmp_vdetach(struct ieee80211vap
*);
70 static int hwmp_newstate(struct ieee80211vap
*,
71 enum ieee80211_state
, int);
72 static int hwmp_send_action(struct ieee80211vap
*,
73 const uint8_t [IEEE80211_ADDR_LEN
],
75 static uint8_t * hwmp_add_meshpreq(uint8_t *,
76 const struct ieee80211_meshpreq_ie
*);
77 static uint8_t * hwmp_add_meshprep(uint8_t *,
78 const struct ieee80211_meshprep_ie
*);
79 static uint8_t * hwmp_add_meshperr(uint8_t *,
80 const struct ieee80211_meshperr_ie
*);
81 static uint8_t * hwmp_add_meshrann(uint8_t *,
82 const struct ieee80211_meshrann_ie
*);
83 static void hwmp_rootmode_setup(struct ieee80211vap
*);
84 static void hwmp_rootmode_cb(void *);
85 static void hwmp_rootmode_rann_cb(void *);
86 static void hwmp_recv_preq(struct ieee80211vap
*, struct ieee80211_node
*,
87 const struct ieee80211_frame
*,
88 const struct ieee80211_meshpreq_ie
*);
89 static int hwmp_send_preq(struct ieee80211vap
*,
90 const uint8_t [IEEE80211_ADDR_LEN
],
91 struct ieee80211_meshpreq_ie
*,
92 struct timeval
*, struct timeval
*);
93 static void hwmp_recv_prep(struct ieee80211vap
*, struct ieee80211_node
*,
94 const struct ieee80211_frame
*,
95 const struct ieee80211_meshprep_ie
*);
96 static int hwmp_send_prep(struct ieee80211vap
*,
97 const uint8_t [IEEE80211_ADDR_LEN
],
98 struct ieee80211_meshprep_ie
*);
99 static void hwmp_recv_perr(struct ieee80211vap
*, struct ieee80211_node
*,
100 const struct ieee80211_frame
*,
101 const struct ieee80211_meshperr_ie
*);
102 static int hwmp_send_perr(struct ieee80211vap
*,
103 const uint8_t [IEEE80211_ADDR_LEN
],
104 struct ieee80211_meshperr_ie
*);
105 static void hwmp_senderror(struct ieee80211vap
*,
106 const uint8_t [IEEE80211_ADDR_LEN
],
107 struct ieee80211_mesh_route
*, int);
108 static void hwmp_recv_rann(struct ieee80211vap
*, struct ieee80211_node
*,
109 const struct ieee80211_frame
*,
110 const struct ieee80211_meshrann_ie
*);
111 static int hwmp_send_rann(struct ieee80211vap
*,
112 const uint8_t [IEEE80211_ADDR_LEN
],
113 struct ieee80211_meshrann_ie
*);
114 static struct ieee80211_node
*
115 hwmp_discover(struct ieee80211vap
*,
116 const uint8_t [IEEE80211_ADDR_LEN
], struct mbuf
*);
117 static void hwmp_peerdown(struct ieee80211_node
*);
119 static struct timeval ieee80211_hwmp_preqminint
= { 0, 100000 };
120 static struct timeval ieee80211_hwmp_perrminint
= { 0, 100000 };
123 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
124 static const uint8_t broadcastaddr
[IEEE80211_ADDR_LEN
] =
125 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
127 typedef uint32_t ieee80211_hwmp_seq
;
128 #define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0)
129 #define HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
130 #define HWMP_SEQ_EQ(a, b) ((int32_t)((a)-(b)) == 0)
131 #define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0)
132 #define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
134 #define HWMP_SEQ_MAX(a, b) (a > b ? a : b)
137 * Private extension of ieee80211_mesh_route.
139 struct ieee80211_hwmp_route
{
140 ieee80211_hwmp_seq hr_seq
; /* last HWMP seq seen from dst*/
141 ieee80211_hwmp_seq hr_preqid
; /* last PREQ ID seen from dst */
142 ieee80211_hwmp_seq hr_origseq
; /* seq. no. on our latest PREQ*/
143 struct timeval hr_lastpreq
; /* last time we sent a PREQ */
144 struct timeval hr_lastrootconf
; /* last sent PREQ root conf */
145 int hr_preqretries
; /* number of discoveries */
146 int hr_lastdiscovery
; /* last discovery in ticks */
148 struct ieee80211_hwmp_state
{
149 ieee80211_hwmp_seq hs_seq
; /* next seq to be used */
150 ieee80211_hwmp_seq hs_preqid
; /* next PREQ ID to be used */
151 int hs_rootmode
; /* proactive HWMP */
152 struct timeval hs_lastperr
; /* last time we sent a PERR */
153 struct callout hs_roottimer
;
154 uint8_t hs_maxhops
; /* max hop count */
157 static SYSCTL_NODE(_net_wlan
, OID_AUTO
, hwmp
, CTLFLAG_RD
, 0,
158 "IEEE 802.11s HWMP parameters");
159 static int ieee80211_hwmp_targetonly
= 0;
160 SYSCTL_INT(_net_wlan_hwmp
, OID_AUTO
, targetonly
, CTLFLAG_RW
,
161 &ieee80211_hwmp_targetonly
, 0, "Set TO bit on generated PREQs");
162 static int ieee80211_hwmp_pathtimeout
= -1;
163 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, pathlifetime
, CTLTYPE_INT
| CTLFLAG_RW
,
164 &ieee80211_hwmp_pathtimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
165 "path entry lifetime (ms)");
166 static int ieee80211_hwmp_maxpreq_retries
= -1;
167 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, maxpreq_retries
, CTLTYPE_INT
| CTLFLAG_RW
,
168 &ieee80211_hwmp_maxpreq_retries
, 0, ieee80211_sysctl_msecs_ticks
, "I",
169 "maximum number of preq retries");
170 static int ieee80211_hwmp_net_diameter_traversaltime
= -1;
171 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, net_diameter_traversal_time
,
172 CTLTYPE_INT
| CTLFLAG_RW
, &ieee80211_hwmp_net_diameter_traversaltime
, 0,
173 ieee80211_sysctl_msecs_ticks
, "I",
174 "estimate travelse time across the MBSS (ms)");
175 static int ieee80211_hwmp_roottimeout
= -1;
176 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, roottimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
177 &ieee80211_hwmp_roottimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
178 "root PREQ timeout (ms)");
179 static int ieee80211_hwmp_rootint
= -1;
180 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, rootint
, CTLTYPE_INT
| CTLFLAG_RW
,
181 &ieee80211_hwmp_rootint
, 0, ieee80211_sysctl_msecs_ticks
, "I",
182 "root interval (ms)");
183 static int ieee80211_hwmp_rannint
= -1;
184 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, rannint
, CTLTYPE_INT
| CTLFLAG_RW
,
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
, CTLTYPE_INT
| CTLFLAG_RD
,
190 &ieee80211_hwmp_rootconfint_internal
, 0, ieee80211_sysctl_msecs_ticks
, "I",
191 "root confirmation interval (ms) (read-only)");
193 #define IEEE80211_HWMP_DEFAULT_MAXHOPS 31
195 static ieee80211_recv_action_func hwmp_recv_action_meshpath
;
197 static struct ieee80211_mesh_proto_path mesh_proto_hwmp
= {
199 .mpp_ie
= IEEE80211_MESHCONF_PATH_HWMP
,
200 .mpp_discover
= hwmp_discover
,
201 .mpp_peerdown
= hwmp_peerdown
,
202 .mpp_senderror
= hwmp_senderror
,
203 .mpp_vattach
= hwmp_vattach
,
204 .mpp_vdetach
= hwmp_vdetach
,
205 .mpp_newstate
= hwmp_newstate
,
206 .mpp_privlen
= sizeof(struct ieee80211_hwmp_route
),
208 SYSCTL_PROC(_net_wlan_hwmp
, OID_AUTO
, inact
, CTLTYPE_INT
| CTLFLAG_RW
,
209 &mesh_proto_hwmp
.mpp_inact
, 0, ieee80211_sysctl_msecs_ticks
, "I",
210 "mesh route inactivity timeout (ms)");
214 ieee80211_hwmp_init(void)
216 /* Default values as per amendment */
217 ieee80211_hwmp_pathtimeout
= msecs_to_ticks(5*1000);
218 ieee80211_hwmp_roottimeout
= msecs_to_ticks(5*1000);
219 ieee80211_hwmp_rootint
= msecs_to_ticks(2*1000);
220 ieee80211_hwmp_rannint
= msecs_to_ticks(1*1000);
221 ieee80211_hwmp_rootconfint_internal
= msecs_to_ticks(2*1000);
222 ieee80211_hwmp_maxpreq_retries
= 3;
224 * (TU): A measurement of time equal to 1024 μs,
227 ieee80211_hwmp_net_diameter_traversaltime
= msecs_to_ticks(512);
230 * NB: I dont know how to make SYSCTL_PROC that calls ms to ticks
231 * and return a struct timeval...
233 ieee80211_hwmp_rootconfint
.tv_usec
=
234 ieee80211_hwmp_rootconfint_internal
* 1000;
237 * Register action frame handler.
239 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH
,
240 IEEE80211_ACTION_MESH_HWMP
, hwmp_recv_action_meshpath
);
242 /* NB: default is 5 secs per spec */
243 mesh_proto_hwmp
.mpp_inact
= msecs_to_ticks(5*1000);
248 ieee80211_mesh_register_proto_path(&mesh_proto_hwmp
);
250 SYSINIT(wlan_hwmp
, SI_SUB_DRIVERS
, SI_ORDER_SECOND
, ieee80211_hwmp_init
, NULL
);
253 hwmp_vattach(struct ieee80211vap
*vap
)
255 struct ieee80211_hwmp_state
*hs
;
257 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
,
258 ("not a mesh vap, opmode %d", vap
->iv_opmode
));
260 #if defined(__DragonFly__)
261 hs
= kmalloc(sizeof(struct ieee80211_hwmp_state
), M_80211_VAP
,
264 hs
= IEEE80211_MALLOC(sizeof(struct ieee80211_hwmp_state
), M_80211_VAP
,
265 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
268 kprintf("%s: couldn't alloc HWMP state\n", __func__
);
271 hs
->hs_maxhops
= IEEE80211_HWMP_DEFAULT_MAXHOPS
;
272 #if defined(__DragonFly__)
273 callout_init_mp(&hs
->hs_roottimer
);
275 callout_init(&hs
->hs_roottimer
, 1);
281 hwmp_vdetach(struct ieee80211vap
*vap
)
283 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
285 callout_drain(&hs
->hs_roottimer
);
286 IEEE80211_FREE(vap
->iv_hwmp
, M_80211_VAP
);
291 hwmp_newstate(struct ieee80211vap
*vap
, enum ieee80211_state ostate
, int arg
)
293 enum ieee80211_state nstate
= vap
->iv_state
;
294 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
296 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
297 __func__
, ieee80211_state_name
[ostate
],
298 ieee80211_state_name
[nstate
], arg
);
300 if (nstate
!= IEEE80211_S_RUN
&& ostate
== IEEE80211_S_RUN
)
301 callout_drain(&hs
->hs_roottimer
);
302 if (nstate
== IEEE80211_S_RUN
)
303 hwmp_rootmode_setup(vap
);
308 * Verify the length of an HWMP PREQ and return the number
309 * of destinations >= 1, if verification fails -1 is returned.
312 verify_mesh_preq_len(struct ieee80211vap
*vap
,
313 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
317 if (iefrm
[2] & IEEE80211_MESHPREQ_FLAGS_AE
) {
318 /* Originator External Address present */
319 alloc_sz
= IEEE80211_MESHPREQ_BASE_SZ_AE
;
320 ndest
= iefrm
[IEEE80211_MESHPREQ_TCNT_OFFSET_AE
];
322 /* w/o Originator External Address */
323 alloc_sz
= IEEE80211_MESHPREQ_BASE_SZ
;
324 ndest
= iefrm
[IEEE80211_MESHPREQ_TCNT_OFFSET
];
326 alloc_sz
+= ndest
* IEEE80211_MESHPREQ_TRGT_SZ
;
328 if(iefrm
[1] != (alloc_sz
)) {
329 IEEE80211_DISCARD(vap
,
330 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
331 wh
, NULL
, "PREQ (AE=%s) with wrong len",
332 iefrm
[2] & IEEE80211_MESHPREQ_FLAGS_AE
? "1" : "0");
339 * Verify the length of an HWMP PREP and returns 1 on success,
343 verify_mesh_prep_len(struct ieee80211vap
*vap
,
344 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
347 if (iefrm
[2] & IEEE80211_MESHPREP_FLAGS_AE
) {
348 if (iefrm
[1] == IEEE80211_MESHPREP_BASE_SZ_AE
)
349 alloc_sz
= IEEE80211_MESHPREP_BASE_SZ_AE
;
350 } else if (iefrm
[1] == IEEE80211_MESHPREP_BASE_SZ
)
351 alloc_sz
= IEEE80211_MESHPREP_BASE_SZ
;
353 IEEE80211_DISCARD(vap
,
354 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
355 wh
, NULL
, "PREP (AE=%s) with wrong len",
356 iefrm
[2] & IEEE80211_MESHPREP_FLAGS_AE
? "1" : "0");
363 * Verify the length of an HWMP PERR and return the number
364 * of destinations >= 1, if verification fails -1 is returned.
367 verify_mesh_perr_len(struct ieee80211vap
*vap
,
368 const struct ieee80211_frame
*wh
, const uint8_t *iefrm
)
371 const uint8_t *iefrm_t
= iefrm
;
372 uint8_t ndest
= iefrm_t
[IEEE80211_MESHPERR_NDEST_OFFSET
];
375 if(ndest
> IEEE80211_MESHPERR_MAXDEST
) {
376 IEEE80211_DISCARD(vap
,
377 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
378 wh
, NULL
, "PERR with wrong number of destionat (>19), %u",
383 iefrm_t
+= IEEE80211_MESHPERR_NDEST_OFFSET
+ 1; /* flag is next field */
384 /* We need to check each destionation flag to know size */
385 for(i
= 0; i
<ndest
; i
++) {
386 if ((*iefrm_t
) & IEEE80211_MESHPERR_FLAGS_AE
)
387 iefrm_t
+= IEEE80211_MESHPERR_DEST_SZ_AE
;
389 iefrm_t
+= IEEE80211_MESHPERR_DEST_SZ
;
392 alloc_sz
= (iefrm_t
- iefrm
) - 2; /* action + code */
393 if(alloc_sz
!= iefrm
[1]) {
394 IEEE80211_DISCARD(vap
,
395 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
396 wh
, NULL
, "%s", "PERR with wrong len");
403 hwmp_recv_action_meshpath(struct ieee80211_node
*ni
,
404 const struct ieee80211_frame
*wh
,
405 const uint8_t *frm
, const uint8_t *efrm
)
407 struct ieee80211vap
*vap
= ni
->ni_vap
;
408 struct ieee80211_meshpreq_ie
*preq
;
409 struct ieee80211_meshprep_ie
*prep
;
410 struct ieee80211_meshperr_ie
*perr
;
411 struct ieee80211_meshrann_ie rann
;
412 const uint8_t *iefrm
= frm
+ 2; /* action + code */
413 const uint8_t *iefrm_t
= iefrm
; /* temporary pointer */
417 while (efrm
- iefrm
> 1) {
418 IEEE80211_VERIFY_LENGTH(efrm
- iefrm
, iefrm
[1] + 2, return 0);
420 case IEEE80211_ELEMID_MESHPREQ
:
425 ndest
= verify_mesh_preq_len(vap
, wh
, iefrm_t
);
427 vap
->iv_stats
.is_rx_mgtdiscard
++;
430 #if defined(__DragonFly__)
431 preq
= kmalloc(sizeof(*preq
) +
432 (ndest
- 1) * sizeof(*preq
->preq_targets
),
433 M_80211_MESH_PREQ
, M_INTWAIT
| M_ZERO
);
435 preq
= IEEE80211_MALLOC(sizeof(*preq
) +
436 (ndest
- 1) * sizeof(*preq
->preq_targets
),
438 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
440 KASSERT(preq
!= NULL
, ("preq == NULL"));
442 preq
->preq_ie
= *iefrm_t
++;
443 preq
->preq_len
= *iefrm_t
++;
444 preq
->preq_flags
= *iefrm_t
++;
445 preq
->preq_hopcount
= *iefrm_t
++;
446 preq
->preq_ttl
= *iefrm_t
++;
447 preq
->preq_id
= le32dec(iefrm_t
); iefrm_t
+= 4;
448 IEEE80211_ADDR_COPY(preq
->preq_origaddr
, iefrm_t
);
450 preq
->preq_origseq
= le32dec(iefrm_t
); iefrm_t
+= 4;
451 /* NB: may have Originator Proxied Address */
452 if (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AE
) {
454 preq
->preq_orig_ext_addr
, iefrm_t
);
457 preq
->preq_lifetime
= le32dec(iefrm_t
); iefrm_t
+= 4;
458 preq
->preq_metric
= le32dec(iefrm_t
); iefrm_t
+= 4;
459 preq
->preq_tcount
= *iefrm_t
++;
461 for (i
= 0; i
< preq
->preq_tcount
; i
++) {
462 preq
->preq_targets
[i
].target_flags
= *iefrm_t
++;
464 preq
->preq_targets
[i
].target_addr
, iefrm_t
);
466 preq
->preq_targets
[i
].target_seq
=
471 hwmp_recv_preq(vap
, ni
, wh
, preq
);
472 IEEE80211_FREE(preq
, M_80211_MESH_PREQ
);
476 case IEEE80211_ELEMID_MESHPREP
:
479 ndest
= verify_mesh_prep_len(vap
, wh
, iefrm_t
);
481 vap
->iv_stats
.is_rx_mgtdiscard
++;
484 #if defined(__DragonFly__)
485 prep
= kmalloc(sizeof(*prep
),
486 M_80211_MESH_PREP
, M_INTWAIT
| M_ZERO
);
488 prep
= IEEE80211_MALLOC(sizeof(*prep
),
490 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
492 KASSERT(prep
!= NULL
, ("prep == NULL"));
494 prep
->prep_ie
= *iefrm_t
++;
495 prep
->prep_len
= *iefrm_t
++;
496 prep
->prep_flags
= *iefrm_t
++;
497 prep
->prep_hopcount
= *iefrm_t
++;
498 prep
->prep_ttl
= *iefrm_t
++;
499 IEEE80211_ADDR_COPY(prep
->prep_targetaddr
, iefrm_t
);
501 prep
->prep_targetseq
= le32dec(iefrm_t
); iefrm_t
+= 4;
502 /* NB: May have Target Proxied Address */
503 if (prep
->prep_flags
& IEEE80211_MESHPREP_FLAGS_AE
) {
505 prep
->prep_target_ext_addr
, iefrm_t
);
508 prep
->prep_lifetime
= le32dec(iefrm_t
); iefrm_t
+= 4;
509 prep
->prep_metric
= le32dec(iefrm_t
); iefrm_t
+= 4;
510 IEEE80211_ADDR_COPY(prep
->prep_origaddr
, iefrm_t
);
512 prep
->prep_origseq
= le32dec(iefrm_t
); iefrm_t
+= 4;
514 hwmp_recv_prep(vap
, ni
, wh
, prep
);
515 IEEE80211_FREE(prep
, M_80211_MESH_PREP
);
519 case IEEE80211_ELEMID_MESHPERR
:
524 ndest
= verify_mesh_perr_len(vap
, wh
, iefrm_t
);
526 vap
->iv_stats
.is_rx_mgtdiscard
++;
529 #if defined(__DragonFly__)
530 perr
= kmalloc(sizeof(*perr
) +
531 (ndest
- 1) * sizeof(*perr
->perr_dests
),
532 M_80211_MESH_PERR
, M_INTWAIT
| M_ZERO
);
534 perr
= IEEE80211_MALLOC(sizeof(*perr
) +
535 (ndest
- 1) * sizeof(*perr
->perr_dests
),
537 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
539 KASSERT(perr
!= NULL
, ("perr == NULL"));
541 perr
->perr_ie
= *iefrm_t
++;
542 perr
->perr_len
= *iefrm_t
++;
543 perr
->perr_ttl
= *iefrm_t
++;
544 perr
->perr_ndests
= *iefrm_t
++;
546 for (i
= 0; i
<perr
->perr_ndests
; i
++) {
547 perr
->perr_dests
[i
].dest_flags
= *iefrm_t
++;
549 perr
->perr_dests
[i
].dest_addr
, iefrm_t
);
551 perr
->perr_dests
[i
].dest_seq
= le32dec(iefrm_t
);
553 /* NB: May have Target Proxied Address */
554 if (perr
->perr_dests
[i
].dest_flags
&
555 IEEE80211_MESHPERR_FLAGS_AE
) {
557 perr
->perr_dests
[i
].dest_ext_addr
,
561 perr
->perr_dests
[i
].dest_rcode
=
566 hwmp_recv_perr(vap
, ni
, wh
, perr
);
567 IEEE80211_FREE(perr
, M_80211_MESH_PERR
);
571 case IEEE80211_ELEMID_MESHRANN
:
573 const struct ieee80211_meshrann_ie
*mrann
=
574 (const struct ieee80211_meshrann_ie
*) iefrm
;
575 if (mrann
->rann_len
!=
576 sizeof(struct ieee80211_meshrann_ie
) - 2) {
577 IEEE80211_DISCARD(vap
,
578 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
579 wh
, NULL
, "%s", "RAN with wrong len");
580 vap
->iv_stats
.is_rx_mgtdiscard
++;
583 memcpy(&rann
, mrann
, sizeof(rann
));
584 rann
.rann_seq
= le32dec(&mrann
->rann_seq
);
585 rann
.rann_interval
= le32dec(&mrann
->rann_interval
);
586 rann
.rann_metric
= le32dec(&mrann
->rann_metric
);
587 hwmp_recv_rann(vap
, ni
, wh
, &rann
);
592 iefrm
+= iefrm
[1] + 2;
595 IEEE80211_DISCARD(vap
,
596 IEEE80211_MSG_ACTION
| IEEE80211_MSG_HWMP
,
597 wh
, NULL
, "%s", "PATH SEL action without IE");
598 vap
->iv_stats
.is_rx_mgtdiscard
++;
604 hwmp_send_action(struct ieee80211vap
*vap
,
605 const uint8_t da
[IEEE80211_ADDR_LEN
],
606 uint8_t *ie
, size_t len
)
608 struct ieee80211_node
*ni
;
609 struct ieee80211com
*ic
;
610 struct ieee80211_bpf_params params
;
615 if (IEEE80211_IS_MULTICAST(da
)) {
616 ni
= ieee80211_ref_node(vap
->iv_bss
);
617 #ifdef IEEE80211_DEBUG_REFCNT
618 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
619 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
621 ni
, ether_sprintf(ni
->ni_macaddr
),
622 ieee80211_node_refcnt(ni
)+1);
624 ieee80211_ref_node(ni
);
627 ni
= ieee80211_mesh_find_txnode(vap
, da
);
629 if (vap
->iv_state
== IEEE80211_S_CAC
) {
630 IEEE80211_NOTE(vap
, IEEE80211_MSG_OUTPUT
, ni
,
631 "block %s frame in CAC state", "HWMP action");
632 vap
->iv_stats
.is_tx_badstate
++;
633 return EIO
; /* XXX */
636 KASSERT(ni
!= NULL
, ("null node"));
639 m
= ieee80211_getmgtframe(&frm
,
640 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
641 sizeof(struct ieee80211_action
) + len
644 ieee80211_free_node(ni
);
645 vap
->iv_stats
.is_tx_nobuf
++;
648 *frm
++ = IEEE80211_ACTION_CAT_MESH
;
649 *frm
++ = IEEE80211_ACTION_MESH_HWMP
;
651 case IEEE80211_ELEMID_MESHPREQ
:
652 frm
= hwmp_add_meshpreq(frm
,
653 (struct ieee80211_meshpreq_ie
*)ie
);
655 case IEEE80211_ELEMID_MESHPREP
:
656 frm
= hwmp_add_meshprep(frm
,
657 (struct ieee80211_meshprep_ie
*)ie
);
659 case IEEE80211_ELEMID_MESHPERR
:
660 frm
= hwmp_add_meshperr(frm
,
661 (struct ieee80211_meshperr_ie
*)ie
);
663 case IEEE80211_ELEMID_MESHRANN
:
664 frm
= hwmp_add_meshrann(frm
,
665 (struct ieee80211_meshrann_ie
*)ie
);
669 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
670 M_PREPEND(m
, sizeof(struct ieee80211_frame
), M_NOWAIT
);
672 ieee80211_free_node(ni
);
673 vap
->iv_stats
.is_tx_nobuf
++;
677 IEEE80211_TX_LOCK(ic
);
679 ieee80211_send_setup(ni
, m
,
680 IEEE80211_FC0_TYPE_MGT
| IEEE80211_FC0_SUBTYPE_ACTION
,
681 IEEE80211_NONQOS_TID
, vap
->iv_myaddr
, da
, vap
->iv_myaddr
);
683 m
->m_flags
|= M_ENCAP
; /* mark encapsulated */
684 IEEE80211_NODE_STAT(ni
, tx_mgmt
);
686 memset(¶ms
, 0, sizeof(params
));
687 params
.ibp_pri
= WME_AC_VO
;
688 params
.ibp_rate0
= ni
->ni_txparms
->mgmtrate
;
689 if (IEEE80211_IS_MULTICAST(da
))
692 params
.ibp_try0
= ni
->ni_txparms
->maxretry
;
693 params
.ibp_power
= ni
->ni_txpower
;
694 ret
= ieee80211_raw_output(vap
, ni
, m
, ¶ms
);
695 IEEE80211_TX_UNLOCK(ic
);
699 #define ADDSHORT(frm, v) do { \
703 #define ADDWORD(frm, v) do { \
708 * Add a Mesh Path Request IE to a frame.
710 #define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags
711 #define PREQ_TADDR(n) preq->preq_targets[n].target_addr
712 #define PREQ_TSEQ(n) preq->preq_targets[n].target_seq
714 hwmp_add_meshpreq(uint8_t *frm
, const struct ieee80211_meshpreq_ie
*preq
)
718 *frm
++ = IEEE80211_ELEMID_MESHPREQ
;
719 *frm
++ = preq
->preq_len
; /* len already calculated */
720 *frm
++ = preq
->preq_flags
;
721 *frm
++ = preq
->preq_hopcount
;
722 *frm
++ = preq
->preq_ttl
;
723 ADDWORD(frm
, preq
->preq_id
);
724 IEEE80211_ADDR_COPY(frm
, preq
->preq_origaddr
); frm
+= 6;
725 ADDWORD(frm
, preq
->preq_origseq
);
726 if (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AE
) {
727 IEEE80211_ADDR_COPY(frm
, preq
->preq_orig_ext_addr
);
730 ADDWORD(frm
, preq
->preq_lifetime
);
731 ADDWORD(frm
, preq
->preq_metric
);
732 *frm
++ = preq
->preq_tcount
;
733 for (i
= 0; i
< preq
->preq_tcount
; i
++) {
734 *frm
++ = PREQ_TFLAGS(i
);
735 IEEE80211_ADDR_COPY(frm
, PREQ_TADDR(i
));
737 ADDWORD(frm
, PREQ_TSEQ(i
));
746 * Add a Mesh Path Reply IE to a frame.
749 hwmp_add_meshprep(uint8_t *frm
, const struct ieee80211_meshprep_ie
*prep
)
751 *frm
++ = IEEE80211_ELEMID_MESHPREP
;
752 *frm
++ = prep
->prep_len
; /* len already calculated */
753 *frm
++ = prep
->prep_flags
;
754 *frm
++ = prep
->prep_hopcount
;
755 *frm
++ = prep
->prep_ttl
;
756 IEEE80211_ADDR_COPY(frm
, prep
->prep_targetaddr
); frm
+= 6;
757 ADDWORD(frm
, prep
->prep_targetseq
);
758 if (prep
->prep_flags
& IEEE80211_MESHPREP_FLAGS_AE
) {
759 IEEE80211_ADDR_COPY(frm
, prep
->prep_target_ext_addr
);
762 ADDWORD(frm
, prep
->prep_lifetime
);
763 ADDWORD(frm
, prep
->prep_metric
);
764 IEEE80211_ADDR_COPY(frm
, prep
->prep_origaddr
); frm
+= 6;
765 ADDWORD(frm
, prep
->prep_origseq
);
770 * Add a Mesh Path Error IE to a frame.
772 #define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
773 #define PERR_DADDR(n) perr->perr_dests[n].dest_addr
774 #define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
775 #define PERR_EXTADDR(n) perr->perr_dests[n].dest_ext_addr
776 #define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
778 hwmp_add_meshperr(uint8_t *frm
, const struct ieee80211_meshperr_ie
*perr
)
782 *frm
++ = IEEE80211_ELEMID_MESHPERR
;
783 *frm
++ = perr
->perr_len
; /* len already calculated */
784 *frm
++ = perr
->perr_ttl
;
785 *frm
++ = perr
->perr_ndests
;
786 for (i
= 0; i
< perr
->perr_ndests
; i
++) {
787 *frm
++ = PERR_DFLAGS(i
);
788 IEEE80211_ADDR_COPY(frm
, PERR_DADDR(i
));
790 ADDWORD(frm
, PERR_DSEQ(i
));
791 if (PERR_DFLAGS(i
) & IEEE80211_MESHPERR_FLAGS_AE
) {
792 IEEE80211_ADDR_COPY(frm
, PERR_EXTADDR(i
));
795 ADDSHORT(frm
, PERR_DRCODE(i
));
806 * Add a Root Annoucement IE to a frame.
809 hwmp_add_meshrann(uint8_t *frm
, const struct ieee80211_meshrann_ie
*rann
)
811 *frm
++ = IEEE80211_ELEMID_MESHRANN
;
812 *frm
++ = rann
->rann_len
;
813 *frm
++ = rann
->rann_flags
;
814 *frm
++ = rann
->rann_hopcount
;
815 *frm
++ = rann
->rann_ttl
;
816 IEEE80211_ADDR_COPY(frm
, rann
->rann_addr
); frm
+= 6;
817 ADDWORD(frm
, rann
->rann_seq
);
818 ADDWORD(frm
, rann
->rann_interval
);
819 ADDWORD(frm
, rann
->rann_metric
);
824 hwmp_rootmode_setup(struct ieee80211vap
*vap
)
826 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
827 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
829 switch (hs
->hs_rootmode
) {
830 case IEEE80211_HWMP_ROOTMODE_DISABLED
:
831 callout_drain(&hs
->hs_roottimer
);
832 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_ROOT
;
834 case IEEE80211_HWMP_ROOTMODE_NORMAL
:
835 case IEEE80211_HWMP_ROOTMODE_PROACTIVE
:
836 callout_reset(&hs
->hs_roottimer
, ieee80211_hwmp_rootint
,
837 hwmp_rootmode_cb
, vap
);
838 ms
->ms_flags
|= IEEE80211_MESHFLAGS_ROOT
;
840 case IEEE80211_HWMP_ROOTMODE_RANN
:
841 callout_reset(&hs
->hs_roottimer
, ieee80211_hwmp_rannint
,
842 hwmp_rootmode_rann_cb
, vap
);
843 ms
->ms_flags
|= IEEE80211_MESHFLAGS_ROOT
;
849 * Send a broadcast Path Request to find all nodes on the mesh. We are
850 * called when the vap is configured as a HWMP root node.
852 #define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags
853 #define PREQ_TADDR(n) preq.preq_targets[n].target_addr
854 #define PREQ_TSEQ(n) preq.preq_targets[n].target_seq
856 hwmp_rootmode_cb(void *arg
)
858 struct ieee80211vap
*vap
= (struct ieee80211vap
*)arg
;
859 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
860 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
861 struct ieee80211_meshpreq_ie preq
;
863 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, vap
->iv_bss
,
864 "%s", "send broadcast PREQ");
867 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
)
868 preq
.preq_flags
|= IEEE80211_MESHPREQ_FLAGS_GATE
;
869 if (hs
->hs_rootmode
== IEEE80211_HWMP_ROOTMODE_PROACTIVE
)
870 preq
.preq_flags
|= IEEE80211_MESHPREQ_FLAGS_PP
;
871 preq
.preq_hopcount
= 0;
872 preq
.preq_ttl
= ms
->ms_ttl
;
873 preq
.preq_id
= ++hs
->hs_preqid
;
874 IEEE80211_ADDR_COPY(preq
.preq_origaddr
, vap
->iv_myaddr
);
875 preq
.preq_origseq
= ++hs
->hs_seq
;
876 preq
.preq_lifetime
= ticks_to_msecs(ieee80211_hwmp_roottimeout
);
877 preq
.preq_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
878 preq
.preq_tcount
= 1;
879 IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr
);
880 PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO
|
881 IEEE80211_MESHPREQ_TFLAGS_USN
;
883 vap
->iv_stats
.is_hwmp_rootreqs
++;
884 /* NB: we enforce rate check ourself */
885 hwmp_send_preq(vap
, broadcastaddr
, &preq
, NULL
, NULL
);
886 hwmp_rootmode_setup(vap
);
893 * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
894 * called when the vap is configured as a HWMP RANN root node.
897 hwmp_rootmode_rann_cb(void *arg
)
899 struct ieee80211vap
*vap
= (struct ieee80211vap
*)arg
;
900 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
901 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
902 struct ieee80211_meshrann_ie rann
;
904 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, vap
->iv_bss
,
905 "%s", "send broadcast RANN");
908 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
)
909 rann
.rann_flags
|= IEEE80211_MESHFLAGS_GATE
;
910 rann
.rann_hopcount
= 0;
911 rann
.rann_ttl
= ms
->ms_ttl
;
912 IEEE80211_ADDR_COPY(rann
.rann_addr
, vap
->iv_myaddr
);
913 rann
.rann_seq
= ++hs
->hs_seq
;
914 rann
.rann_interval
= ieee80211_hwmp_rannint
;
915 rann
.rann_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
917 vap
->iv_stats
.is_hwmp_rootrann
++;
918 hwmp_send_rann(vap
, broadcastaddr
, &rann
);
919 hwmp_rootmode_setup(vap
);
923 * Update forwarding information to TA if metric improves.
926 hwmp_update_transmitter(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
927 const char *hwmp_frame
)
929 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
930 struct ieee80211_mesh_route
*rttran
= NULL
; /* Transmitter */
933 rttran
= ieee80211_mesh_rt_find(vap
, ni
->ni_macaddr
);
934 if (rttran
== NULL
) {
935 rttran
= ieee80211_mesh_rt_add(vap
, ni
->ni_macaddr
);
936 if (rttran
== NULL
) {
937 #if defined(__DragonFly__)
938 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
939 "unable to add path to transmitter %s of %s",
940 ether_sprintf(ni
->ni_macaddr
), hwmp_frame
);
942 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
943 "unable to add path to transmitter %6D of %s",
944 ni
->ni_macaddr
, ":", hwmp_frame
);
946 vap
->iv_stats
.is_mesh_rtaddfailed
++;
950 metric
= ms
->ms_pmetric
->mpm_metric(ni
);
951 if (!(rttran
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) ||
952 rttran
->rt_metric
> metric
)
954 #if defined(__DragonFly__)
955 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
956 "%s path to transmitter %s of %s, metric %d:%d",
957 rttran
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
958 "prefer" : "update", ether_sprintf(ni
->ni_macaddr
),
960 rttran
->rt_metric
, metric
);
962 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
963 "%s path to transmiter %6D of %s, metric %d:%d",
964 rttran
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
965 "prefer" : "update", ni
->ni_macaddr
, ":", hwmp_frame
,
966 rttran
->rt_metric
, metric
);
968 IEEE80211_ADDR_COPY(rttran
->rt_nexthop
, ni
->ni_macaddr
);
969 rttran
->rt_metric
= metric
;
970 rttran
->rt_nhops
= 1;
971 ieee80211_mesh_rt_update(rttran
, ms
->ms_ppath
->mpp_inact
);
972 rttran
->rt_flags
= IEEE80211_MESHRT_FLAGS_VALID
;
976 #define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags
977 #define PREQ_TADDR(n) preq->preq_targets[n].target_addr
978 #define PREQ_TSEQ(n) preq->preq_targets[n].target_seq
980 hwmp_recv_preq(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
981 const struct ieee80211_frame
*wh
, const struct ieee80211_meshpreq_ie
*preq
)
983 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
984 struct ieee80211_mesh_route
*rtorig
= NULL
;
985 struct ieee80211_mesh_route
*rtorig_ext
= NULL
;
986 struct ieee80211_mesh_route
*rttarg
= NULL
;
987 struct ieee80211_hwmp_route
*hrorig
= NULL
;
988 struct ieee80211_hwmp_route
*hrtarg
= NULL
;
989 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
990 struct ieee80211_meshprep_ie prep
;
991 ieee80211_hwmp_seq preqid
; /* last seen preqid for orig */
995 * Ignore PREQs from us. Could happen because someone forward it
998 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, preq
->preq_origaddr
))
1001 #if defined(__DragonFly__)
1002 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1003 "received PREQ, orig %s, targ(0) %s",
1004 ether_sprintf(preq
->preq_origaddr
),
1005 ether_sprintf(PREQ_TADDR(0)));
1007 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1008 "received PREQ, orig %6D, targ(0) %6D", preq
->preq_origaddr
, ":",
1009 PREQ_TADDR(0), ":");
1013 * Acceptance criteria: (if the PREQ is not for us or not broadcast,
1014 * or an external mac address not proxied by us),
1015 * AND forwarding is disabled, discard this PREQ.
1017 rttarg
= ieee80211_mesh_rt_find(vap
, PREQ_TADDR(0));
1018 if (!(ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) &&
1019 (!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, PREQ_TADDR(0)) ||
1020 !IEEE80211_IS_MULTICAST(PREQ_TADDR(0)) ||
1022 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
&&
1023 IEEE80211_ADDR_EQ(vap
->iv_myaddr
, rttarg
->rt_mesh_gate
)))) {
1024 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_HWMP
,
1025 preq
->preq_origaddr
, NULL
, "%s", "not accepting PREQ");
1029 * Acceptance criteria: if unicast addressed
1030 * AND no valid forwarding for Target of PREQ, discard this PREQ.
1033 hrtarg
= IEEE80211_MESH_ROUTE_PRIV(rttarg
,
1034 struct ieee80211_hwmp_route
);
1035 /* Address mode: ucast */
1036 if(preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AM
&&
1038 !IEEE80211_ADDR_EQ(vap
->iv_myaddr
, PREQ_TADDR(0))) {
1039 #if defined(__DragonFly__)
1040 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_HWMP
,
1041 preq
->preq_origaddr
, NULL
,
1042 "unicast addressed PREQ of unknown target %s",
1043 ether_sprintf(PREQ_TADDR(0)));
1045 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_HWMP
,
1046 preq
->preq_origaddr
, NULL
,
1047 "unicast addressed PREQ of unknown target %6D",
1048 PREQ_TADDR(0), ":");
1055 rtorig
= ieee80211_mesh_rt_find(vap
, preq
->preq_origaddr
);
1056 if (rtorig
== NULL
) {
1057 rtorig
= ieee80211_mesh_rt_add(vap
, preq
->preq_origaddr
);
1058 if (rtorig
== NULL
) {
1059 #if defined(__DragonFly__)
1060 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1061 "unable to add orig path to %s",
1062 ether_sprintf(preq
->preq_origaddr
));
1064 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1065 "unable to add orig path to %6D",
1066 preq
->preq_origaddr
, ":");
1068 vap
->iv_stats
.is_mesh_rtaddfailed
++;
1071 #if defined(__DragonFly__)
1072 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1073 "adding originator %s",
1074 ether_sprintf(preq
->preq_origaddr
));
1076 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1077 "adding originator %6D", preq
->preq_origaddr
, ":");
1080 hrorig
= IEEE80211_MESH_ROUTE_PRIV(rtorig
, struct ieee80211_hwmp_route
);
1082 /* record last seen preqid */
1083 preqid
= hrorig
->hr_preqid
;
1084 hrorig
->hr_preqid
= HWMP_SEQ_MAX(hrorig
->hr_preqid
, preq
->preq_id
);
1086 /* Data creation and update of forwarding information
1087 * according to Table 11C-8 for originator mesh STA.
1089 metric
= preq
->preq_metric
+ ms
->ms_pmetric
->mpm_metric(ni
);
1090 if (HWMP_SEQ_GT(preq
->preq_origseq
, hrorig
->hr_seq
) ||
1091 (HWMP_SEQ_EQ(preq
->preq_origseq
, hrorig
->hr_seq
) &&
1092 metric
< rtorig
->rt_metric
)) {
1093 hrorig
->hr_seq
= preq
->preq_origseq
;
1094 IEEE80211_ADDR_COPY(rtorig
->rt_nexthop
, wh
->i_addr2
);
1095 rtorig
->rt_metric
= metric
;
1096 rtorig
->rt_nhops
= preq
->preq_hopcount
+ 1;
1097 ieee80211_mesh_rt_update(rtorig
, preq
->preq_lifetime
);
1098 /* Path to orig is valid now.
1099 * NB: we know it can't be Proxy, and if it is GATE
1100 * it will be marked below.
1102 rtorig
->rt_flags
= IEEE80211_MESHRT_FLAGS_VALID
;
1103 } else if ((hrtarg
!= NULL
&&
1104 !HWMP_SEQ_EQ(hrtarg
->hr_seq
, PREQ_TSEQ(0))) ||
1105 (rtorig
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
&&
1106 preqid
>= preq
->preq_id
)) {
1107 #if defined(__DragonFly__)
1108 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1109 "discard PREQ from %s, old seqno %u <= %u,"
1110 " or old preqid %u < %u",
1111 ether_sprintf(preq
->preq_origaddr
),
1112 preq
->preq_origseq
, hrorig
->hr_seq
,
1113 preq
->preq_id
, preqid
);
1115 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1116 "discard PREQ from %6D, old seqno %u <= %u,"
1117 " or old preqid %u < %u",
1118 preq
->preq_origaddr
, ":",
1119 preq
->preq_origseq
, hrorig
->hr_seq
,
1120 preq
->preq_id
, preqid
);
1125 /* Update forwarding information to TA if metric improves. */
1126 hwmp_update_transmitter(vap
, ni
, "PREQ");
1129 * Check if the PREQ is addressed to us.
1130 * or a Proxy currently gated by us.
1132 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, PREQ_TADDR(0)) ||
1133 (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
&&
1135 IEEE80211_ADDR_EQ(vap
->iv_myaddr
, rttarg
->rt_mesh_gate
) &&
1136 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
&&
1137 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
)) {
1139 * When we are the target we shall update our own HWMP seq
1140 * number with max of (current and preq->seq) + 1
1142 hs
->hs_seq
= HWMP_SEQ_MAX(hs
->hs_seq
, PREQ_TSEQ(0)) + 1;
1144 prep
.prep_flags
= 0;
1145 prep
.prep_hopcount
= 0;
1146 prep
.prep_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
1147 IEEE80211_ADDR_COPY(prep
.prep_targetaddr
, vap
->iv_myaddr
);
1148 if (rttarg
!= NULL
&& /* if NULL it means we are the target */
1149 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
) {
1150 #if defined(__DragonFly__)
1151 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1152 "reply for proxy %s",
1153 ether_sprintf(rttarg
->rt_dest
));
1155 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1156 "reply for proxy %6D", rttarg
->rt_dest
, ":");
1158 prep
.prep_flags
|= IEEE80211_MESHPREP_FLAGS_AE
;
1159 IEEE80211_ADDR_COPY(prep
.prep_target_ext_addr
,
1161 /* update proxy seqno to HWMP seqno */
1162 rttarg
->rt_ext_seq
= hs
->hs_seq
;
1163 prep
.prep_hopcount
= rttarg
->rt_nhops
;
1164 prep
.prep_metric
= rttarg
->rt_metric
;
1165 IEEE80211_ADDR_COPY(prep
.prep_targetaddr
, rttarg
->rt_mesh_gate
);
1168 * Build and send a PREP frame.
1170 prep
.prep_ttl
= ms
->ms_ttl
;
1171 prep
.prep_targetseq
= hs
->hs_seq
;
1172 prep
.prep_lifetime
= preq
->preq_lifetime
;
1173 IEEE80211_ADDR_COPY(prep
.prep_origaddr
, preq
->preq_origaddr
);
1174 prep
.prep_origseq
= preq
->preq_origseq
;
1176 #if defined(__DragonFly__)
1177 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1178 "reply to %s", ether_sprintf(preq
->preq_origaddr
));
1180 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1181 "reply to %6D", preq
->preq_origaddr
, ":");
1183 hwmp_send_prep(vap
, wh
->i_addr2
, &prep
);
1186 /* we may update our proxy information for the orig external */
1187 else if (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AE
) {
1189 ieee80211_mesh_rt_find(vap
, preq
->preq_orig_ext_addr
);
1190 if (rtorig_ext
== NULL
) {
1191 rtorig_ext
= ieee80211_mesh_rt_add(vap
,
1192 preq
->preq_orig_ext_addr
);
1193 if (rtorig_ext
== NULL
) {
1194 #if defined(__DragonFly__)
1195 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1196 "unable to add orig ext proxy to %s",
1197 ether_sprintf(preq
->preq_orig_ext_addr
));
1199 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1200 "unable to add orig ext proxy to %6D",
1201 preq
->preq_orig_ext_addr
, ":");
1203 vap
->iv_stats
.is_mesh_rtaddfailed
++;
1206 IEEE80211_ADDR_COPY(rtorig_ext
->rt_mesh_gate
,
1207 preq
->preq_origaddr
);
1209 rtorig_ext
->rt_ext_seq
= preq
->preq_origseq
;
1210 ieee80211_mesh_rt_update(rtorig_ext
, preq
->preq_lifetime
);
1213 * Proactive PREQ: reply with a proactive PREP to the
1214 * root STA if requested.
1216 if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr
) &&
1217 (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO
)) {
1218 #if defined(__DragonFly__)
1219 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1220 "root mesh station @ %s",
1221 ether_sprintf(preq
->preq_origaddr
));
1223 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1224 "root mesh station @ %6D", preq
->preq_origaddr
, ":");
1227 /* Check if root is a mesh gate, mark it */
1228 if (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_GATE
) {
1229 struct ieee80211_mesh_gate_route
*gr
;
1231 rtorig
->rt_flags
|= IEEE80211_MESHRT_FLAGS_GATE
;
1232 gr
= ieee80211_mesh_mark_gate(vap
, preq
->preq_origaddr
,
1234 gr
->gr_lastseq
= 0; /* NOT GANN */
1238 * Reply with a PREP if we don't have a path to the root
1239 * or if the root sent us a proactive PREQ.
1241 if ((rtorig
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0 ||
1242 (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_PP
)) {
1243 prep
.prep_flags
= 0;
1244 prep
.prep_hopcount
= 0;
1245 prep
.prep_ttl
= ms
->ms_ttl
;
1246 IEEE80211_ADDR_COPY(prep
.prep_origaddr
,
1247 preq
->preq_origaddr
);
1248 prep
.prep_origseq
= preq
->preq_origseq
;
1249 prep
.prep_lifetime
= preq
->preq_lifetime
;
1250 prep
.prep_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
1251 IEEE80211_ADDR_COPY(prep
.prep_targetaddr
,
1253 prep
.prep_targetseq
= ++hs
->hs_seq
;
1254 hwmp_send_prep(vap
, rtorig
->rt_nexthop
, &prep
);
1259 * Forwarding and Intermediate reply for PREQs with 1 target.
1261 if ((preq
->preq_tcount
== 1) && (preq
->preq_ttl
> 1) &&
1262 (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)) {
1263 struct ieee80211_meshpreq_ie ppreq
; /* propagated PREQ */
1265 memcpy(&ppreq
, preq
, sizeof(ppreq
));
1268 * We have a valid route to this node.
1269 * NB: if target is proxy dont reply.
1271 if (rttarg
!= NULL
&&
1272 rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
&&
1273 !(rttarg
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
)) {
1275 * Check if we can send an intermediate Path Reply,
1276 * i.e., Target Only bit is not set and target is not
1277 * the MAC broadcast address.
1279 if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO
) &&
1280 !IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr
)) {
1281 struct ieee80211_meshprep_ie prep
;
1283 #if defined(__DragonFly__)
1284 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1285 "intermediate reply for PREQ from %s",
1286 ether_sprintf(preq
->preq_origaddr
));
1288 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1289 "intermediate reply for PREQ from %6D",
1290 preq
->preq_origaddr
, ":");
1292 prep
.prep_flags
= 0;
1293 prep
.prep_hopcount
= rttarg
->rt_nhops
;
1294 prep
.prep_ttl
= ms
->ms_ttl
;
1295 IEEE80211_ADDR_COPY(&prep
.prep_targetaddr
,
1297 prep
.prep_targetseq
= hrtarg
->hr_seq
;
1298 prep
.prep_lifetime
= preq
->preq_lifetime
;
1299 prep
.prep_metric
=rttarg
->rt_metric
;
1300 IEEE80211_ADDR_COPY(&prep
.prep_origaddr
,
1301 preq
->preq_origaddr
);
1302 prep
.prep_origseq
= hrorig
->hr_seq
;
1303 hwmp_send_prep(vap
, rtorig
->rt_nexthop
, &prep
);
1306 * Set TO and unset RF bits because we have
1309 ppreq
.preq_targets
[0].target_flags
|=
1310 IEEE80211_MESHPREQ_TFLAGS_TO
;
1314 #if defined(__DragonFly__)
1315 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1316 "forward PREQ from %s",
1317 ether_sprintf(preq
->preq_origaddr
));
1319 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1320 "forward PREQ from %6D",
1321 preq
->preq_origaddr
, ":");
1323 ppreq
.preq_hopcount
+= 1;
1324 ppreq
.preq_ttl
-= 1;
1325 ppreq
.preq_metric
+= ms
->ms_pmetric
->mpm_metric(ni
);
1327 /* don't do PREQ ratecheck when we propagate */
1328 hwmp_send_preq(vap
, broadcastaddr
, &ppreq
, NULL
, NULL
);
1336 hwmp_send_preq(struct ieee80211vap
*vap
,
1337 const uint8_t da
[IEEE80211_ADDR_LEN
],
1338 struct ieee80211_meshpreq_ie
*preq
,
1339 struct timeval
*last
, struct timeval
*minint
)
1343 * Enforce PREQ interval.
1344 * NB: Proactive ROOT PREQs rate is handled by cb task.
1346 if (last
!= NULL
&& minint
!= NULL
) {
1347 if (ratecheck(last
, minint
) == 0)
1348 return EALREADY
; /* XXX: we should postpone */
1349 getmicrouptime(last
);
1353 * mesh preq action frame format
1359 * [tlv] mesh path request
1361 preq
->preq_ie
= IEEE80211_ELEMID_MESHPREQ
;
1362 preq
->preq_len
= (preq
->preq_flags
& IEEE80211_MESHPREQ_FLAGS_AE
?
1363 IEEE80211_MESHPREQ_BASE_SZ_AE
: IEEE80211_MESHPREQ_BASE_SZ
) +
1364 preq
->preq_tcount
* IEEE80211_MESHPREQ_TRGT_SZ
;
1365 return hwmp_send_action(vap
, da
, (uint8_t *)preq
, preq
->preq_len
+2);
1369 hwmp_recv_prep(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1370 const struct ieee80211_frame
*wh
, const struct ieee80211_meshprep_ie
*prep
)
1372 #define IS_PROXY(rt) (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)
1373 #define PROXIED_BY_US(rt) \
1374 (IEEE80211_ADDR_EQ(vap->iv_myaddr, rt->rt_mesh_gate))
1375 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1376 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
1377 struct ieee80211_mesh_route
*rt
= NULL
;
1378 struct ieee80211_mesh_route
*rtorig
= NULL
;
1379 struct ieee80211_mesh_route
*rtext
= NULL
;
1380 struct ieee80211_hwmp_route
*hr
;
1381 struct ieee80211com
*ic
= vap
->iv_ic
;
1382 struct mbuf
*m
, *next
;
1383 uint32_t metric
= 0;
1384 const uint8_t *addr
;
1386 #if defined(__DragonFly__)
1387 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1388 "received PREP, orig %s, targ %s",
1389 ether_sprintf(prep
->prep_origaddr
),
1390 ether_sprintf(prep
->prep_targetaddr
));
1392 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1393 "received PREP, orig %6D, targ %6D", prep
->prep_origaddr
, ":",
1394 prep
->prep_targetaddr
, ":");
1398 * Acceptance criteria: (If the corresponding PREP was not generated
1399 * by us OR not generated by an external mac that is not proxied by us)
1400 * AND forwarding is disabled, discard this PREP.
1402 rtorig
= ieee80211_mesh_rt_find(vap
, prep
->prep_origaddr
);
1403 if ((!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, prep
->prep_origaddr
) ||
1404 (rtorig
!= NULL
&& IS_PROXY(rtorig
) && !PROXIED_BY_US(rtorig
))) &&
1405 !(ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)){
1406 #if defined(__DragonFly__)
1407 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1408 "discard PREP, orig(%s) not proxied or generated by us",
1409 ether_sprintf(prep
->prep_origaddr
));
1411 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1412 "discard PREP, orig(%6D) not proxied or generated by us",
1413 prep
->prep_origaddr
, ":");
1421 * If accepted shall create or update the active forwarding information
1422 * it maintains for the target mesh STA of the PREP (according to the
1423 * rules defined in 13.10.8.4). If the conditions for creating or
1424 * updating the forwarding information have not been met in those
1425 * rules, no further steps are applied to the PREP.
1427 rt
= ieee80211_mesh_rt_find(vap
, prep
->prep_targetaddr
);
1429 rt
= ieee80211_mesh_rt_add(vap
, prep
->prep_targetaddr
);
1431 #if defined(__DragonFly__)
1432 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1433 "unable to add PREP path to %s",
1434 ether_sprintf(prep
->prep_targetaddr
));
1436 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1437 "unable to add PREP path to %6D",
1438 prep
->prep_targetaddr
, ":");
1440 vap
->iv_stats
.is_mesh_rtaddfailed
++;
1443 #if defined(__DragonFly__)
1444 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1445 "adding target %s", ether_sprintf(prep
->prep_targetaddr
));
1447 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1448 "adding target %6D", prep
->prep_targetaddr
, ":");
1451 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
1452 /* update path metric */
1453 metric
= prep
->prep_metric
+ ms
->ms_pmetric
->mpm_metric(ni
);
1454 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
)) {
1455 if (HWMP_SEQ_LT(prep
->prep_targetseq
, hr
->hr_seq
)) {
1456 #if defined(__DragonFly__)
1457 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1458 "discard PREP from %s, old seq no %u < %u",
1459 ether_sprintf(prep
->prep_targetaddr
),
1460 prep
->prep_targetseq
, hr
->hr_seq
);
1462 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1463 "discard PREP from %6D, old seq no %u < %u",
1464 prep
->prep_targetaddr
, ":",
1465 prep
->prep_targetseq
, hr
->hr_seq
);
1468 } else if (HWMP_SEQ_LEQ(prep
->prep_targetseq
, hr
->hr_seq
) &&
1469 metric
> rt
->rt_metric
) {
1470 #if defined(__DragonFly__)
1471 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1472 "discard PREP from %s, new metric %u > %u",
1473 ether_sprintf(prep
->prep_targetaddr
),
1474 metric
, rt
->rt_metric
);
1476 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1477 "discard PREP from %6D, new metric %u > %u",
1478 prep
->prep_targetaddr
, ":",
1479 metric
, rt
->rt_metric
);
1485 #if defined(__DragonFly__)
1486 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1487 "%s path to %s, hopcount %d:%d metric %d:%d",
1488 rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
1489 "prefer" : "update",
1490 ether_sprintf(prep
->prep_targetaddr
),
1491 rt
->rt_nhops
, prep
->prep_hopcount
+ 1,
1492 rt
->rt_metric
, metric
);
1494 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1495 "%s path to %6D, hopcount %d:%d metric %d:%d",
1496 rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
1497 "prefer" : "update",
1498 prep
->prep_targetaddr
, ":",
1499 rt
->rt_nhops
, prep
->prep_hopcount
+ 1,
1500 rt
->rt_metric
, metric
);
1503 hr
->hr_seq
= prep
->prep_targetseq
;
1504 hr
->hr_preqretries
= 0;
1505 IEEE80211_ADDR_COPY(rt
->rt_nexthop
, ni
->ni_macaddr
);
1506 rt
->rt_metric
= metric
;
1507 rt
->rt_nhops
= prep
->prep_hopcount
+ 1;
1508 ieee80211_mesh_rt_update(rt
, prep
->prep_lifetime
);
1509 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_DISCOVER
) {
1510 /* discovery complete */
1511 rt
->rt_flags
&= ~IEEE80211_MESHRT_FLAGS_DISCOVER
;
1513 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
; /* mark valid */
1515 /* Update forwarding information to TA if metric improves */
1516 hwmp_update_transmitter(vap
, ni
, "PREP");
1519 * If it's NOT for us, propagate the PREP
1521 if (!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, prep
->prep_origaddr
) &&
1522 prep
->prep_ttl
> 1 &&
1523 prep
->prep_hopcount
< hs
->hs_maxhops
) {
1524 struct ieee80211_meshprep_ie pprep
; /* propagated PREP */
1526 * NB: We should already have setup the path to orig
1527 * mesh STA when we propagated PREQ to target mesh STA,
1528 * no PREP is generated without a corresponding PREQ.
1529 * XXX: for now just ignore.
1531 if (rtorig
== NULL
) {
1532 #if defined(__DragonFly__)
1533 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1534 "received PREP for an unknown orig(%s)",
1535 ether_sprintf(prep
->prep_origaddr
));
1537 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1538 "received PREP for an unknown orig(%6D)",
1539 prep
->prep_origaddr
, ":");
1544 #if defined(__DragonFly__)
1545 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1546 "propagate PREP from %s",
1547 ether_sprintf(prep
->prep_targetaddr
));
1549 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1550 "propagate PREP from %6D",
1551 prep
->prep_targetaddr
, ":");
1554 memcpy(&pprep
, prep
, sizeof(pprep
));
1555 pprep
.prep_hopcount
+= 1;
1556 pprep
.prep_ttl
-= 1;
1557 pprep
.prep_metric
+= ms
->ms_pmetric
->mpm_metric(ni
);
1558 hwmp_send_prep(vap
, rtorig
->rt_nexthop
, &pprep
);
1560 /* precursor list for the Target Mesh STA Address is updated */
1564 * Check if we received a PREP w/ AE and store target external address.
1565 * We may store target external address if recevied PREP w/ AE
1566 * and we are not final destination
1568 if (prep
->prep_flags
& IEEE80211_MESHPREP_FLAGS_AE
) {
1569 rtext
= ieee80211_mesh_rt_find(vap
,
1570 prep
->prep_target_ext_addr
);
1571 if (rtext
== NULL
) {
1572 rtext
= ieee80211_mesh_rt_add(vap
,
1573 prep
->prep_target_ext_addr
);
1574 if (rtext
== NULL
) {
1575 #if defined(__DragonFly__)
1576 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1577 "unable to add PREP path to proxy %s",
1578 ether_sprintf(prep
->prep_targetaddr
));
1580 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1581 "unable to add PREP path to proxy %6D",
1582 prep
->prep_targetaddr
, ":");
1584 vap
->iv_stats
.is_mesh_rtaddfailed
++;
1588 #if defined(__DragonFly__)
1589 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1590 "%s path to %s, hopcount %d:%d metric %d:%d",
1591 rtext
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
1592 "prefer" : "update",
1593 ether_sprintf(prep
->prep_target_ext_addr
),
1594 rtext
->rt_nhops
, prep
->prep_hopcount
+ 1,
1595 rtext
->rt_metric
, metric
);
1597 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1598 "%s path to %6D, hopcount %d:%d metric %d:%d",
1599 rtext
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
?
1600 "prefer" : "update",
1601 prep
->prep_target_ext_addr
, ":",
1602 rtext
->rt_nhops
, prep
->prep_hopcount
+ 1,
1603 rtext
->rt_metric
, metric
);
1606 rtext
->rt_flags
= IEEE80211_MESHRT_FLAGS_PROXY
|
1607 IEEE80211_MESHRT_FLAGS_VALID
;
1608 IEEE80211_ADDR_COPY(rtext
->rt_dest
,
1609 prep
->prep_target_ext_addr
);
1610 IEEE80211_ADDR_COPY(rtext
->rt_mesh_gate
,
1611 prep
->prep_targetaddr
);
1612 IEEE80211_ADDR_COPY(rtext
->rt_nexthop
, wh
->i_addr2
);
1613 rtext
->rt_metric
= metric
;
1614 rtext
->rt_lifetime
= prep
->prep_lifetime
;
1615 rtext
->rt_nhops
= prep
->prep_hopcount
+ 1;
1616 rtext
->rt_ext_seq
= prep
->prep_origseq
; /* new proxy seq */
1618 * XXX: proxy entries have no HWMP priv data,
1619 * nullify them to be sure?
1623 * Check for frames queued awaiting path discovery.
1624 * XXX probably can tell exactly and avoid remove call
1625 * NB: hash may have false matches, if so they will get
1626 * stuck back on the stageq because there won't be
1629 addr
= prep
->prep_flags
& IEEE80211_MESHPREP_FLAGS_AE
?
1630 prep
->prep_target_ext_addr
: prep
->prep_targetaddr
;
1631 m
= ieee80211_ageq_remove(&ic
->ic_stageq
,
1632 (struct ieee80211_node
*)(uintptr_t)
1633 ieee80211_mac_hash(ic
, addr
)); /* either dest or ext_dest */
1636 * All frames in the stageq here should be non-M_ENCAP; or things
1637 * will get very unhappy.
1639 for (; m
!= NULL
; m
= next
) {
1640 next
= m
->m_nextpkt
;
1641 m
->m_nextpkt
= NULL
;
1642 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1643 "flush queued frame %p len %d", m
, m
->m_pkthdr
.len
);
1645 * If the mbuf has M_ENCAP set, ensure we free it.
1646 * Note that after if_transmit() is called, m is invalid.
1648 (void) ieee80211_vap_xmitpkt(vap
, m
);
1651 #undef PROXIED_BY_US
1655 hwmp_send_prep(struct ieee80211vap
*vap
,
1656 const uint8_t da
[IEEE80211_ADDR_LEN
],
1657 struct ieee80211_meshprep_ie
*prep
)
1659 /* NB: there's no PREP minimum interval. */
1662 * mesh prep action frame format
1668 * [tlv] mesh path reply
1670 prep
->prep_ie
= IEEE80211_ELEMID_MESHPREP
;
1671 prep
->prep_len
= prep
->prep_flags
& IEEE80211_MESHPREP_FLAGS_AE
?
1672 IEEE80211_MESHPREP_BASE_SZ_AE
: IEEE80211_MESHPREP_BASE_SZ
;
1673 return hwmp_send_action(vap
, da
, (uint8_t *)prep
, prep
->prep_len
+ 2);
1676 #define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags
1677 #define PERR_DADDR(n) perr.perr_dests[n].dest_addr
1678 #define PERR_DSEQ(n) perr.perr_dests[n].dest_seq
1679 #define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode
1681 hwmp_peerdown(struct ieee80211_node
*ni
)
1683 struct ieee80211vap
*vap
= ni
->ni_vap
;
1684 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1685 struct ieee80211_meshperr_ie perr
;
1686 struct ieee80211_mesh_route
*rt
;
1687 struct ieee80211_hwmp_route
*hr
;
1689 rt
= ieee80211_mesh_rt_find(vap
, ni
->ni_macaddr
);
1692 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
1693 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1694 "%s", "delete route entry");
1695 perr
.perr_ttl
= ms
->ms_ttl
;
1696 perr
.perr_ndests
= 1;
1698 if (hr
->hr_seq
== 0)
1699 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN
;
1700 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC
;
1701 IEEE80211_ADDR_COPY(PERR_DADDR(0), rt
->rt_dest
);
1702 PERR_DSEQ(0) = ++hr
->hr_seq
;
1703 PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH
;
1704 /* NB: flush everything passing through peer */
1705 ieee80211_mesh_rt_flush_peer(vap
, ni
->ni_macaddr
);
1706 hwmp_send_perr(vap
, broadcastaddr
, &perr
);
1713 #define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
1714 #define PERR_DADDR(n) perr->perr_dests[n].dest_addr
1715 #define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
1716 #define PERR_DEXTADDR(n) perr->perr_dests[n].dest_ext_addr
1717 #define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
1719 hwmp_recv_perr(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1720 const struct ieee80211_frame
*wh
, const struct ieee80211_meshperr_ie
*perr
)
1722 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1723 struct ieee80211_mesh_route
*rt
= NULL
;
1724 struct ieee80211_mesh_route
*rt_ext
= NULL
;
1725 struct ieee80211_hwmp_route
*hr
;
1726 struct ieee80211_meshperr_ie
*pperr
= NULL
;
1727 int i
, j
= 0, forward
= 0;
1729 #if defined(__DragonFly__)
1730 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1731 "received PERR from %s", ether_sprintf(wh
->i_addr2
));
1733 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1734 "received PERR from %6D", wh
->i_addr2
, ":");
1738 * if forwarding is true, prepare pperr
1740 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) {
1742 #if defined(__DragonFly__)
1743 pperr
= kmalloc(sizeof(*perr
) + 31*sizeof(*perr
->perr_dests
),
1744 M_80211_MESH_PERR
, M_INTWAIT
); /* XXX: magic number, 32 err dests */
1746 pperr
= IEEE80211_MALLOC(sizeof(*perr
) + 31*sizeof(*perr
->perr_dests
),
1747 M_80211_MESH_PERR
, IEEE80211_M_NOWAIT
); /* XXX: magic number, 32 err dests */
1752 * Acceptance criteria: check if we have forwarding information
1753 * stored about destination, and that nexthop == TA of this PERR.
1754 * NB: we also build a new PERR to propagate in case we should forward.
1756 for (i
= 0; i
< perr
->perr_ndests
; i
++) {
1757 rt
= ieee80211_mesh_rt_find(vap
, PERR_DADDR(i
));
1760 if (!IEEE80211_ADDR_EQ(rt
->rt_nexthop
, wh
->i_addr2
))
1763 /* found and accepted a PERR ndest element, process it... */
1765 memcpy(&pperr
->perr_dests
[j
], &perr
->perr_dests
[i
],
1766 sizeof(*perr
->perr_dests
));
1767 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
1768 switch(PERR_DFLAGS(i
)) {
1769 case (IEEE80211_REASON_MESH_PERR_NO_FI
):
1770 if (PERR_DSEQ(i
) == 0) {
1773 pperr
->perr_dests
[j
].dest_seq
=
1777 hr
->hr_seq
= PERR_DSEQ(i
);
1779 rt
->rt_flags
&= ~IEEE80211_MESHRT_FLAGS_VALID
;
1782 case (IEEE80211_REASON_MESH_PERR_DEST_UNREACH
):
1783 if(HWMP_SEQ_GT(PERR_DSEQ(i
), hr
->hr_seq
)) {
1784 hr
->hr_seq
= PERR_DSEQ(i
);
1785 rt
->rt_flags
&= ~IEEE80211_MESHRT_FLAGS_VALID
;
1789 case (IEEE80211_REASON_MESH_PERR_NO_PROXY
):
1790 rt_ext
= ieee80211_mesh_rt_find(vap
, PERR_DEXTADDR(i
));
1791 if (rt_ext
!= NULL
) {
1793 ~IEEE80211_MESHRT_FLAGS_VALID
;
1798 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1799 "PERR, unknown reason code %u\n", PERR_DFLAGS(i
));
1800 goto done
; /* XXX: stats?? */
1802 ieee80211_mesh_rt_flush_peer(vap
, PERR_DADDR(i
));
1803 KASSERT(j
< 32, ("PERR, error ndest >= 32 (%u)", j
));
1806 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
, "%s",
1807 "PERR not accepted");
1808 goto done
; /* XXX: stats?? */
1812 * Propagate the PERR if we previously found it on our routing table.
1814 if (forward
&& perr
->perr_ttl
> 1) {
1815 #if defined(__DragonFly__)
1816 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1817 "propagate PERR from %s", ether_sprintf(wh
->i_addr2
));
1819 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
, ni
,
1820 "propagate PERR from %6D", wh
->i_addr2
, ":");
1822 pperr
->perr_ndests
= j
;
1824 hwmp_send_perr(vap
, broadcastaddr
, pperr
);
1828 IEEE80211_FREE(pperr
, M_80211_MESH_PERR
);
1833 #undef PERR_DEXTADDR
1837 hwmp_send_perr(struct ieee80211vap
*vap
,
1838 const uint8_t da
[IEEE80211_ADDR_LEN
],
1839 struct ieee80211_meshperr_ie
*perr
)
1841 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
1846 * Enforce PERR interval.
1848 if (ratecheck(&hs
->hs_lastperr
, &ieee80211_hwmp_perrminint
) == 0)
1850 getmicrouptime(&hs
->hs_lastperr
);
1853 * mesh perr action frame format
1859 * [tlv] mesh path error
1861 perr
->perr_ie
= IEEE80211_ELEMID_MESHPERR
;
1862 length
= IEEE80211_MESHPERR_BASE_SZ
;
1863 for (i
= 0; i
<perr
->perr_ndests
; i
++) {
1864 if (perr
->perr_dests
[i
].dest_flags
&
1865 IEEE80211_MESHPERR_FLAGS_AE
) {
1866 length
+= IEEE80211_MESHPERR_DEST_SZ_AE
;
1869 length
+= IEEE80211_MESHPERR_DEST_SZ
;
1871 perr
->perr_len
=length
;
1872 return hwmp_send_action(vap
, da
, (uint8_t *)perr
, perr
->perr_len
+2);
1876 * Called from the rest of the net80211 code (mesh code for example).
1877 * NB: IEEE80211_REASON_MESH_PERR_DEST_UNREACH can be trigger by the fact that
1878 * a mesh STA is unable to forward an MSDU/MMPDU to a next-hop mesh STA.
1880 #define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags
1881 #define PERR_DADDR(n) perr.perr_dests[n].dest_addr
1882 #define PERR_DSEQ(n) perr.perr_dests[n].dest_seq
1883 #define PERR_DEXTADDR(n) perr.perr_dests[n].dest_ext_addr
1884 #define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode
1886 hwmp_senderror(struct ieee80211vap
*vap
,
1887 const uint8_t addr
[IEEE80211_ADDR_LEN
],
1888 struct ieee80211_mesh_route
*rt
, int rcode
)
1890 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1891 struct ieee80211_hwmp_route
*hr
= NULL
;
1892 struct ieee80211_meshperr_ie perr
;
1895 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
,
1896 struct ieee80211_hwmp_route
);
1898 perr
.perr_ndests
= 1;
1899 perr
.perr_ttl
= ms
->ms_ttl
;
1901 PERR_DRCODE(0) = rcode
;
1904 case IEEE80211_REASON_MESH_PERR_NO_FI
:
1905 IEEE80211_ADDR_COPY(PERR_DADDR(0), addr
);
1906 PERR_DSEQ(0) = 0; /* reserved */
1908 case IEEE80211_REASON_MESH_PERR_NO_PROXY
:
1909 KASSERT(rt
!= NULL
, ("no proxy info for sending PERR"));
1910 KASSERT(rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
,
1911 ("route is not marked proxy"));
1912 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_FLAGS_AE
;
1913 IEEE80211_ADDR_COPY(PERR_DADDR(0), vap
->iv_myaddr
);
1914 PERR_DSEQ(0) = rt
->rt_ext_seq
;
1915 IEEE80211_ADDR_COPY(PERR_DEXTADDR(0), addr
);
1917 case IEEE80211_REASON_MESH_PERR_DEST_UNREACH
:
1918 KASSERT(rt
!= NULL
, ("no route info for sending PERR"));
1919 IEEE80211_ADDR_COPY(PERR_DADDR(0), addr
);
1920 PERR_DSEQ(0) = hr
->hr_seq
;
1923 KASSERT(0, ("unknown reason code for HWMP PERR (%u)", rcode
));
1925 hwmp_send_perr(vap
, broadcastaddr
, &perr
);
1930 #undef PERR_DEXTADDR
1934 hwmp_recv_rann(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
,
1935 const struct ieee80211_frame
*wh
, const struct ieee80211_meshrann_ie
*rann
)
1937 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1938 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
1939 struct ieee80211_mesh_route
*rt
= NULL
;
1940 struct ieee80211_hwmp_route
*hr
;
1941 struct ieee80211_meshpreq_ie preq
;
1942 struct ieee80211_meshrann_ie prann
;
1943 uint32_t metric
= 0;
1945 if (IEEE80211_ADDR_EQ(rann
->rann_addr
, vap
->iv_myaddr
))
1948 rt
= ieee80211_mesh_rt_find(vap
, rann
->rann_addr
);
1949 if (rt
!= NULL
&& rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) {
1950 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
1952 /* Acceptance criteria: if RANN.seq < stored seq, discard RANN */
1953 if (HWMP_SEQ_LT(rann
->rann_seq
, hr
->hr_seq
)) {
1954 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1955 "RANN seq %u < %u", rann
->rann_seq
, hr
->hr_seq
);
1959 /* Acceptance criteria: if RANN.seq == stored seq AND
1960 * RANN.metric > stored metric, discard RANN */
1961 if (HWMP_SEQ_EQ(rann
->rann_seq
, hr
->hr_seq
) &&
1962 rann
->rann_metric
> rt
->rt_metric
) {
1963 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1964 "RANN metric %u > %u", rann
->rann_metric
, rt
->rt_metric
);
1971 ieee80211_hwmp_rannint
= rann
->rann_interval
; /* XXX: mtx lock? */
1972 metric
= rann
->rann_metric
+ ms
->ms_pmetric
->mpm_metric(ni
);
1975 rt
= ieee80211_mesh_rt_add(vap
, rann
->rann_addr
);
1977 #if defined(__DragonFly__)
1978 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1979 "unable to add mac for RANN root %s",
1980 ether_sprintf(rann
->rann_addr
));
1982 IEEE80211_DISCARD(vap
, IEEE80211_MSG_HWMP
, wh
, NULL
,
1983 "unable to add mac for RANN root %6D",
1984 rann
->rann_addr
, ":");
1986 vap
->iv_stats
.is_mesh_rtaddfailed
++;
1990 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
1991 /* Check if root is a mesh gate, mark it */
1992 if (rann
->rann_flags
& IEEE80211_MESHRANN_FLAGS_GATE
) {
1993 struct ieee80211_mesh_gate_route
*gr
;
1995 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_GATE
;
1996 gr
= ieee80211_mesh_mark_gate(vap
, rann
->rann_addr
,
1998 gr
->gr_lastseq
= 0; /* NOT GANN */
2000 /* discovery timeout */
2001 ieee80211_mesh_rt_update(rt
,
2002 ticks_to_msecs(ieee80211_hwmp_roottimeout
));
2004 preq
.preq_flags
= IEEE80211_MESHPREQ_FLAGS_AM
;
2005 preq
.preq_hopcount
= 0;
2006 preq
.preq_ttl
= ms
->ms_ttl
;
2007 preq
.preq_id
= 0; /* reserved */
2008 IEEE80211_ADDR_COPY(preq
.preq_origaddr
, vap
->iv_myaddr
);
2009 preq
.preq_origseq
= ++hs
->hs_seq
;
2010 preq
.preq_lifetime
= ieee80211_hwmp_roottimeout
;
2011 preq
.preq_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
2012 preq
.preq_tcount
= 1;
2013 preq
.preq_targets
[0].target_flags
= IEEE80211_MESHPREQ_TFLAGS_TO
;
2014 /* NB: IEEE80211_MESHPREQ_TFLAGS_USN = 0 implicitly implied */
2015 IEEE80211_ADDR_COPY(preq
.preq_targets
[0].target_addr
, rann
->rann_addr
);
2016 preq
.preq_targets
[0].target_seq
= rann
->rann_seq
;
2017 /* XXX: if rootconfint have not passed, we built this preq in vain */
2018 hwmp_send_preq(vap
, wh
->i_addr2
, &preq
, &hr
->hr_lastrootconf
,
2019 &ieee80211_hwmp_rootconfint
);
2021 /* propagate a RANN */
2022 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
&&
2023 rann
->rann_ttl
> 1 &&
2024 ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) {
2025 hr
->hr_seq
= rann
->rann_seq
;
2026 memcpy(&prann
, rann
, sizeof(prann
));
2027 prann
.rann_hopcount
+= 1;
2028 prann
.rann_ttl
-= 1;
2029 prann
.rann_metric
+= ms
->ms_pmetric
->mpm_metric(ni
);
2030 hwmp_send_rann(vap
, broadcastaddr
, &prann
);
2035 hwmp_send_rann(struct ieee80211vap
*vap
,
2036 const uint8_t da
[IEEE80211_ADDR_LEN
],
2037 struct ieee80211_meshrann_ie
*rann
)
2040 * mesh rann action frame format
2046 * [tlv] root annoucement
2048 rann
->rann_ie
= IEEE80211_ELEMID_MESHRANN
;
2049 rann
->rann_len
= IEEE80211_MESHRANN_BASE_SZ
;
2050 return hwmp_send_action(vap
, da
, (uint8_t *)rann
, rann
->rann_len
+ 2);
2053 #define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags
2054 #define PREQ_TADDR(n) preq.preq_targets[n].target_addr
2055 #define PREQ_TSEQ(n) preq.preq_targets[n].target_seq
2057 hwmp_rediscover_cb(void *arg
)
2059 struct ieee80211_mesh_route
*rt
= arg
;
2060 struct ieee80211vap
*vap
= rt
->rt_vap
;
2061 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2062 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2063 struct ieee80211_hwmp_route
*hr
;
2064 struct ieee80211_meshpreq_ie preq
; /* Optimize: storing first preq? */
2066 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
))
2067 return ; /* nothing to do */
2069 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
, struct ieee80211_hwmp_route
);
2070 if (hr
->hr_preqretries
>=
2071 ieee80211_hwmp_maxpreq_retries
) {
2072 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_ANY
,
2074 "max number of discovery, send queued frames to GATE");
2075 ieee80211_mesh_forward_to_gates(vap
, rt
);
2076 vap
->iv_stats
.is_mesh_fwd_nopath
++;
2077 return ; /* XXX: flush queue? */
2080 hr
->hr_preqretries
++;
2083 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
, rt
->rt_dest
,
2084 "start path rediscovery , target seq %u", hr
->hr_seq
);
2086 * Try to discover the path for this node.
2087 * Group addressed PREQ Case A
2089 preq
.preq_flags
= 0;
2090 preq
.preq_hopcount
= 0;
2091 preq
.preq_ttl
= ms
->ms_ttl
;
2092 preq
.preq_id
= ++hs
->hs_preqid
;
2093 IEEE80211_ADDR_COPY(preq
.preq_origaddr
, vap
->iv_myaddr
);
2094 preq
.preq_origseq
= hr
->hr_origseq
;
2095 preq
.preq_lifetime
= ticks_to_msecs(ieee80211_hwmp_pathtimeout
);
2096 preq
.preq_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
2097 preq
.preq_tcount
= 1;
2098 IEEE80211_ADDR_COPY(PREQ_TADDR(0), rt
->rt_dest
);
2100 if (ieee80211_hwmp_targetonly
)
2101 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO
;
2102 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN
;
2103 PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
2104 /* XXX check return value */
2105 hwmp_send_preq(vap
, broadcastaddr
, &preq
, &hr
->hr_lastpreq
,
2106 &ieee80211_hwmp_preqminint
);
2107 callout_reset(&rt
->rt_discovery
,
2108 ieee80211_hwmp_net_diameter_traversaltime
* 2,
2109 hwmp_rediscover_cb
, rt
);
2112 static struct ieee80211_node
*
2113 hwmp_discover(struct ieee80211vap
*vap
,
2114 const uint8_t dest
[IEEE80211_ADDR_LEN
], struct mbuf
*m
)
2116 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2117 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2118 struct ieee80211_mesh_route
*rt
= NULL
;
2119 struct ieee80211_hwmp_route
*hr
;
2120 struct ieee80211_meshpreq_ie preq
;
2121 struct ieee80211_node
*ni
;
2124 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
,
2125 ("not a mesh vap, opmode %d", vap
->iv_opmode
));
2127 KASSERT(!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, dest
),
2128 ("%s: discovering self!", __func__
));
2131 if (!IEEE80211_IS_MULTICAST(dest
)) {
2132 rt
= ieee80211_mesh_rt_find(vap
, dest
);
2134 rt
= ieee80211_mesh_rt_add(vap
, dest
);
2136 #if defined(__DragonFly__)
2137 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
,
2138 ni
, "unable to add discovery path to %s",
2139 ether_sprintf(dest
));
2141 IEEE80211_NOTE(vap
, IEEE80211_MSG_HWMP
,
2142 ni
, "unable to add discovery path to %6D",
2145 vap
->iv_stats
.is_mesh_rtaddfailed
++;
2149 hr
= IEEE80211_MESH_ROUTE_PRIV(rt
,
2150 struct ieee80211_hwmp_route
);
2151 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_DISCOVER
) {
2152 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
, dest
,
2153 "%s", "already discovering queue frame until path found");
2157 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0) {
2158 if (hr
->hr_lastdiscovery
!= 0 &&
2159 (ticks
- hr
->hr_lastdiscovery
<
2160 (ieee80211_hwmp_net_diameter_traversaltime
* 2))) {
2161 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
2163 "too frequent discovery requeust");
2167 hr
->hr_lastdiscovery
= ticks
;
2168 if (hr
->hr_preqretries
>=
2169 ieee80211_hwmp_maxpreq_retries
) {
2170 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
2172 "no valid path , max number of discovery");
2173 vap
->iv_stats
.is_mesh_fwd_nopath
++;
2176 rt
->rt_flags
= IEEE80211_MESHRT_FLAGS_DISCOVER
;
2177 hr
->hr_preqretries
++;
2178 if (hr
->hr_origseq
== 0)
2179 hr
->hr_origseq
= ++hs
->hs_seq
;
2180 rt
->rt_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
2182 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
, dest
,
2183 "start path discovery (src %s), target seq %u",
2184 m
== NULL
? "<none>" : ether_sprintf(
2185 mtod(m
, struct ether_header
*)->ether_shost
),
2188 * Try to discover the path for this node.
2189 * Group addressed PREQ Case A
2191 preq
.preq_flags
= 0;
2192 preq
.preq_hopcount
= 0;
2193 preq
.preq_ttl
= ms
->ms_ttl
;
2194 preq
.preq_id
= ++hs
->hs_preqid
;
2195 IEEE80211_ADDR_COPY(preq
.preq_origaddr
, vap
->iv_myaddr
);
2196 preq
.preq_origseq
= hr
->hr_origseq
;
2197 preq
.preq_lifetime
=
2198 ticks_to_msecs(ieee80211_hwmp_pathtimeout
);
2199 preq
.preq_metric
= IEEE80211_MESHLMETRIC_INITIALVAL
;
2200 preq
.preq_tcount
= 1;
2201 IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest
);
2203 if (ieee80211_hwmp_targetonly
)
2204 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO
;
2205 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN
;
2206 PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
2207 /* XXX check return value */
2208 hwmp_send_preq(vap
, broadcastaddr
, &preq
,
2209 &hr
->hr_lastpreq
, &ieee80211_hwmp_preqminint
);
2210 callout_reset(&rt
->rt_discovery
,
2211 ieee80211_hwmp_net_diameter_traversaltime
* 2,
2212 hwmp_rediscover_cb
, rt
);
2214 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
)
2215 ni
= ieee80211_find_txnode(vap
, rt
->rt_nexthop
);
2217 ni
= ieee80211_find_txnode(vap
, dest
);
2218 /* NB: if null then we leak mbuf */
2219 KASSERT(ni
!= NULL
, ("leak mcast frame"));
2223 if (ni
== NULL
&& m
!= NULL
) {
2225 struct ieee80211com
*ic
= vap
->iv_ic
;
2227 * Queue packet for transmit when path discovery
2228 * completes. If discovery never completes the
2229 * frame will be flushed by way of the aging timer.
2231 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
, dest
,
2232 "%s", "queue frame until path found");
2233 m
->m_pkthdr
.rcvif
= (void *)(uintptr_t)
2234 ieee80211_mac_hash(ic
, dest
);
2235 /* XXX age chosen randomly */
2236 ieee80211_ageq_append(&ic
->ic_stageq
, m
,
2237 IEEE80211_INACT_WAIT
);
2239 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_HWMP
,
2240 dest
, NULL
, "%s", "no valid path to this node");
2251 hwmp_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2253 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2256 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2259 switch (ireq
->i_type
) {
2260 case IEEE80211_IOC_HWMP_ROOTMODE
:
2261 ireq
->i_val
= hs
->hs_rootmode
;
2263 case IEEE80211_IOC_HWMP_MAXHOPS
:
2264 ireq
->i_val
= hs
->hs_maxhops
;
2271 IEEE80211_IOCTL_GET(hwmp
, hwmp_ioctl_get80211
);
2274 hwmp_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2276 struct ieee80211_hwmp_state
*hs
= vap
->iv_hwmp
;
2279 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2282 switch (ireq
->i_type
) {
2283 case IEEE80211_IOC_HWMP_ROOTMODE
:
2284 if (ireq
->i_val
< 0 || ireq
->i_val
> 3)
2286 hs
->hs_rootmode
= ireq
->i_val
;
2287 hwmp_rootmode_setup(vap
);
2289 case IEEE80211_IOC_HWMP_MAXHOPS
:
2290 if (ireq
->i_val
<= 0 || ireq
->i_val
> 255)
2292 hs
->hs_maxhops
= ireq
->i_val
;
2299 IEEE80211_IOCTL_SET(hwmp
, hwmp_ioctl_set80211
);