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