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 Mesh Point (MBSS) support.
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>
57 #include <net/if_var.h>
58 #include <net/if_media.h>
59 #include <net/if_llc.h>
60 #include <net/ethernet.h>
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_action.h>
64 #ifdef IEEE80211_SUPPORT_SUPERG
65 #include <net80211/ieee80211_superg.h>
67 #include <net80211/ieee80211_input.h>
68 #include <net80211/ieee80211_mesh.h>
70 static void mesh_rt_flush_invalid(struct ieee80211vap
*);
71 static int mesh_select_proto_path(struct ieee80211vap
*, const char *);
72 static int mesh_select_proto_metric(struct ieee80211vap
*, const char *);
73 static void mesh_vattach(struct ieee80211vap
*);
74 static int mesh_newstate(struct ieee80211vap
*, enum ieee80211_state
, int);
75 static void mesh_rt_cleanup_cb(void *);
76 static void mesh_gatemode_setup(struct ieee80211vap
*);
77 static void mesh_gatemode_cb(void *);
78 static void mesh_linkchange(struct ieee80211_node
*,
79 enum ieee80211_mesh_mlstate
);
80 static void mesh_checkid(void *, struct ieee80211_node
*);
81 static uint32_t mesh_generateid(struct ieee80211vap
*);
82 static int mesh_checkpseq(struct ieee80211vap
*,
83 const uint8_t [IEEE80211_ADDR_LEN
], uint32_t);
84 static void mesh_transmit_to_gate(struct ieee80211vap
*, struct mbuf
*,
85 struct ieee80211_mesh_route
*);
86 static void mesh_forward(struct ieee80211vap
*, struct mbuf
*,
87 const struct ieee80211_meshcntl
*);
88 static int mesh_input(struct ieee80211_node
*, struct mbuf
*,
89 const struct ieee80211_rx_stats
*rxs
, int, int);
90 static void mesh_recv_mgmt(struct ieee80211_node
*, struct mbuf
*, int,
91 const struct ieee80211_rx_stats
*rxs
, int, int);
92 static void mesh_recv_ctl(struct ieee80211_node
*, struct mbuf
*, int);
93 static void mesh_peer_timeout_setup(struct ieee80211_node
*);
94 static void mesh_peer_timeout_backoff(struct ieee80211_node
*);
95 static void mesh_peer_timeout_cb(void *);
97 mesh_peer_timeout_stop(struct ieee80211_node
*);
98 static int mesh_verify_meshid(struct ieee80211vap
*, const uint8_t *);
99 static int mesh_verify_meshconf(struct ieee80211vap
*, const uint8_t *);
100 static int mesh_verify_meshpeer(struct ieee80211vap
*, uint8_t,
102 uint32_t mesh_airtime_calc(struct ieee80211_node
*);
105 * Timeout values come from the specification and are in milliseconds.
107 static SYSCTL_NODE(_net_wlan
, OID_AUTO
, mesh
, CTLFLAG_RD
, 0,
108 "IEEE 802.11s parameters");
109 static int ieee80211_mesh_gateint
= -1;
110 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, gateint
, CTLTYPE_INT
| CTLFLAG_RW
,
111 &ieee80211_mesh_gateint
, 0, ieee80211_sysctl_msecs_ticks
, "I",
112 "mesh gate interval (ms)");
113 static int ieee80211_mesh_retrytimeout
= -1;
114 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, retrytimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
115 &ieee80211_mesh_retrytimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
116 "Retry timeout (msec)");
117 static int ieee80211_mesh_holdingtimeout
= -1;
119 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, holdingtimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
120 &ieee80211_mesh_holdingtimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
121 "Holding state timeout (msec)");
122 static int ieee80211_mesh_confirmtimeout
= -1;
123 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, confirmtimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
124 &ieee80211_mesh_confirmtimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
125 "Confirm state timeout (msec)");
126 static int ieee80211_mesh_backofftimeout
= -1;
127 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, backofftimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
128 &ieee80211_mesh_backofftimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
129 "Backoff timeout (msec). This is to throutles peering forever when "
130 "not receiving answer or is rejected by a neighbor");
131 static int ieee80211_mesh_maxretries
= 2;
132 SYSCTL_INT(_net_wlan_mesh
, OID_AUTO
, maxretries
, CTLFLAG_RW
,
133 &ieee80211_mesh_maxretries
, 0,
134 "Maximum retries during peer link establishment");
135 static int ieee80211_mesh_maxholding
= 2;
136 SYSCTL_INT(_net_wlan_mesh
, OID_AUTO
, maxholding
, CTLFLAG_RW
,
137 &ieee80211_mesh_maxholding
, 0,
138 "Maximum times we are allowed to transition to HOLDING state before "
139 "backinoff during peer link establishment");
141 static const uint8_t broadcastaddr
[IEEE80211_ADDR_LEN
] =
142 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
144 static ieee80211_recv_action_func mesh_recv_action_meshpeering_open
;
145 static ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm
;
146 static ieee80211_recv_action_func mesh_recv_action_meshpeering_close
;
147 static ieee80211_recv_action_func mesh_recv_action_meshlmetric
;
148 static ieee80211_recv_action_func mesh_recv_action_meshgate
;
150 static ieee80211_send_action_func mesh_send_action_meshpeering_open
;
151 static ieee80211_send_action_func mesh_send_action_meshpeering_confirm
;
152 static ieee80211_send_action_func mesh_send_action_meshpeering_close
;
153 static ieee80211_send_action_func mesh_send_action_meshlmetric
;
154 static ieee80211_send_action_func mesh_send_action_meshgate
;
156 static const struct ieee80211_mesh_proto_metric mesh_metric_airtime
= {
157 .mpm_descr
= "AIRTIME",
158 .mpm_ie
= IEEE80211_MESHCONF_METRIC_AIRTIME
,
159 .mpm_metric
= mesh_airtime_calc
,
162 static struct ieee80211_mesh_proto_path mesh_proto_paths
[4];
163 static struct ieee80211_mesh_proto_metric mesh_proto_metrics
[4];
165 MALLOC_DEFINE(M_80211_MESH_PREQ
, "80211preq", "802.11 MESH Path Request frame");
166 MALLOC_DEFINE(M_80211_MESH_PREP
, "80211prep", "802.11 MESH Path Reply frame");
167 MALLOC_DEFINE(M_80211_MESH_PERR
, "80211perr", "802.11 MESH Path Error frame");
169 /* The longer one of the lifetime should be stored as new lifetime */
170 #define MESH_ROUTE_LIFETIME_MAX(a, b) (a > b ? a : b)
172 MALLOC_DEFINE(M_80211_MESH_RT
, "80211mesh_rt", "802.11s routing table");
173 MALLOC_DEFINE(M_80211_MESH_GT_RT
, "80211mesh_gt", "802.11s known gates table");
176 * Helper functions to manipulate the Mesh routing table.
179 static struct ieee80211_mesh_route
*
180 mesh_rt_find_locked(struct ieee80211_mesh_state
*ms
,
181 const uint8_t dest
[IEEE80211_ADDR_LEN
])
183 struct ieee80211_mesh_route
*rt
;
185 MESH_RT_LOCK_ASSERT(ms
);
187 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
188 if (IEEE80211_ADDR_EQ(dest
, rt
->rt_dest
))
194 static struct ieee80211_mesh_route
*
195 mesh_rt_add_locked(struct ieee80211vap
*vap
,
196 const uint8_t dest
[IEEE80211_ADDR_LEN
])
198 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
199 struct ieee80211_mesh_route
*rt
;
201 KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr
, dest
),
202 ("%s: adding broadcast to the routing table", __func__
));
204 MESH_RT_LOCK_ASSERT(ms
);
206 rt
= IEEE80211_MALLOC(ALIGN(sizeof(struct ieee80211_mesh_route
)) +
207 ms
->ms_ppath
->mpp_privlen
, M_80211_MESH_RT
,
208 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
211 IEEE80211_ADDR_COPY(rt
->rt_dest
, dest
);
212 rt
->rt_priv
= (void *)ALIGN(&rt
[1]);
213 MESH_RT_ENTRY_LOCK_INIT(rt
, "MBSS_RT");
214 callout_init(&rt
->rt_discovery
, 1);
215 rt
->rt_updtime
= ticks
; /* create time */
216 TAILQ_INSERT_TAIL(&ms
->ms_routes
, rt
, rt_next
);
221 struct ieee80211_mesh_route
*
222 ieee80211_mesh_rt_find(struct ieee80211vap
*vap
,
223 const uint8_t dest
[IEEE80211_ADDR_LEN
])
225 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
226 struct ieee80211_mesh_route
*rt
;
229 rt
= mesh_rt_find_locked(ms
, dest
);
234 struct ieee80211_mesh_route
*
235 ieee80211_mesh_rt_add(struct ieee80211vap
*vap
,
236 const uint8_t dest
[IEEE80211_ADDR_LEN
])
238 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
239 struct ieee80211_mesh_route
*rt
;
241 KASSERT(ieee80211_mesh_rt_find(vap
, dest
) == NULL
,
242 ("%s: duplicate entry in the routing table", __func__
));
243 KASSERT(!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, dest
),
244 ("%s: adding self to the routing table", __func__
));
247 rt
= mesh_rt_add_locked(vap
, dest
);
253 * Update the route lifetime and returns the updated lifetime.
254 * If new_lifetime is zero and route is timedout it will be invalidated.
255 * new_lifetime is in msec
258 ieee80211_mesh_rt_update(struct ieee80211_mesh_route
*rt
, int new_lifetime
)
261 uint32_t lifetime
= 0;
263 KASSERT(rt
!= NULL
, ("route is NULL"));
266 MESH_RT_ENTRY_LOCK(rt
);
268 /* dont clobber a proxy entry gated by us */
269 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
&& rt
->rt_nhops
== 0) {
270 MESH_RT_ENTRY_UNLOCK(rt
);
271 return rt
->rt_lifetime
;
274 timesince
= ticks_to_msecs(now
- rt
->rt_updtime
);
275 rt
->rt_updtime
= now
;
276 if (timesince
>= rt
->rt_lifetime
) {
277 if (new_lifetime
!= 0) {
278 rt
->rt_lifetime
= new_lifetime
;
281 rt
->rt_flags
&= ~IEEE80211_MESHRT_FLAGS_VALID
;
285 /* update what is left of lifetime */
286 rt
->rt_lifetime
= rt
->rt_lifetime
- timesince
;
287 rt
->rt_lifetime
= MESH_ROUTE_LIFETIME_MAX(
288 new_lifetime
, rt
->rt_lifetime
);
290 lifetime
= rt
->rt_lifetime
;
291 MESH_RT_ENTRY_UNLOCK(rt
);
297 * Add a proxy route (as needed) for the specified destination.
300 ieee80211_mesh_proxy_check(struct ieee80211vap
*vap
,
301 const uint8_t dest
[IEEE80211_ADDR_LEN
])
303 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
304 struct ieee80211_mesh_route
*rt
;
307 rt
= mesh_rt_find_locked(ms
, dest
);
309 rt
= mesh_rt_add_locked(vap
, dest
);
311 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
312 "%s", "unable to add proxy entry");
313 vap
->iv_stats
.is_mesh_rtaddfailed
++;
315 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
316 "%s", "add proxy entry");
317 IEEE80211_ADDR_COPY(rt
->rt_mesh_gate
, vap
->iv_myaddr
);
318 IEEE80211_ADDR_COPY(rt
->rt_nexthop
, vap
->iv_myaddr
);
319 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
320 | IEEE80211_MESHRT_FLAGS_PROXY
;
322 } else if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0) {
323 KASSERT(rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
,
324 ("no proxy flag for poxy entry"));
325 struct ieee80211com
*ic
= vap
->iv_ic
;
327 * Fix existing entry created by received frames from
328 * stations that have some memory of dest. We also
329 * flush any frames held on the staging queue; delivering
330 * them is too much trouble right now.
332 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
333 "%s", "fix proxy entry");
334 IEEE80211_ADDR_COPY(rt
->rt_nexthop
, vap
->iv_myaddr
);
335 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
336 | IEEE80211_MESHRT_FLAGS_PROXY
;
337 /* XXX belongs in hwmp */
338 ieee80211_ageq_drain_node(&ic
->ic_stageq
,
339 (void *)(uintptr_t) ieee80211_mac_hash(ic
, dest
));
346 mesh_rt_del(struct ieee80211_mesh_state
*ms
, struct ieee80211_mesh_route
*rt
)
348 TAILQ_REMOVE(&ms
->ms_routes
, rt
, rt_next
);
350 * Grab the lock before destroying it, to be sure no one else
351 * is holding the route.
353 MESH_RT_ENTRY_LOCK(rt
);
354 callout_drain(&rt
->rt_discovery
);
355 MESH_RT_ENTRY_LOCK_DESTROY(rt
);
356 IEEE80211_FREE(rt
, M_80211_MESH_RT
);
360 ieee80211_mesh_rt_del(struct ieee80211vap
*vap
,
361 const uint8_t dest
[IEEE80211_ADDR_LEN
])
363 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
364 struct ieee80211_mesh_route
*rt
, *next
;
367 TAILQ_FOREACH_SAFE(rt
, &ms
->ms_routes
, rt_next
, next
) {
368 if (IEEE80211_ADDR_EQ(rt
->rt_dest
, dest
)) {
369 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
) {
370 ms
->ms_ppath
->mpp_senderror(vap
, dest
, rt
,
371 IEEE80211_REASON_MESH_PERR_NO_PROXY
);
373 ms
->ms_ppath
->mpp_senderror(vap
, dest
, rt
,
374 IEEE80211_REASON_MESH_PERR_DEST_UNREACH
);
385 ieee80211_mesh_rt_flush(struct ieee80211vap
*vap
)
387 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
388 struct ieee80211_mesh_route
*rt
, *next
;
393 TAILQ_FOREACH_SAFE(rt
, &ms
->ms_routes
, rt_next
, next
)
399 ieee80211_mesh_rt_flush_peer(struct ieee80211vap
*vap
,
400 const uint8_t peer
[IEEE80211_ADDR_LEN
])
402 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
403 struct ieee80211_mesh_route
*rt
, *next
;
406 TAILQ_FOREACH_SAFE(rt
, &ms
->ms_routes
, rt_next
, next
) {
407 if (IEEE80211_ADDR_EQ(rt
->rt_nexthop
, peer
))
414 * Flush expired routing entries, i.e. those in invalid state for
418 mesh_rt_flush_invalid(struct ieee80211vap
*vap
)
420 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
421 struct ieee80211_mesh_route
*rt
, *next
;
426 TAILQ_FOREACH_SAFE(rt
, &ms
->ms_routes
, rt_next
, next
) {
427 /* Discover paths will be deleted by their own callout */
428 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_DISCOVER
)
430 ieee80211_mesh_rt_update(rt
, 0);
431 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0)
438 ieee80211_mesh_register_proto_path(const struct ieee80211_mesh_proto_path
*mpp
)
440 int i
, firstempty
= -1;
442 for (i
= 0; i
< nitems(mesh_proto_paths
); i
++) {
443 if (strncmp(mpp
->mpp_descr
, mesh_proto_paths
[i
].mpp_descr
,
444 IEEE80211_MESH_PROTO_DSZ
) == 0)
446 if (!mesh_proto_paths
[i
].mpp_active
&& firstempty
== -1)
451 memcpy(&mesh_proto_paths
[firstempty
], mpp
, sizeof(*mpp
));
452 mesh_proto_paths
[firstempty
].mpp_active
= 1;
457 ieee80211_mesh_register_proto_metric(const struct
458 ieee80211_mesh_proto_metric
*mpm
)
460 int i
, firstempty
= -1;
462 for (i
= 0; i
< nitems(mesh_proto_metrics
); i
++) {
463 if (strncmp(mpm
->mpm_descr
, mesh_proto_metrics
[i
].mpm_descr
,
464 IEEE80211_MESH_PROTO_DSZ
) == 0)
466 if (!mesh_proto_metrics
[i
].mpm_active
&& firstempty
== -1)
471 memcpy(&mesh_proto_metrics
[firstempty
], mpm
, sizeof(*mpm
));
472 mesh_proto_metrics
[firstempty
].mpm_active
= 1;
477 mesh_select_proto_path(struct ieee80211vap
*vap
, const char *name
)
479 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
482 for (i
= 0; i
< nitems(mesh_proto_paths
); i
++) {
483 if (strcasecmp(mesh_proto_paths
[i
].mpp_descr
, name
) == 0) {
484 ms
->ms_ppath
= &mesh_proto_paths
[i
];
492 mesh_select_proto_metric(struct ieee80211vap
*vap
, const char *name
)
494 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
497 for (i
= 0; i
< nitems(mesh_proto_metrics
); i
++) {
498 if (strcasecmp(mesh_proto_metrics
[i
].mpm_descr
, name
) == 0) {
499 ms
->ms_pmetric
= &mesh_proto_metrics
[i
];
507 mesh_gatemode_setup(struct ieee80211vap
*vap
)
509 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
512 * NB: When a mesh gate is running as a ROOT it shall
513 * not send out periodic GANNs but instead mark the
514 * mesh gate flag for the corresponding proactive PREQ
517 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_ROOT
||
518 (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
) == 0) {
519 callout_drain(&ms
->ms_gatetimer
);
522 callout_reset(&ms
->ms_gatetimer
, ieee80211_mesh_gateint
,
523 mesh_gatemode_cb
, vap
);
527 mesh_gatemode_cb(void *arg
)
529 struct ieee80211vap
*vap
= (struct ieee80211vap
*)arg
;
530 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
531 struct ieee80211_meshgann_ie gann
;
533 gann
.gann_flags
= 0; /* Reserved */
534 gann
.gann_hopcount
= 0;
535 gann
.gann_ttl
= ms
->ms_ttl
;
536 IEEE80211_ADDR_COPY(gann
.gann_addr
, vap
->iv_myaddr
);
537 gann
.gann_seq
= ms
->ms_gateseq
++;
538 gann
.gann_interval
= ieee80211_mesh_gateint
;
540 IEEE80211_NOTE(vap
, IEEE80211_MSG_MESH
, vap
->iv_bss
,
541 "send broadcast GANN (seq %u)", gann
.gann_seq
);
543 ieee80211_send_action(vap
->iv_bss
, IEEE80211_ACTION_CAT_MESH
,
544 IEEE80211_ACTION_MESH_GANN
, &gann
);
545 mesh_gatemode_setup(vap
);
549 ieee80211_mesh_init(void)
552 memset(mesh_proto_paths
, 0, sizeof(mesh_proto_paths
));
553 memset(mesh_proto_metrics
, 0, sizeof(mesh_proto_metrics
));
556 * Setup mesh parameters that depends on the clock frequency.
558 ieee80211_mesh_gateint
= msecs_to_ticks(10000);
559 ieee80211_mesh_retrytimeout
= msecs_to_ticks(40);
560 ieee80211_mesh_holdingtimeout
= msecs_to_ticks(40);
561 ieee80211_mesh_confirmtimeout
= msecs_to_ticks(40);
562 ieee80211_mesh_backofftimeout
= msecs_to_ticks(5000);
565 * Register action frame handlers.
567 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
568 IEEE80211_ACTION_MESHPEERING_OPEN
,
569 mesh_recv_action_meshpeering_open
);
570 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
571 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
572 mesh_recv_action_meshpeering_confirm
);
573 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
574 IEEE80211_ACTION_MESHPEERING_CLOSE
,
575 mesh_recv_action_meshpeering_close
);
576 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH
,
577 IEEE80211_ACTION_MESH_LMETRIC
, mesh_recv_action_meshlmetric
);
578 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH
,
579 IEEE80211_ACTION_MESH_GANN
, mesh_recv_action_meshgate
);
581 ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
582 IEEE80211_ACTION_MESHPEERING_OPEN
,
583 mesh_send_action_meshpeering_open
);
584 ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
585 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
586 mesh_send_action_meshpeering_confirm
);
587 ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT
,
588 IEEE80211_ACTION_MESHPEERING_CLOSE
,
589 mesh_send_action_meshpeering_close
);
590 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH
,
591 IEEE80211_ACTION_MESH_LMETRIC
,
592 mesh_send_action_meshlmetric
);
593 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH
,
594 IEEE80211_ACTION_MESH_GANN
,
595 mesh_send_action_meshgate
);
598 * Register Airtime Link Metric.
600 ieee80211_mesh_register_proto_metric(&mesh_metric_airtime
);
603 SYSINIT(wlan_mesh
, SI_SUB_DRIVERS
, SI_ORDER_FIRST
, ieee80211_mesh_init
, NULL
);
606 ieee80211_mesh_attach(struct ieee80211com
*ic
)
608 ic
->ic_vattach
[IEEE80211_M_MBSS
] = mesh_vattach
;
612 ieee80211_mesh_detach(struct ieee80211com
*ic
)
617 mesh_vdetach_peers(void *arg
, struct ieee80211_node
*ni
)
619 struct ieee80211com
*ic
= ni
->ni_ic
;
622 if (ni
->ni_mlstate
== IEEE80211_NODE_MESH_ESTABLISHED
) {
623 args
[0] = ni
->ni_mlpid
;
624 args
[1] = ni
->ni_mllid
;
625 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
626 ieee80211_send_action(ni
,
627 IEEE80211_ACTION_CAT_SELF_PROT
,
628 IEEE80211_ACTION_MESHPEERING_CLOSE
,
631 callout_drain(&ni
->ni_mltimer
);
632 /* XXX belongs in hwmp */
633 ieee80211_ageq_drain_node(&ic
->ic_stageq
,
634 (void *)(uintptr_t) ieee80211_mac_hash(ic
, ni
->ni_macaddr
));
638 mesh_vdetach(struct ieee80211vap
*vap
)
640 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
642 callout_drain(&ms
->ms_cleantimer
);
643 ieee80211_iterate_nodes(&vap
->iv_ic
->ic_sta
, mesh_vdetach_peers
,
645 ieee80211_mesh_rt_flush(vap
);
646 MESH_RT_LOCK_DESTROY(ms
);
647 ms
->ms_ppath
->mpp_vdetach(vap
);
648 IEEE80211_FREE(vap
->iv_mesh
, M_80211_VAP
);
653 mesh_vattach(struct ieee80211vap
*vap
)
655 struct ieee80211_mesh_state
*ms
;
656 vap
->iv_newstate
= mesh_newstate
;
657 vap
->iv_input
= mesh_input
;
658 vap
->iv_opdetach
= mesh_vdetach
;
659 vap
->iv_recv_mgmt
= mesh_recv_mgmt
;
660 vap
->iv_recv_ctl
= mesh_recv_ctl
;
661 ms
= IEEE80211_MALLOC(sizeof(struct ieee80211_mesh_state
), M_80211_VAP
,
662 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
664 printf("%s: couldn't alloc MBSS state\n", __func__
);
669 ms
->ms_flags
= (IEEE80211_MESHFLAGS_AP
| IEEE80211_MESHFLAGS_FWD
);
670 ms
->ms_ttl
= IEEE80211_MESH_DEFAULT_TTL
;
671 TAILQ_INIT(&ms
->ms_known_gates
);
672 TAILQ_INIT(&ms
->ms_routes
);
673 MESH_RT_LOCK_INIT(ms
, "MBSS");
674 callout_init(&ms
->ms_cleantimer
, 1);
675 callout_init(&ms
->ms_gatetimer
, 1);
677 mesh_select_proto_metric(vap
, "AIRTIME");
678 KASSERT(ms
->ms_pmetric
, ("ms_pmetric == NULL"));
679 mesh_select_proto_path(vap
, "HWMP");
680 KASSERT(ms
->ms_ppath
, ("ms_ppath == NULL"));
681 ms
->ms_ppath
->mpp_vattach(vap
);
685 * IEEE80211_M_MBSS vap state machine handler.
688 mesh_newstate(struct ieee80211vap
*vap
, enum ieee80211_state nstate
, int arg
)
690 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
691 struct ieee80211com
*ic
= vap
->iv_ic
;
692 struct ieee80211_node
*ni
;
693 enum ieee80211_state ostate
;
695 IEEE80211_LOCK_ASSERT(ic
);
697 ostate
= vap
->iv_state
;
698 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
699 __func__
, ieee80211_state_name
[ostate
],
700 ieee80211_state_name
[nstate
], arg
);
701 vap
->iv_state
= nstate
; /* state transition */
702 if (ostate
!= IEEE80211_S_SCAN
)
703 ieee80211_cancel_scan(vap
); /* background scan */
704 ni
= vap
->iv_bss
; /* NB: no reference held */
705 if (nstate
!= IEEE80211_S_RUN
&& ostate
== IEEE80211_S_RUN
) {
706 callout_drain(&ms
->ms_cleantimer
);
707 callout_drain(&ms
->ms_gatetimer
);
710 case IEEE80211_S_INIT
:
712 case IEEE80211_S_SCAN
:
713 ieee80211_cancel_scan(vap
);
715 case IEEE80211_S_CAC
:
716 ieee80211_dfs_cac_stop(vap
);
718 case IEEE80211_S_RUN
:
719 ieee80211_iterate_nodes(&ic
->ic_sta
,
720 mesh_vdetach_peers
, NULL
);
725 if (ostate
!= IEEE80211_S_INIT
) {
726 /* NB: optimize INIT -> INIT case */
727 ieee80211_reset_bss(vap
);
728 ieee80211_mesh_rt_flush(vap
);
731 case IEEE80211_S_SCAN
:
733 case IEEE80211_S_INIT
:
734 if (vap
->iv_des_chan
!= IEEE80211_CHAN_ANYC
&&
735 !IEEE80211_IS_CHAN_RADAR(vap
->iv_des_chan
) &&
738 * Already have a channel and a mesh ID; bypass
739 * the scan and startup immediately.
741 ieee80211_create_ibss(vap
, vap
->iv_des_chan
);
745 * Initiate a scan. We can come here as a result
746 * of an IEEE80211_IOC_SCAN_REQ too in which case
747 * the vap will be marked with IEEE80211_FEXT_SCANREQ
748 * and the scan request parameters will be present
749 * in iv_scanreq. Otherwise we do the default.
751 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SCANREQ
) {
752 ieee80211_check_scan(vap
,
753 vap
->iv_scanreq_flags
,
754 vap
->iv_scanreq_duration
,
755 vap
->iv_scanreq_mindwell
,
756 vap
->iv_scanreq_maxdwell
,
757 vap
->iv_scanreq_nssid
, vap
->iv_scanreq_ssid
);
758 vap
->iv_flags_ext
&= ~IEEE80211_FEXT_SCANREQ
;
760 ieee80211_check_scan_current(vap
);
766 case IEEE80211_S_CAC
:
768 * Start CAC on a DFS channel. We come here when starting
769 * a bss on a DFS channel (see ieee80211_create_ibss).
771 ieee80211_dfs_cac_start(vap
);
773 case IEEE80211_S_RUN
:
775 case IEEE80211_S_INIT
:
777 * Already have a channel; bypass the
778 * scan and startup immediately.
779 * Note that ieee80211_create_ibss will call
780 * back to do a RUN->RUN state change.
782 ieee80211_create_ibss(vap
,
783 ieee80211_ht_adjust_channel(ic
,
784 ic
->ic_curchan
, vap
->iv_flags_ht
));
785 /* NB: iv_bss is changed on return */
787 case IEEE80211_S_CAC
:
789 * NB: This is the normal state change when CAC
790 * expires and no radar was detected; no need to
791 * clear the CAC timer as it's already expired.
794 case IEEE80211_S_CSA
:
797 * Shorten inactivity timer of associated stations
798 * to weed out sta's that don't follow a CSA.
800 ieee80211_iterate_nodes(&ic
->ic_sta
, sta_csa
, vap
);
803 * Update bss node channel to reflect where
804 * we landed after CSA.
806 ieee80211_node_set_chan(ni
,
807 ieee80211_ht_adjust_channel(ic
, ic
->ic_curchan
,
808 ieee80211_htchanflags(ni
->ni_chan
)));
809 /* XXX bypass debug msgs */
811 case IEEE80211_S_SCAN
:
812 case IEEE80211_S_RUN
:
813 #ifdef IEEE80211_DEBUG
814 if (ieee80211_msg_debug(vap
)) {
816 "synchronized with %s meshid ",
817 ether_sprintf(ni
->ni_meshid
));
818 ieee80211_print_essid(ni
->ni_meshid
,
821 printf(" channel %d\n",
822 ieee80211_chan2ieee(ic
, ic
->ic_curchan
));
829 ieee80211_node_authorize(ni
);
830 callout_reset(&ms
->ms_cleantimer
, ms
->ms_ppath
->mpp_inact
,
831 mesh_rt_cleanup_cb
, vap
);
832 mesh_gatemode_setup(vap
);
837 /* NB: ostate not nstate */
838 ms
->ms_ppath
->mpp_newstate(vap
, ostate
, arg
);
843 mesh_rt_cleanup_cb(void *arg
)
845 struct ieee80211vap
*vap
= arg
;
846 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
848 mesh_rt_flush_invalid(vap
);
849 callout_reset(&ms
->ms_cleantimer
, ms
->ms_ppath
->mpp_inact
,
850 mesh_rt_cleanup_cb
, vap
);
854 * Mark a mesh STA as gate and return a pointer to it.
855 * If this is first time, we create a new gate route.
856 * Always update the path route to this mesh gate.
858 struct ieee80211_mesh_gate_route
*
859 ieee80211_mesh_mark_gate(struct ieee80211vap
*vap
, const uint8_t *addr
,
860 struct ieee80211_mesh_route
*rt
)
862 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
863 struct ieee80211_mesh_gate_route
*gr
= NULL
, *next
;
867 TAILQ_FOREACH_SAFE(gr
, &ms
->ms_known_gates
, gr_next
, next
) {
868 if (IEEE80211_ADDR_EQ(gr
->gr_addr
, addr
)) {
875 /* New mesh gate add it to known table. */
876 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, addr
,
877 "%s", "stored new gate information from pro-PREQ.");
878 gr
= IEEE80211_MALLOC(ALIGN(sizeof(struct ieee80211_mesh_gate_route
)),
880 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
881 IEEE80211_ADDR_COPY(gr
->gr_addr
, addr
);
882 TAILQ_INSERT_TAIL(&ms
->ms_known_gates
, gr
, gr_next
);
885 /* TODO: link from path route to gate route */
893 * Helper function to note the Mesh Peer Link FSM change.
896 mesh_linkchange(struct ieee80211_node
*ni
, enum ieee80211_mesh_mlstate state
)
898 struct ieee80211vap
*vap
= ni
->ni_vap
;
899 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
900 #ifdef IEEE80211_DEBUG
901 static const char *meshlinkstates
[] = {
902 [IEEE80211_NODE_MESH_IDLE
] = "IDLE",
903 [IEEE80211_NODE_MESH_OPENSNT
] = "OPEN SENT",
904 [IEEE80211_NODE_MESH_OPENRCV
] = "OPEN RECEIVED",
905 [IEEE80211_NODE_MESH_CONFIRMRCV
] = "CONFIRM RECEIVED",
906 [IEEE80211_NODE_MESH_ESTABLISHED
] = "ESTABLISHED",
907 [IEEE80211_NODE_MESH_HOLDING
] = "HOLDING"
910 IEEE80211_NOTE(vap
, IEEE80211_MSG_MESH
,
911 ni
, "peer link: %s -> %s",
912 meshlinkstates
[ni
->ni_mlstate
], meshlinkstates
[state
]);
914 /* track neighbor count */
915 if (state
== IEEE80211_NODE_MESH_ESTABLISHED
&&
916 ni
->ni_mlstate
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
917 KASSERT(ms
->ms_neighbors
< 65535, ("neighbor count overflow"));
919 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_MESHCONF
);
920 } else if (ni
->ni_mlstate
== IEEE80211_NODE_MESH_ESTABLISHED
&&
921 state
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
922 KASSERT(ms
->ms_neighbors
> 0, ("neighbor count 0"));
924 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_MESHCONF
);
926 ni
->ni_mlstate
= state
;
928 case IEEE80211_NODE_MESH_HOLDING
:
929 ms
->ms_ppath
->mpp_peerdown(ni
);
931 case IEEE80211_NODE_MESH_ESTABLISHED
:
932 ieee80211_mesh_discover(vap
, ni
->ni_macaddr
, NULL
);
940 * Helper function to generate a unique local ID required for mesh
941 * peer establishment.
944 mesh_checkid(void *arg
, struct ieee80211_node
*ni
)
948 if (*r
== ni
->ni_mllid
)
949 *(uint16_t *)arg
= 0;
953 mesh_generateid(struct ieee80211vap
*vap
)
959 get_random_bytes(&r
, 2);
960 ieee80211_iterate_nodes(&vap
->iv_ic
->ic_sta
, mesh_checkid
, &r
);
962 } while (r
== 0 && maxiter
> 0);
967 * Verifies if we already received this packet by checking its
969 * Returns 0 if the frame is to be accepted, 1 otherwise.
972 mesh_checkpseq(struct ieee80211vap
*vap
,
973 const uint8_t source
[IEEE80211_ADDR_LEN
], uint32_t seq
)
975 struct ieee80211_mesh_route
*rt
;
977 rt
= ieee80211_mesh_rt_find(vap
, source
);
979 rt
= ieee80211_mesh_rt_add(vap
, source
);
981 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, source
,
982 "%s", "add mcast route failed");
983 vap
->iv_stats
.is_mesh_rtaddfailed
++;
986 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, source
,
987 "add mcast route, mesh seqno %d", seq
);
988 rt
->rt_lastmseq
= seq
;
991 if (IEEE80211_MESH_SEQ_GEQ(rt
->rt_lastmseq
, seq
)) {
994 rt
->rt_lastmseq
= seq
;
1000 * Iterate the routing table and locate the next hop.
1002 struct ieee80211_node
*
1003 ieee80211_mesh_find_txnode(struct ieee80211vap
*vap
,
1004 const uint8_t dest
[IEEE80211_ADDR_LEN
])
1006 struct ieee80211_mesh_route
*rt
;
1008 rt
= ieee80211_mesh_rt_find(vap
, dest
);
1011 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0) {
1012 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
1013 "%s: !valid, flags 0x%x", __func__
, rt
->rt_flags
);
1017 if (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
) {
1018 rt
= ieee80211_mesh_rt_find(vap
, rt
->rt_mesh_gate
);
1019 if (rt
== NULL
) return NULL
;
1020 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0) {
1021 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
1022 "%s: meshgate !valid, flags 0x%x", __func__
,
1028 return ieee80211_find_txnode(vap
, rt
->rt_nexthop
);
1032 mesh_transmit_to_gate(struct ieee80211vap
*vap
, struct mbuf
*m
,
1033 struct ieee80211_mesh_route
*rt_gate
)
1035 struct ifnet
*ifp
= vap
->iv_ifp
;
1036 struct ieee80211_node
*ni
;
1038 IEEE80211_TX_UNLOCK_ASSERT(vap
->iv_ic
);
1040 ni
= ieee80211_mesh_find_txnode(vap
, rt_gate
->rt_dest
);
1042 if_inc_counter(ifp
, IFCOUNTER_OERRORS
, 1);
1048 * Send through the VAP packet transmit path.
1049 * This consumes the node ref grabbed above and
1050 * the mbuf, regardless of whether there's a problem
1053 (void) ieee80211_vap_pkt_send_dest(vap
, m
, ni
);
1057 * Forward the queued frames to known valid mesh gates.
1058 * Assume destination to be outside the MBSS (i.e. proxy entry),
1059 * If no valid mesh gates are known silently discard queued frames.
1060 * After transmitting frames to all known valid mesh gates, this route
1061 * will be marked invalid, and a new path discovery will happen in the hopes
1062 * that (at least) one of the mesh gates have a new proxy entry for us to use.
1065 ieee80211_mesh_forward_to_gates(struct ieee80211vap
*vap
,
1066 struct ieee80211_mesh_route
*rt_dest
)
1068 struct ieee80211com
*ic
= vap
->iv_ic
;
1069 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1070 struct ieee80211_mesh_route
*rt_gate
;
1071 struct ieee80211_mesh_gate_route
*gr
= NULL
, *gr_next
;
1072 struct mbuf
*m
, *mcopy
, *next
;
1074 IEEE80211_TX_UNLOCK_ASSERT(ic
);
1076 KASSERT( rt_dest
->rt_flags
== IEEE80211_MESHRT_FLAGS_DISCOVER
,
1077 ("Route is not marked with IEEE80211_MESHRT_FLAGS_DISCOVER"));
1079 /* XXX: send to more than one valid mash gate */
1082 m
= ieee80211_ageq_remove(&ic
->ic_stageq
,
1083 (struct ieee80211_node
*)(uintptr_t)
1084 ieee80211_mac_hash(ic
, rt_dest
->rt_dest
));
1086 TAILQ_FOREACH_SAFE(gr
, &ms
->ms_known_gates
, gr_next
, gr_next
) {
1087 rt_gate
= gr
->gr_route
;
1088 if (rt_gate
== NULL
) {
1089 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
,
1091 "mesh gate with no path %6D",
1095 if ((rt_gate
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0)
1097 KASSERT(rt_gate
->rt_flags
& IEEE80211_MESHRT_FLAGS_GATE
,
1098 ("route not marked as a mesh gate"));
1099 KASSERT((rt_gate
->rt_flags
&
1100 IEEE80211_MESHRT_FLAGS_PROXY
) == 0,
1101 ("found mesh gate that is also marked porxy"));
1103 * convert route to a proxy route gated by the current
1104 * mesh gate, this is needed so encap can built data
1105 * frame with correct address.
1107 rt_dest
->rt_flags
= IEEE80211_MESHRT_FLAGS_PROXY
|
1108 IEEE80211_MESHRT_FLAGS_VALID
;
1109 rt_dest
->rt_ext_seq
= 1; /* random value */
1110 IEEE80211_ADDR_COPY(rt_dest
->rt_mesh_gate
, rt_gate
->rt_dest
);
1111 IEEE80211_ADDR_COPY(rt_dest
->rt_nexthop
, rt_gate
->rt_nexthop
);
1112 rt_dest
->rt_metric
= rt_gate
->rt_metric
;
1113 rt_dest
->rt_nhops
= rt_gate
->rt_nhops
;
1114 ieee80211_mesh_rt_update(rt_dest
, ms
->ms_ppath
->mpp_inact
);
1117 mcopy
= m_dup(m
, M_NOWAIT
);
1118 for (; mcopy
!= NULL
; mcopy
= next
) {
1119 next
= mcopy
->m_nextpkt
;
1120 mcopy
->m_nextpkt
= NULL
;
1121 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_HWMP
,
1123 "flush queued frame %p len %d", mcopy
,
1124 mcopy
->m_pkthdr
.len
);
1125 mesh_transmit_to_gate(vap
, mcopy
, rt_gate
);
1129 rt_dest
->rt_flags
= 0; /* Mark invalid */
1135 * Forward the specified frame.
1136 * Decrement the TTL and set TA to our MAC address.
1139 mesh_forward(struct ieee80211vap
*vap
, struct mbuf
*m
,
1140 const struct ieee80211_meshcntl
*mc
)
1142 struct ieee80211com
*ic
= vap
->iv_ic
;
1143 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1144 struct ifnet
*ifp
= vap
->iv_ifp
;
1145 const struct ieee80211_frame
*wh
=
1146 mtod(m
, const struct ieee80211_frame
*);
1148 struct ieee80211_meshcntl
*mccopy
;
1149 struct ieee80211_frame
*whcopy
;
1150 struct ieee80211_node
*ni
;
1153 /* This is called from the RX path - don't hold this lock */
1154 IEEE80211_TX_UNLOCK_ASSERT(ic
);
1157 * mesh ttl of 1 means we are the last one receiving it,
1158 * according to amendment we decrement and then check if
1159 * 0, if so we dont forward.
1161 if (mc
->mc_ttl
< 1) {
1162 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
1163 "%s", "frame not fwd'd, ttl 1");
1164 vap
->iv_stats
.is_mesh_fwd_ttl
++;
1167 if (!(ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)) {
1168 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
1169 "%s", "frame not fwd'd, fwding disabled");
1170 vap
->iv_stats
.is_mesh_fwd_disabled
++;
1173 mcopy
= m_dup(m
, M_NOWAIT
);
1174 if (mcopy
== NULL
) {
1175 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
1176 "%s", "frame not fwd'd, cannot dup");
1177 vap
->iv_stats
.is_mesh_fwd_nobuf
++;
1178 if_inc_counter(ifp
, IFCOUNTER_OERRORS
, 1);
1181 mcopy
= m_pullup(mcopy
, ieee80211_hdrspace(ic
, wh
) +
1182 sizeof(struct ieee80211_meshcntl
));
1183 if (mcopy
== NULL
) {
1184 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
1185 "%s", "frame not fwd'd, too short");
1186 vap
->iv_stats
.is_mesh_fwd_tooshort
++;
1187 if_inc_counter(ifp
, IFCOUNTER_OERRORS
, 1);
1191 whcopy
= mtod(mcopy
, struct ieee80211_frame
*);
1192 mccopy
= (struct ieee80211_meshcntl
*)
1193 (mtod(mcopy
, uint8_t *) + ieee80211_hdrspace(ic
, wh
));
1194 /* XXX clear other bits? */
1195 whcopy
->i_fc
[1] &= ~IEEE80211_FC1_RETRY
;
1196 IEEE80211_ADDR_COPY(whcopy
->i_addr2
, vap
->iv_myaddr
);
1197 if (IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
1198 ni
= ieee80211_ref_node(vap
->iv_bss
);
1199 mcopy
->m_flags
|= M_MCAST
;
1201 ni
= ieee80211_mesh_find_txnode(vap
, whcopy
->i_addr3
);
1204 * [Optional] any of the following three actions:
1205 * o silently discard
1206 * o trigger a path discovery
1207 * o inform TA that meshDA is unknown.
1209 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
1210 "%s", "frame not fwd'd, no path");
1211 ms
->ms_ppath
->mpp_senderror(vap
, whcopy
->i_addr3
, NULL
,
1212 IEEE80211_REASON_MESH_PERR_NO_FI
);
1213 vap
->iv_stats
.is_mesh_fwd_nopath
++;
1217 IEEE80211_ADDR_COPY(whcopy
->i_addr1
, ni
->ni_macaddr
);
1219 KASSERT(mccopy
->mc_ttl
> 0, ("%s called with wrong ttl", __func__
));
1222 /* XXX calculate priority so drivers can find the tx queue */
1223 M_WME_SETAC(mcopy
, WME_AC_BE
);
1225 /* XXX do we know m_nextpkt is NULL? */
1226 mcopy
->m_pkthdr
.rcvif
= (void *) ni
;
1229 * XXX this bypasses all of the VAP TX handling; it passes frames
1230 * directly to the parent interface.
1232 * Because of this, there's no TX lock being held as there's no
1233 * encaps state being used.
1235 * Doing a direct parent transmit may not be the correct thing
1236 * to do here; we'll have to re-think this soon.
1238 IEEE80211_TX_LOCK(ic
);
1239 err
= ieee80211_parent_xmitpkt(ic
, mcopy
);
1240 IEEE80211_TX_UNLOCK(ic
);
1242 if_inc_counter(ifp
, IFCOUNTER_OPACKETS
, 1);
1245 static struct mbuf
*
1246 mesh_decap(struct ieee80211vap
*vap
, struct mbuf
*m
, int hdrlen
, int meshdrlen
)
1248 #define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
1249 #define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
1250 uint8_t b
[sizeof(struct ieee80211_qosframe_addr4
) +
1251 sizeof(struct ieee80211_meshcntl_ae10
)];
1252 const struct ieee80211_qosframe_addr4
*wh
;
1253 const struct ieee80211_meshcntl_ae10
*mc
;
1254 struct ether_header
*eh
;
1258 if (m
->m_len
< hdrlen
+ sizeof(*llc
) &&
1259 (m
= m_pullup(m
, hdrlen
+ sizeof(*llc
))) == NULL
) {
1260 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_ANY
,
1261 "discard data frame: %s", "m_pullup failed");
1262 vap
->iv_stats
.is_rx_tooshort
++;
1265 memcpy(b
, mtod(m
, caddr_t
), hdrlen
);
1266 wh
= (const struct ieee80211_qosframe_addr4
*)&b
[0];
1267 mc
= (const struct ieee80211_meshcntl_ae10
*)&b
[hdrlen
- meshdrlen
];
1268 KASSERT(WHDIR(wh
) == IEEE80211_FC1_DIR_FROMDS
||
1269 WHDIR(wh
) == IEEE80211_FC1_DIR_DSTODS
,
1270 ("bogus dir, fc 0x%x:0x%x", wh
->i_fc
[0], wh
->i_fc
[1]));
1272 llc
= (struct llc
*)(mtod(m
, caddr_t
) + hdrlen
);
1273 if (llc
->llc_dsap
== LLC_SNAP_LSAP
&& llc
->llc_ssap
== LLC_SNAP_LSAP
&&
1274 llc
->llc_control
== LLC_UI
&& llc
->llc_snap
.org_code
[0] == 0 &&
1275 llc
->llc_snap
.org_code
[1] == 0 && llc
->llc_snap
.org_code
[2] == 0 &&
1276 /* NB: preserve AppleTalk frames that have a native SNAP hdr */
1277 !(llc
->llc_snap
.ether_type
== htons(ETHERTYPE_AARP
) ||
1278 llc
->llc_snap
.ether_type
== htons(ETHERTYPE_IPX
))) {
1279 m_adj(m
, hdrlen
+ sizeof(struct llc
) - sizeof(*eh
));
1282 m_adj(m
, hdrlen
- sizeof(*eh
));
1284 eh
= mtod(m
, struct ether_header
*);
1285 ae
= mc
->mc_flags
& IEEE80211_MESH_AE_MASK
;
1286 if (WHDIR(wh
) == IEEE80211_FC1_DIR_FROMDS
) {
1287 IEEE80211_ADDR_COPY(eh
->ether_dhost
, wh
->i_addr1
);
1288 if (ae
== IEEE80211_MESH_AE_00
) {
1289 IEEE80211_ADDR_COPY(eh
->ether_shost
, wh
->i_addr3
);
1290 } else if (ae
== IEEE80211_MESH_AE_01
) {
1291 IEEE80211_ADDR_COPY(eh
->ether_shost
,
1292 MC01(mc
)->mc_addr4
);
1294 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
1295 (const struct ieee80211_frame
*)wh
, NULL
,
1297 vap
->iv_stats
.is_mesh_badae
++;
1302 if (ae
== IEEE80211_MESH_AE_00
) {
1303 IEEE80211_ADDR_COPY(eh
->ether_dhost
, wh
->i_addr3
);
1304 IEEE80211_ADDR_COPY(eh
->ether_shost
, wh
->i_addr4
);
1305 } else if (ae
== IEEE80211_MESH_AE_10
) {
1306 IEEE80211_ADDR_COPY(eh
->ether_dhost
, mc
->mc_addr5
);
1307 IEEE80211_ADDR_COPY(eh
->ether_shost
, mc
->mc_addr6
);
1309 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
1310 (const struct ieee80211_frame
*)wh
, NULL
,
1312 vap
->iv_stats
.is_mesh_badae
++;
1317 #ifndef __NO_STRICT_ALIGNMENT
1318 if (!ALIGNED_POINTER(mtod(m
, caddr_t
) + sizeof(*eh
), uint32_t)) {
1319 m
= ieee80211_realign(vap
, m
, sizeof(*eh
));
1323 #endif /* !__NO_STRICT_ALIGNMENT */
1325 eh
= mtod(m
, struct ether_header
*);
1326 eh
->ether_type
= htons(m
->m_pkthdr
.len
- sizeof(*eh
));
1334 * Return non-zero if the unicast mesh data frame should be processed
1335 * locally. Frames that are not proxy'd have our address, otherwise
1336 * we need to consult the routing table to look for a proxy entry.
1339 mesh_isucastforme(struct ieee80211vap
*vap
, const struct ieee80211_frame
*wh
,
1340 const struct ieee80211_meshcntl
*mc
)
1342 int ae
= mc
->mc_flags
& 3;
1344 KASSERT((wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
) == IEEE80211_FC1_DIR_DSTODS
,
1345 ("bad dir 0x%x:0x%x", wh
->i_fc
[0], wh
->i_fc
[1]));
1346 KASSERT(ae
== IEEE80211_MESH_AE_00
|| ae
== IEEE80211_MESH_AE_10
,
1348 if (ae
== IEEE80211_MESH_AE_10
) { /* ucast w/ proxy */
1349 const struct ieee80211_meshcntl_ae10
*mc10
=
1350 (const struct ieee80211_meshcntl_ae10
*) mc
;
1351 struct ieee80211_mesh_route
*rt
=
1352 ieee80211_mesh_rt_find(vap
, mc10
->mc_addr5
);
1353 /* check for proxy route to ourself */
1354 return (rt
!= NULL
&&
1355 (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
));
1356 } else /* ucast w/o proxy */
1357 return IEEE80211_ADDR_EQ(wh
->i_addr3
, vap
->iv_myaddr
);
1361 * Verifies transmitter, updates lifetime, precursor list and forwards data.
1362 * > 0 means we have forwarded data and no need to process locally
1363 * == 0 means we want to process locally (and we may have forwarded data
1364 * < 0 means there was an error and data should be discarded
1367 mesh_recv_indiv_data_to_fwrd(struct ieee80211vap
*vap
, struct mbuf
*m
,
1368 struct ieee80211_frame
*wh
, const struct ieee80211_meshcntl
*mc
)
1370 struct ieee80211_qosframe_addr4
*qwh
;
1371 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1372 struct ieee80211_mesh_route
*rt_meshda
, *rt_meshsa
;
1374 /* This is called from the RX path - don't hold this lock */
1375 IEEE80211_TX_UNLOCK_ASSERT(vap
->iv_ic
);
1377 qwh
= (struct ieee80211_qosframe_addr4
*)wh
;
1381 * o verify addr2 is a legitimate transmitter
1382 * o lifetime of precursor of addr3 (addr2) is max(init, curr)
1383 * o lifetime of precursor of addr4 (nexthop) is max(init, curr)
1386 /* set lifetime of addr3 (meshDA) to initial value */
1387 rt_meshda
= ieee80211_mesh_rt_find(vap
, qwh
->i_addr3
);
1388 if (rt_meshda
== NULL
) {
1389 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, qwh
->i_addr2
,
1390 "no route to meshDA(%6D)", qwh
->i_addr3
, ":");
1392 * [Optional] any of the following three actions:
1393 * o silently discard [X]
1394 * o trigger a path discovery [ ]
1395 * o inform TA that meshDA is unknown. [ ]
1401 ieee80211_mesh_rt_update(rt_meshda
, ticks_to_msecs(
1402 ms
->ms_ppath
->mpp_inact
));
1404 /* set lifetime of addr4 (meshSA) to initial value */
1405 rt_meshsa
= ieee80211_mesh_rt_find(vap
, qwh
->i_addr4
);
1406 KASSERT(rt_meshsa
!= NULL
, ("no route"));
1407 ieee80211_mesh_rt_update(rt_meshsa
, ticks_to_msecs(
1408 ms
->ms_ppath
->mpp_inact
));
1410 mesh_forward(vap
, m
, mc
);
1411 return (1); /* dont process locally */
1415 * Verifies transmitter, updates lifetime, precursor list and process data
1416 * locally, if data is proxy with AE = 10 it could mean data should go
1417 * on another mesh path or data should be forwarded to the DS.
1419 * > 0 means we have forwarded data and no need to process locally
1420 * == 0 means we want to process locally (and we may have forwarded data
1421 * < 0 means there was an error and data should be discarded
1424 mesh_recv_indiv_data_to_me(struct ieee80211vap
*vap
, struct mbuf
*m
,
1425 struct ieee80211_frame
*wh
, const struct ieee80211_meshcntl
*mc
)
1427 struct ieee80211_qosframe_addr4
*qwh
;
1428 const struct ieee80211_meshcntl_ae10
*mc10
;
1429 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1430 struct ieee80211_mesh_route
*rt
;
1433 /* This is called from the RX path - don't hold this lock */
1434 IEEE80211_TX_UNLOCK_ASSERT(vap
->iv_ic
);
1436 qwh
= (struct ieee80211_qosframe_addr4
*)wh
;
1437 mc10
= (const struct ieee80211_meshcntl_ae10
*)mc
;
1441 * o verify addr2 is a legitimate transmitter
1442 * o lifetime of precursor entry is max(init, curr)
1445 /* set lifetime of addr4 (meshSA) to initial value */
1446 rt
= ieee80211_mesh_rt_find(vap
, qwh
->i_addr4
);
1447 KASSERT(rt
!= NULL
, ("no route"));
1448 ieee80211_mesh_rt_update(rt
, ticks_to_msecs(ms
->ms_ppath
->mpp_inact
));
1451 ae
= mc10
->mc_flags
& IEEE80211_MESH_AE_MASK
;
1452 KASSERT(ae
== IEEE80211_MESH_AE_00
||
1453 ae
== IEEE80211_MESH_AE_10
, ("bad AE %d", ae
));
1454 if (ae
== IEEE80211_MESH_AE_10
) {
1455 if (IEEE80211_ADDR_EQ(mc10
->mc_addr5
, qwh
->i_addr3
)) {
1456 return (0); /* process locally */
1459 rt
= ieee80211_mesh_rt_find(vap
, mc10
->mc_addr5
);
1461 (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) &&
1462 (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
) == 0) {
1464 * Forward on another mesh-path, according to
1465 * amendment as specified in 9.32.4.1
1467 IEEE80211_ADDR_COPY(qwh
->i_addr3
, mc10
->mc_addr5
);
1468 mesh_forward(vap
, m
,
1469 (const struct ieee80211_meshcntl
*)mc10
);
1470 return (1); /* dont process locally */
1473 * All other cases: forward of MSDUs from the MBSS to DS indiv.
1474 * addressed according to 13.11.3.2.
1476 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_OUTPUT
, qwh
->i_addr2
,
1477 "forward frame to DS, SA(%6D) DA(%6D)",
1478 mc10
->mc_addr6
, ":", mc10
->mc_addr5
, ":");
1480 return (0); /* process locally */
1484 * Try to forward the group addressed data on to other mesh STAs, and
1487 * > 0 means we have forwarded data and no need to process locally
1488 * == 0 means we want to process locally (and we may have forwarded data
1489 * < 0 means there was an error and data should be discarded
1492 mesh_recv_group_data(struct ieee80211vap
*vap
, struct mbuf
*m
,
1493 struct ieee80211_frame
*wh
, const struct ieee80211_meshcntl
*mc
)
1495 #define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
1496 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1498 /* This is called from the RX path - don't hold this lock */
1499 IEEE80211_TX_UNLOCK_ASSERT(vap
->iv_ic
);
1501 mesh_forward(vap
, m
, mc
);
1503 if(mc
->mc_ttl
> 0) {
1504 if (mc
->mc_flags
& IEEE80211_MESH_AE_01
) {
1506 * Forward of MSDUs from the MBSS to DS group addressed
1507 * (according to 13.11.3.2)
1508 * This happens by delivering the packet, and a bridge
1509 * will sent it on another port member.
1511 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
&&
1512 ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) {
1513 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
,
1514 MC01(mc
)->mc_addr4
, "%s",
1515 "forward from MBSS to the DS");
1519 return (0); /* process locally */
1524 mesh_input(struct ieee80211_node
*ni
, struct mbuf
*m
,
1525 const struct ieee80211_rx_stats
*rxs
, int rssi
, int nf
)
1527 #define HAS_SEQ(type) ((type & 0x4) == 0)
1528 #define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
1529 struct ieee80211vap
*vap
= ni
->ni_vap
;
1530 struct ieee80211com
*ic
= ni
->ni_ic
;
1531 struct ifnet
*ifp
= vap
->iv_ifp
;
1532 struct ieee80211_frame
*wh
;
1533 const struct ieee80211_meshcntl
*mc
;
1534 int hdrspace
, meshdrlen
, need_tap
, error
;
1535 uint8_t dir
, type
, subtype
, ae
;
1537 const uint8_t *addr
;
1540 KASSERT(ni
!= NULL
, ("null node"));
1541 ni
->ni_inact
= ni
->ni_inact_reload
;
1543 need_tap
= 1; /* mbuf need to be tapped. */
1544 type
= -1; /* undefined */
1546 /* This is called from the RX path - don't hold this lock */
1547 IEEE80211_TX_UNLOCK_ASSERT(ic
);
1549 if (m
->m_pkthdr
.len
< sizeof(struct ieee80211_frame_min
)) {
1550 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1551 ni
->ni_macaddr
, NULL
,
1552 "too short (1): len %u", m
->m_pkthdr
.len
);
1553 vap
->iv_stats
.is_rx_tooshort
++;
1557 * Bit of a cheat here, we use a pointer for a 3-address
1558 * frame format but don't reference fields past outside
1559 * ieee80211_frame_min w/o first validating the data is
1562 wh
= mtod(m
, struct ieee80211_frame
*);
1564 if ((wh
->i_fc
[0] & IEEE80211_FC0_VERSION_MASK
) !=
1565 IEEE80211_FC0_VERSION_0
) {
1566 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1567 ni
->ni_macaddr
, NULL
, "wrong version %x", wh
->i_fc
[0]);
1568 vap
->iv_stats
.is_rx_badversion
++;
1571 dir
= wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
;
1572 type
= wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
;
1573 subtype
= wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
;
1574 if ((ic
->ic_flags
& IEEE80211_F_SCAN
) == 0) {
1575 IEEE80211_RSSI_LPF(ni
->ni_avgrssi
, rssi
);
1577 if (HAS_SEQ(type
)) {
1578 uint8_t tid
= ieee80211_gettid(wh
);
1580 if (IEEE80211_QOS_HAS_SEQ(wh
) &&
1581 TID_TO_WME_AC(tid
) >= WME_AC_VI
)
1582 ic
->ic_wme
.wme_hipri_traffic
++;
1583 if (! ieee80211_check_rxseq(ni
, wh
, wh
->i_addr1
))
1587 #ifdef IEEE80211_DEBUG
1589 * It's easier, but too expensive, to simulate different mesh
1590 * topologies by consulting the ACL policy very early, so do this
1593 * NB: this check is also done upon peering link initiation.
1595 if (vap
->iv_acl
!= NULL
&& !vap
->iv_acl
->iac_check(vap
, wh
)) {
1596 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ACL
,
1597 wh
, NULL
, "%s", "disallowed by ACL");
1598 vap
->iv_stats
.is_rx_acl
++;
1603 case IEEE80211_FC0_TYPE_DATA
:
1604 if (ni
== vap
->iv_bss
)
1606 if (ni
->ni_mlstate
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
1607 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_MESH
,
1608 ni
->ni_macaddr
, NULL
,
1609 "peer link not yet established (%d)",
1611 vap
->iv_stats
.is_mesh_nolink
++;
1614 if (dir
!= IEEE80211_FC1_DIR_FROMDS
&&
1615 dir
!= IEEE80211_FC1_DIR_DSTODS
) {
1616 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1617 wh
, "data", "incorrect dir 0x%x", dir
);
1618 vap
->iv_stats
.is_rx_wrongdir
++;
1622 /* All Mesh data frames are QoS subtype */
1623 if (!HAS_SEQ(type
)) {
1624 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1625 wh
, "data", "incorrect subtype 0x%x", subtype
);
1626 vap
->iv_stats
.is_rx_badsubtype
++;
1631 * Next up, any fragmentation.
1632 * XXX: we defrag before we even try to forward,
1633 * Mesh Control field is not present in sub-sequent
1634 * fragmented frames. This is in contrast to Draft 4.0.
1636 hdrspace
= ieee80211_hdrspace(ic
, wh
);
1637 if (!IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
1638 m
= ieee80211_defrag(ni
, m
, hdrspace
);
1640 /* Fragment dropped or frame not complete yet */
1644 wh
= mtod(m
, struct ieee80211_frame
*); /* NB: after defrag */
1647 * Now we have a complete Mesh Data frame.
1651 * Only fromDStoDS data frames use 4 address qos frames
1652 * as specified in amendment. Otherwise addr4 is located
1653 * in the Mesh Control field and a 3 address qos frame
1656 if (IEEE80211_IS_DSTODS(wh
))
1657 *(uint16_t *)qos
= *(uint16_t *)
1658 ((struct ieee80211_qosframe_addr4
*)wh
)->i_qos
;
1660 *(uint16_t *)qos
= *(uint16_t *)
1661 ((struct ieee80211_qosframe
*)wh
)->i_qos
;
1664 * NB: The mesh STA sets the Mesh Control Present
1665 * subfield to 1 in the Mesh Data frame containing
1666 * an unfragmented MSDU, an A-MSDU, or the first
1667 * fragment of an MSDU.
1668 * After defrag it should always be present.
1670 if (!(qos
[1] & IEEE80211_QOS_MC
)) {
1671 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_MESH
,
1672 ni
->ni_macaddr
, NULL
,
1673 "%s", "Mesh control field not present");
1674 vap
->iv_stats
.is_rx_elem_missing
++; /* XXX: kinda */
1678 /* pull up enough to get to the mesh control */
1679 if (m
->m_len
< hdrspace
+ sizeof(struct ieee80211_meshcntl
) &&
1680 (m
= m_pullup(m
, hdrspace
+
1681 sizeof(struct ieee80211_meshcntl
))) == NULL
) {
1682 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1683 ni
->ni_macaddr
, NULL
,
1684 "data too short: expecting %u", hdrspace
);
1685 vap
->iv_stats
.is_rx_tooshort
++;
1689 * Now calculate the full extent of the headers. Note
1690 * mesh_decap will pull up anything we didn't get
1691 * above when it strips the 802.11 headers.
1693 mc
= (const struct ieee80211_meshcntl
*)
1694 (mtod(m
, const uint8_t *) + hdrspace
);
1695 ae
= mc
->mc_flags
& IEEE80211_MESH_AE_MASK
;
1696 meshdrlen
= sizeof(struct ieee80211_meshcntl
) +
1697 ae
* IEEE80211_ADDR_LEN
;
1698 hdrspace
+= meshdrlen
;
1700 /* pull complete hdrspace = ieee80211_hdrspace + meshcontrol */
1701 if ((meshdrlen
> sizeof(struct ieee80211_meshcntl
)) &&
1702 (m
->m_len
< hdrspace
) &&
1703 ((m
= m_pullup(m
, hdrspace
)) == NULL
)) {
1704 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1705 ni
->ni_macaddr
, NULL
,
1706 "data too short: expecting %u", hdrspace
);
1707 vap
->iv_stats
.is_rx_tooshort
++;
1710 /* XXX: are we sure there is no reallocating after m_pullup? */
1712 seq
= le32dec(mc
->mc_seq
);
1713 if (IEEE80211_IS_MULTICAST(wh
->i_addr1
))
1715 else if (ae
== IEEE80211_MESH_AE_01
)
1716 addr
= MC01(mc
)->mc_addr4
;
1718 addr
= ((struct ieee80211_qosframe_addr4
*)wh
)->i_addr4
;
1719 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, addr
)) {
1720 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_INPUT
,
1721 addr
, "data", "%s", "not to me");
1722 vap
->iv_stats
.is_rx_wrongbss
++; /* XXX kinda */
1725 if (mesh_checkpseq(vap
, addr
, seq
) != 0) {
1726 vap
->iv_stats
.is_rx_dup
++;
1730 /* This code "routes" the frame to the right control path */
1731 if (!IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
1732 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, wh
->i_addr3
))
1734 mesh_recv_indiv_data_to_me(vap
, m
, wh
, mc
);
1735 else if (IEEE80211_IS_MULTICAST(wh
->i_addr3
))
1736 error
= mesh_recv_group_data(vap
, m
, wh
, mc
);
1738 error
= mesh_recv_indiv_data_to_fwrd(vap
, m
,
1741 error
= mesh_recv_group_data(vap
, m
, wh
, mc
);
1747 if (ieee80211_radiotap_active_vap(vap
))
1748 ieee80211_radiotap_rx(vap
, m
);
1752 * Finally, strip the 802.11 header.
1754 m
= mesh_decap(vap
, m
, hdrspace
, meshdrlen
);
1756 /* XXX mask bit to check for both */
1757 /* don't count Null data frames as errors */
1758 if (subtype
== IEEE80211_FC0_SUBTYPE_NODATA
||
1759 subtype
== IEEE80211_FC0_SUBTYPE_QOS_NULL
)
1761 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_INPUT
,
1762 ni
->ni_macaddr
, "data", "%s", "decap error");
1763 vap
->iv_stats
.is_rx_decap
++;
1764 IEEE80211_NODE_STAT(ni
, rx_decap
);
1767 if (qos
[0] & IEEE80211_QOS_AMSDU
) {
1768 m
= ieee80211_decap_amsdu(ni
, m
);
1770 return IEEE80211_FC0_TYPE_DATA
;
1772 ieee80211_deliver_data(vap
, ni
, m
);
1774 case IEEE80211_FC0_TYPE_MGT
:
1775 vap
->iv_stats
.is_rx_mgmt
++;
1776 IEEE80211_NODE_STAT(ni
, rx_mgmt
);
1777 if (dir
!= IEEE80211_FC1_DIR_NODS
) {
1778 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1779 wh
, "mgt", "incorrect dir 0x%x", dir
);
1780 vap
->iv_stats
.is_rx_wrongdir
++;
1783 if (m
->m_pkthdr
.len
< sizeof(struct ieee80211_frame
)) {
1784 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1785 ni
->ni_macaddr
, "mgt", "too short: len %u",
1787 vap
->iv_stats
.is_rx_tooshort
++;
1790 #ifdef IEEE80211_DEBUG
1791 if ((ieee80211_msg_debug(vap
) &&
1792 (vap
->iv_ic
->ic_flags
& IEEE80211_F_SCAN
)) ||
1793 ieee80211_msg_dumppkts(vap
)) {
1794 if_printf(ifp
, "received %s from %s rssi %d\n",
1795 ieee80211_mgt_subtype_name(subtype
),
1796 ether_sprintf(wh
->i_addr2
), rssi
);
1799 if (wh
->i_fc
[1] & IEEE80211_FC1_PROTECTED
) {
1800 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1801 wh
, NULL
, "%s", "WEP set but not permitted");
1802 vap
->iv_stats
.is_rx_mgtdiscard
++; /* XXX */
1805 vap
->iv_recv_mgmt(ni
, m
, subtype
, rxs
, rssi
, nf
);
1807 case IEEE80211_FC0_TYPE_CTL
:
1808 vap
->iv_stats
.is_rx_ctl
++;
1809 IEEE80211_NODE_STAT(ni
, rx_ctrl
);
1812 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
1813 wh
, "bad", "frame type 0x%x", type
);
1814 /* should not come here */
1818 if_inc_counter(ifp
, IFCOUNTER_IERRORS
, 1);
1821 if (need_tap
&& ieee80211_radiotap_active_vap(vap
))
1822 ieee80211_radiotap_rx(vap
, m
);
1831 mesh_recv_mgmt(struct ieee80211_node
*ni
, struct mbuf
*m0
, int subtype
,
1832 const struct ieee80211_rx_stats
*rxs
, int rssi
, int nf
)
1834 struct ieee80211vap
*vap
= ni
->ni_vap
;
1835 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1836 struct ieee80211com
*ic
= ni
->ni_ic
;
1837 struct ieee80211_channel
*rxchan
= ic
->ic_curchan
;
1838 struct ieee80211_frame
*wh
;
1839 struct ieee80211_mesh_route
*rt
;
1840 uint8_t *frm
, *efrm
;
1842 wh
= mtod(m0
, struct ieee80211_frame
*);
1843 frm
= (uint8_t *)&wh
[1];
1844 efrm
= mtod(m0
, uint8_t *) + m0
->m_len
;
1846 case IEEE80211_FC0_SUBTYPE_PROBE_RESP
:
1847 case IEEE80211_FC0_SUBTYPE_BEACON
:
1849 struct ieee80211_scanparams scan
;
1850 struct ieee80211_channel
*c
;
1852 * We process beacon/probe response
1853 * frames to discover neighbors.
1856 c
= ieee80211_lookup_channel_rxstatus(vap
, rxs
);
1860 if (ieee80211_parse_beacon(ni
, m0
, rxchan
, &scan
) != 0)
1863 * Count frame now that we know it's to be processed.
1865 if (subtype
== IEEE80211_FC0_SUBTYPE_BEACON
) {
1866 vap
->iv_stats
.is_rx_beacon
++; /* XXX remove */
1867 IEEE80211_NODE_STAT(ni
, rx_beacons
);
1869 IEEE80211_NODE_STAT(ni
, rx_proberesp
);
1871 * If scanning, just pass information to the scan module.
1873 if (ic
->ic_flags
& IEEE80211_F_SCAN
) {
1874 if (ic
->ic_flags_ext
& IEEE80211_FEXT_PROBECHAN
) {
1876 * Actively scanning a channel marked passive;
1877 * send a probe request now that we know there
1878 * is 802.11 traffic present.
1880 * XXX check if the beacon we recv'd gives
1881 * us what we need and suppress the probe req
1883 ieee80211_probe_curchan(vap
, 1);
1884 ic
->ic_flags_ext
&= ~IEEE80211_FEXT_PROBECHAN
;
1886 ieee80211_add_scan(vap
, rxchan
, &scan
, wh
,
1891 /* The rest of this code assumes we are running */
1892 if (vap
->iv_state
!= IEEE80211_S_RUN
)
1895 * Ignore non-mesh STAs.
1898 (IEEE80211_CAPINFO_ESS
|IEEE80211_CAPINFO_IBSS
)) ||
1899 scan
.meshid
== NULL
|| scan
.meshconf
== NULL
) {
1900 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1901 wh
, "beacon", "%s", "not a mesh sta");
1902 vap
->iv_stats
.is_mesh_wrongmesh
++;
1906 * Ignore STAs for other mesh networks.
1908 if (memcmp(scan
.meshid
+2, ms
->ms_id
, ms
->ms_idlen
) != 0 ||
1909 mesh_verify_meshconf(vap
, scan
.meshconf
)) {
1910 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1911 wh
, "beacon", "%s", "not for our mesh");
1912 vap
->iv_stats
.is_mesh_wrongmesh
++;
1916 * Peer only based on the current ACL policy.
1918 if (vap
->iv_acl
!= NULL
&& !vap
->iv_acl
->iac_check(vap
, wh
)) {
1919 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ACL
,
1920 wh
, NULL
, "%s", "disallowed by ACL");
1921 vap
->iv_stats
.is_rx_acl
++;
1925 * Do neighbor discovery.
1927 if (!IEEE80211_ADDR_EQ(wh
->i_addr2
, ni
->ni_macaddr
)) {
1929 * Create a new entry in the neighbor table.
1931 ni
= ieee80211_add_neighbor(vap
, wh
, &scan
);
1934 * Automatically peer with discovered nodes if possible.
1936 if (ni
!= vap
->iv_bss
&&
1937 (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
)) {
1938 switch (ni
->ni_mlstate
) {
1939 case IEEE80211_NODE_MESH_IDLE
:
1943 /* Wait for backoff callout to reset counter */
1944 if (ni
->ni_mlhcnt
>= ieee80211_mesh_maxholding
)
1947 ni
->ni_mlpid
= mesh_generateid(vap
);
1948 if (ni
->ni_mlpid
== 0)
1950 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENSNT
);
1951 args
[0] = ni
->ni_mlpid
;
1952 ieee80211_send_action(ni
,
1953 IEEE80211_ACTION_CAT_SELF_PROT
,
1954 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
1956 mesh_peer_timeout_setup(ni
);
1959 case IEEE80211_NODE_MESH_ESTABLISHED
:
1962 * Valid beacon from a peer mesh STA
1965 rt
= ieee80211_mesh_rt_find(vap
, wh
->i_addr2
);
1967 ieee80211_mesh_rt_update(rt
,
1969 ms
->ms_ppath
->mpp_inact
));
1979 case IEEE80211_FC0_SUBTYPE_PROBE_REQ
:
1981 uint8_t *ssid
, *meshid
, *rates
, *xrates
;
1983 if (vap
->iv_state
!= IEEE80211_S_RUN
) {
1984 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1985 wh
, NULL
, "wrong state %s",
1986 ieee80211_state_name
[vap
->iv_state
]);
1987 vap
->iv_stats
.is_rx_mgtdiscard
++;
1990 if (IEEE80211_IS_MULTICAST(wh
->i_addr2
)) {
1991 /* frame must be directed */
1992 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1993 wh
, NULL
, "%s", "not unicast");
1994 vap
->iv_stats
.is_rx_mgtdiscard
++; /* XXX stat */
1998 * prreq frame format
2000 * [tlv] supported rates
2001 * [tlv] extended supported rates
2004 ssid
= meshid
= rates
= xrates
= NULL
;
2005 while (efrm
- frm
> 1) {
2006 IEEE80211_VERIFY_LENGTH(efrm
- frm
, frm
[1] + 2, return);
2008 case IEEE80211_ELEMID_SSID
:
2011 case IEEE80211_ELEMID_RATES
:
2014 case IEEE80211_ELEMID_XRATES
:
2017 case IEEE80211_ELEMID_MESHID
:
2023 IEEE80211_VERIFY_ELEMENT(ssid
, IEEE80211_NWID_LEN
, return);
2024 IEEE80211_VERIFY_ELEMENT(rates
, IEEE80211_RATE_MAXSIZE
, return);
2026 IEEE80211_VERIFY_ELEMENT(xrates
,
2027 IEEE80211_RATE_MAXSIZE
- rates
[1], return);
2028 if (meshid
!= NULL
) {
2029 IEEE80211_VERIFY_ELEMENT(meshid
,
2030 IEEE80211_MESHID_LEN
, return);
2031 /* NB: meshid, not ssid */
2032 IEEE80211_VERIFY_SSID(vap
->iv_bss
, meshid
, return);
2035 /* XXX find a better class or define it's own */
2036 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_INPUT
, wh
->i_addr2
,
2037 "%s", "recv probe req");
2039 * Some legacy 11b clients cannot hack a complete
2040 * probe response frame. When the request includes
2041 * only a bare-bones rate set, communicate this to
2042 * the transmit side.
2044 ieee80211_send_proberesp(vap
, wh
->i_addr2
, 0);
2048 case IEEE80211_FC0_SUBTYPE_ACTION
:
2049 case IEEE80211_FC0_SUBTYPE_ACTION_NOACK
:
2050 if (ni
== vap
->iv_bss
) {
2051 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
2052 wh
, NULL
, "%s", "unknown node");
2053 vap
->iv_stats
.is_rx_mgtdiscard
++;
2054 } else if (!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, wh
->i_addr1
) &&
2055 !IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
2056 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
2057 wh
, NULL
, "%s", "not for us");
2058 vap
->iv_stats
.is_rx_mgtdiscard
++;
2059 } else if (vap
->iv_state
!= IEEE80211_S_RUN
) {
2060 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
2061 wh
, NULL
, "wrong state %s",
2062 ieee80211_state_name
[vap
->iv_state
]);
2063 vap
->iv_stats
.is_rx_mgtdiscard
++;
2065 if (ieee80211_parse_action(ni
, m0
) == 0)
2066 (void)ic
->ic_recv_action(ni
, wh
, frm
, efrm
);
2070 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ
:
2071 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP
:
2072 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ
:
2073 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP
:
2074 case IEEE80211_FC0_SUBTYPE_TIMING_ADV
:
2075 case IEEE80211_FC0_SUBTYPE_ATIM
:
2076 case IEEE80211_FC0_SUBTYPE_DISASSOC
:
2077 case IEEE80211_FC0_SUBTYPE_AUTH
:
2078 case IEEE80211_FC0_SUBTYPE_DEAUTH
:
2079 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
2080 wh
, NULL
, "%s", "not handled");
2081 vap
->iv_stats
.is_rx_mgtdiscard
++;
2085 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
2086 wh
, "mgt", "subtype 0x%x not handled", subtype
);
2087 vap
->iv_stats
.is_rx_badsubtype
++;
2093 mesh_recv_ctl(struct ieee80211_node
*ni
, struct mbuf
*m
, int subtype
)
2097 case IEEE80211_FC0_SUBTYPE_BAR
:
2098 ieee80211_recv_bar(ni
, m
);
2104 * Parse meshpeering action ie's for MPM frames
2106 static const struct ieee80211_meshpeer_ie
*
2107 mesh_parse_meshpeering_action(struct ieee80211_node
*ni
,
2108 const struct ieee80211_frame
*wh
, /* XXX for VERIFY_LENGTH */
2109 const uint8_t *frm
, const uint8_t *efrm
,
2110 struct ieee80211_meshpeer_ie
*mp
, uint8_t subtype
)
2112 struct ieee80211vap
*vap
= ni
->ni_vap
;
2113 const struct ieee80211_meshpeer_ie
*mpie
;
2115 const uint8_t *meshid
, *meshconf
;
2116 uint8_t sendclose
= 0; /* 1 = MPM frame rejected, close will be sent */
2118 meshid
= meshconf
= NULL
;
2119 while (efrm
- frm
> 1) {
2120 IEEE80211_VERIFY_LENGTH(efrm
- frm
, frm
[1] + 2, return NULL
);
2122 case IEEE80211_ELEMID_MESHID
:
2125 case IEEE80211_ELEMID_MESHCONF
:
2128 case IEEE80211_ELEMID_MESHPEER
:
2129 mpie
= (const struct ieee80211_meshpeer_ie
*) frm
;
2130 memset(mp
, 0, sizeof(*mp
));
2131 mp
->peer_len
= mpie
->peer_len
;
2132 mp
->peer_proto
= le16dec(&mpie
->peer_proto
);
2133 mp
->peer_llinkid
= le16dec(&mpie
->peer_llinkid
);
2135 case IEEE80211_ACTION_MESHPEERING_CONFIRM
:
2137 le16dec(&mpie
->peer_linkid
);
2139 case IEEE80211_ACTION_MESHPEERING_CLOSE
:
2140 /* NB: peer link ID is optional */
2141 if (mpie
->peer_len
==
2142 (IEEE80211_MPM_BASE_SZ
+ 2)) {
2143 mp
->peer_linkid
= 0;
2145 le16dec(&mpie
->peer_linkid
);
2148 le16dec(&mpie
->peer_linkid
);
2150 le16dec(&mpie
->peer_rcode
);
2160 * Verify the contents of the frame.
2161 * If it fails validation, close the peer link.
2163 if (mesh_verify_meshpeer(vap
, subtype
, (const uint8_t *)mp
)) {
2165 IEEE80211_DISCARD(vap
,
2166 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2167 wh
, NULL
, "%s", "MPM validation failed");
2170 /* If meshid is not the same reject any frames type. */
2171 if (sendclose
== 0 && mesh_verify_meshid(vap
, meshid
)) {
2173 IEEE80211_DISCARD(vap
,
2174 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2175 wh
, NULL
, "%s", "not for our mesh");
2176 if (subtype
== IEEE80211_ACTION_MESHPEERING_CLOSE
) {
2178 * Standard not clear about this, if we dont ignore
2179 * there will be an endless loop between nodes sending
2180 * CLOSE frames between each other with wrong meshid.
2181 * Discard and timers will bring FSM to IDLE state.
2188 * Close frames are accepted if meshid is the same.
2189 * Verify the other two types.
2191 if (sendclose
== 0 && subtype
!= IEEE80211_ACTION_MESHPEERING_CLOSE
&&
2192 mesh_verify_meshconf(vap
, meshconf
)) {
2194 IEEE80211_DISCARD(vap
,
2195 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2196 wh
, NULL
, "%s", "configuration missmatch");
2200 vap
->iv_stats
.is_rx_mgtdiscard
++;
2201 switch (ni
->ni_mlstate
) {
2202 case IEEE80211_NODE_MESH_IDLE
:
2203 case IEEE80211_NODE_MESH_ESTABLISHED
:
2204 case IEEE80211_NODE_MESH_HOLDING
:
2207 case IEEE80211_NODE_MESH_OPENSNT
:
2208 case IEEE80211_NODE_MESH_OPENRCV
:
2209 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2210 args
[0] = ni
->ni_mlpid
;
2211 args
[1] = ni
->ni_mllid
;
2212 /* Reason codes for rejection */
2214 case IEEE80211_ACTION_MESHPEERING_OPEN
:
2215 args
[2] = IEEE80211_REASON_MESH_CPVIOLATION
;
2217 case IEEE80211_ACTION_MESHPEERING_CONFIRM
:
2218 args
[2] = IEEE80211_REASON_MESH_INCONS_PARAMS
;
2221 ieee80211_send_action(ni
,
2222 IEEE80211_ACTION_CAT_SELF_PROT
,
2223 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2225 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2226 mesh_peer_timeout_setup(ni
);
2232 return (const struct ieee80211_meshpeer_ie
*) mp
;
2236 mesh_recv_action_meshpeering_open(struct ieee80211_node
*ni
,
2237 const struct ieee80211_frame
*wh
,
2238 const uint8_t *frm
, const uint8_t *efrm
)
2240 struct ieee80211vap
*vap
= ni
->ni_vap
;
2241 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2242 struct ieee80211_meshpeer_ie ie
;
2243 const struct ieee80211_meshpeer_ie
*meshpeer
;
2246 /* +2+2 for action + code + capabilites */
2247 meshpeer
= mesh_parse_meshpeering_action(ni
, wh
, frm
+2+2, efrm
, &ie
,
2248 IEEE80211_ACTION_MESHPEERING_OPEN
);
2249 if (meshpeer
== NULL
) {
2254 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2255 "recv PEER OPEN, lid 0x%x", meshpeer
->peer_llinkid
);
2257 switch (ni
->ni_mlstate
) {
2258 case IEEE80211_NODE_MESH_IDLE
:
2259 /* Reject open request if reached our maximum neighbor count */
2260 if (ms
->ms_neighbors
>= IEEE80211_MESH_MAX_NEIGHBORS
) {
2261 args
[0] = meshpeer
->peer_llinkid
;
2263 args
[2] = IEEE80211_REASON_MESH_MAX_PEERS
;
2264 ieee80211_send_action(ni
,
2265 IEEE80211_ACTION_CAT_SELF_PROT
,
2266 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2268 /* stay in IDLE state */
2271 /* Open frame accepted */
2272 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENRCV
);
2273 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
2274 ni
->ni_mlpid
= mesh_generateid(vap
);
2275 if (ni
->ni_mlpid
== 0)
2277 args
[0] = ni
->ni_mlpid
;
2278 /* Announce we're open too... */
2279 ieee80211_send_action(ni
,
2280 IEEE80211_ACTION_CAT_SELF_PROT
,
2281 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
2282 /* ...and confirm the link. */
2283 args
[0] = ni
->ni_mlpid
;
2284 args
[1] = ni
->ni_mllid
;
2285 ieee80211_send_action(ni
,
2286 IEEE80211_ACTION_CAT_SELF_PROT
,
2287 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2289 mesh_peer_timeout_setup(ni
);
2291 case IEEE80211_NODE_MESH_OPENRCV
:
2293 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
2294 args
[0] = ni
->ni_mllid
;
2295 args
[1] = ni
->ni_mlpid
;
2296 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2297 ieee80211_send_action(ni
,
2298 IEEE80211_ACTION_CAT_SELF_PROT
,
2299 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2301 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2302 mesh_peer_timeout_setup(ni
);
2305 /* Duplicate open, confirm again. */
2306 args
[0] = ni
->ni_mlpid
;
2307 args
[1] = ni
->ni_mllid
;
2308 ieee80211_send_action(ni
,
2309 IEEE80211_ACTION_CAT_SELF_PROT
,
2310 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2313 case IEEE80211_NODE_MESH_OPENSNT
:
2314 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
2315 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENRCV
);
2316 args
[0] = ni
->ni_mlpid
;
2317 args
[1] = ni
->ni_mllid
;
2318 ieee80211_send_action(ni
,
2319 IEEE80211_ACTION_CAT_SELF_PROT
,
2320 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2322 /* NB: don't setup/clear any timeout */
2324 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2325 if (ni
->ni_mlpid
!= meshpeer
->peer_linkid
||
2326 ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
2327 args
[0] = ni
->ni_mlpid
;
2328 args
[1] = ni
->ni_mllid
;
2329 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2330 ieee80211_send_action(ni
,
2331 IEEE80211_ACTION_CAT_SELF_PROT
,
2332 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2335 IEEE80211_NODE_MESH_HOLDING
);
2336 mesh_peer_timeout_setup(ni
);
2339 mesh_linkchange(ni
, IEEE80211_NODE_MESH_ESTABLISHED
);
2340 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
2341 args
[0] = ni
->ni_mlpid
;
2342 args
[1] = ni
->ni_mllid
;
2343 ieee80211_send_action(ni
,
2344 IEEE80211_ACTION_CAT_SELF_PROT
,
2345 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2347 mesh_peer_timeout_stop(ni
);
2349 case IEEE80211_NODE_MESH_ESTABLISHED
:
2350 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
2351 args
[0] = ni
->ni_mllid
;
2352 args
[1] = ni
->ni_mlpid
;
2353 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2354 ieee80211_send_action(ni
,
2355 IEEE80211_ACTION_CAT_SELF_PROT
,
2356 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2358 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2359 mesh_peer_timeout_setup(ni
);
2362 args
[0] = ni
->ni_mlpid
;
2363 args
[1] = ni
->ni_mllid
;
2364 ieee80211_send_action(ni
,
2365 IEEE80211_ACTION_CAT_SELF_PROT
,
2366 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2369 case IEEE80211_NODE_MESH_HOLDING
:
2370 args
[0] = ni
->ni_mlpid
;
2371 args
[1] = meshpeer
->peer_llinkid
;
2372 /* Standard not clear about what the reaason code should be */
2373 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2374 ieee80211_send_action(ni
,
2375 IEEE80211_ACTION_CAT_SELF_PROT
,
2376 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2384 mesh_recv_action_meshpeering_confirm(struct ieee80211_node
*ni
,
2385 const struct ieee80211_frame
*wh
,
2386 const uint8_t *frm
, const uint8_t *efrm
)
2388 struct ieee80211vap
*vap
= ni
->ni_vap
;
2389 struct ieee80211_meshpeer_ie ie
;
2390 const struct ieee80211_meshpeer_ie
*meshpeer
;
2393 /* +2+2+2+2 for action + code + capabilites + status code + AID */
2394 meshpeer
= mesh_parse_meshpeering_action(ni
, wh
, frm
+2+2+2+2, efrm
, &ie
,
2395 IEEE80211_ACTION_MESHPEERING_CONFIRM
);
2396 if (meshpeer
== NULL
) {
2400 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2401 "recv PEER CONFIRM, local id 0x%x, peer id 0x%x",
2402 meshpeer
->peer_llinkid
, meshpeer
->peer_linkid
);
2404 switch (ni
->ni_mlstate
) {
2405 case IEEE80211_NODE_MESH_OPENRCV
:
2406 mesh_linkchange(ni
, IEEE80211_NODE_MESH_ESTABLISHED
);
2407 mesh_peer_timeout_stop(ni
);
2409 case IEEE80211_NODE_MESH_OPENSNT
:
2410 mesh_linkchange(ni
, IEEE80211_NODE_MESH_CONFIRMRCV
);
2411 mesh_peer_timeout_setup(ni
);
2413 case IEEE80211_NODE_MESH_HOLDING
:
2414 args
[0] = ni
->ni_mlpid
;
2415 args
[1] = meshpeer
->peer_llinkid
;
2416 /* Standard not clear about what the reaason code should be */
2417 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2418 ieee80211_send_action(ni
,
2419 IEEE80211_ACTION_CAT_SELF_PROT
,
2420 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2423 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2424 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
2425 args
[0] = ni
->ni_mlpid
;
2426 args
[1] = ni
->ni_mllid
;
2427 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
2428 ieee80211_send_action(ni
,
2429 IEEE80211_ACTION_CAT_SELF_PROT
,
2430 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2432 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2433 mesh_peer_timeout_setup(ni
);
2437 IEEE80211_DISCARD(vap
,
2438 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2439 wh
, NULL
, "received confirm in invalid state %d",
2441 vap
->iv_stats
.is_rx_mgtdiscard
++;
2448 mesh_recv_action_meshpeering_close(struct ieee80211_node
*ni
,
2449 const struct ieee80211_frame
*wh
,
2450 const uint8_t *frm
, const uint8_t *efrm
)
2452 struct ieee80211_meshpeer_ie ie
;
2453 const struct ieee80211_meshpeer_ie
*meshpeer
;
2456 /* +2 for action + code */
2457 meshpeer
= mesh_parse_meshpeering_action(ni
, wh
, frm
+2, efrm
, &ie
,
2458 IEEE80211_ACTION_MESHPEERING_CLOSE
);
2459 if (meshpeer
== NULL
) {
2464 * XXX: check reason code, for example we could receive
2465 * IEEE80211_REASON_MESH_MAX_PEERS then we should not attempt
2469 IEEE80211_NOTE(ni
->ni_vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2470 ni
, "%s", "recv PEER CLOSE");
2472 switch (ni
->ni_mlstate
) {
2473 case IEEE80211_NODE_MESH_IDLE
:
2476 case IEEE80211_NODE_MESH_OPENRCV
:
2477 case IEEE80211_NODE_MESH_OPENSNT
:
2478 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2479 case IEEE80211_NODE_MESH_ESTABLISHED
:
2480 args
[0] = ni
->ni_mlpid
;
2481 args
[1] = ni
->ni_mllid
;
2482 args
[2] = IEEE80211_REASON_MESH_CLOSE_RCVD
;
2483 ieee80211_send_action(ni
,
2484 IEEE80211_ACTION_CAT_SELF_PROT
,
2485 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2487 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2488 mesh_peer_timeout_setup(ni
);
2490 case IEEE80211_NODE_MESH_HOLDING
:
2491 mesh_linkchange(ni
, IEEE80211_NODE_MESH_IDLE
);
2492 mesh_peer_timeout_stop(ni
);
2499 * Link Metric handling.
2502 mesh_recv_action_meshlmetric(struct ieee80211_node
*ni
,
2503 const struct ieee80211_frame
*wh
,
2504 const uint8_t *frm
, const uint8_t *efrm
)
2506 const struct ieee80211_meshlmetric_ie
*ie
=
2507 (const struct ieee80211_meshlmetric_ie
*)
2508 (frm
+2); /* action + code */
2509 struct ieee80211_meshlmetric_ie lm_rep
;
2511 if (ie
->lm_flags
& IEEE80211_MESH_LMETRIC_FLAGS_REQ
) {
2512 lm_rep
.lm_flags
= 0;
2513 lm_rep
.lm_metric
= mesh_airtime_calc(ni
);
2514 ieee80211_send_action(ni
,
2515 IEEE80211_ACTION_CAT_MESH
,
2516 IEEE80211_ACTION_MESH_LMETRIC
,
2519 /* XXX: else do nothing for now */
2524 * Parse meshgate action ie's for GANN frames.
2525 * Returns -1 if parsing fails, otherwise 0.
2528 mesh_parse_meshgate_action(struct ieee80211_node
*ni
,
2529 const struct ieee80211_frame
*wh
, /* XXX for VERIFY_LENGTH */
2530 struct ieee80211_meshgann_ie
*ie
, const uint8_t *frm
, const uint8_t *efrm
)
2532 struct ieee80211vap
*vap
= ni
->ni_vap
;
2533 const struct ieee80211_meshgann_ie
*gannie
;
2535 while (efrm
- frm
> 1) {
2536 IEEE80211_VERIFY_LENGTH(efrm
- frm
, frm
[1] + 2, return -1);
2538 case IEEE80211_ELEMID_MESHGANN
:
2539 gannie
= (const struct ieee80211_meshgann_ie
*) frm
;
2540 memset(ie
, 0, sizeof(*ie
));
2541 ie
->gann_ie
= gannie
->gann_ie
;
2542 ie
->gann_len
= gannie
->gann_len
;
2543 ie
->gann_flags
= gannie
->gann_flags
;
2544 ie
->gann_hopcount
= gannie
->gann_hopcount
;
2545 ie
->gann_ttl
= gannie
->gann_ttl
;
2546 IEEE80211_ADDR_COPY(ie
->gann_addr
, gannie
->gann_addr
);
2547 ie
->gann_seq
= le32dec(&gannie
->gann_seq
);
2548 ie
->gann_interval
= le16dec(&gannie
->gann_interval
);
2558 * Mesh Gate Announcement handling.
2561 mesh_recv_action_meshgate(struct ieee80211_node
*ni
,
2562 const struct ieee80211_frame
*wh
,
2563 const uint8_t *frm
, const uint8_t *efrm
)
2565 struct ieee80211vap
*vap
= ni
->ni_vap
;
2566 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2567 struct ieee80211_mesh_gate_route
*gr
, *next
;
2568 struct ieee80211_mesh_route
*rt_gate
;
2569 struct ieee80211_meshgann_ie pgann
;
2570 struct ieee80211_meshgann_ie ie
;
2573 /* +2 for action + code */
2574 if (mesh_parse_meshgate_action(ni
, wh
, &ie
, frm
+2, efrm
) != 0) {
2575 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_MESH
,
2576 ni
->ni_macaddr
, NULL
, "%s",
2577 "GANN parsing failed");
2578 vap
->iv_stats
.is_rx_mgtdiscard
++;
2582 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, ie
.gann_addr
))
2585 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, ni
->ni_macaddr
,
2586 "received GANN, meshgate: %6D (seq %u)", ie
.gann_addr
, ":",
2592 TAILQ_FOREACH_SAFE(gr
, &ms
->ms_known_gates
, gr_next
, next
) {
2593 if (!IEEE80211_ADDR_EQ(gr
->gr_addr
, ie
.gann_addr
))
2595 if (ie
.gann_seq
<= gr
->gr_lastseq
) {
2596 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_MESH
,
2597 ni
->ni_macaddr
, NULL
,
2598 "GANN old seqno %u <= %u",
2599 ie
.gann_seq
, gr
->gr_lastseq
);
2603 /* corresponding mesh gate found & GANN accepted */
2609 /* this GANN is from a new mesh Gate add it to known table. */
2610 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, ie
.gann_addr
,
2611 "stored new GANN information, seq %u.", ie
.gann_seq
);
2612 gr
= IEEE80211_MALLOC(ALIGN(sizeof(struct ieee80211_mesh_gate_route
)),
2614 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
2615 IEEE80211_ADDR_COPY(gr
->gr_addr
, ie
.gann_addr
);
2616 TAILQ_INSERT_TAIL(&ms
->ms_known_gates
, gr
, gr_next
);
2618 gr
->gr_lastseq
= ie
.gann_seq
;
2620 /* check if we have a path to this gate */
2621 rt_gate
= mesh_rt_find_locked(ms
, gr
->gr_addr
);
2622 if (rt_gate
!= NULL
&&
2623 rt_gate
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) {
2624 gr
->gr_route
= rt_gate
;
2625 rt_gate
->rt_flags
|= IEEE80211_MESHRT_FLAGS_GATE
;
2630 /* popagate only if decremented ttl >= 1 && forwarding is enabled */
2631 if ((ie
.gann_ttl
- 1) < 1 && !(ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
))
2633 pgann
.gann_flags
= ie
.gann_flags
; /* Reserved */
2634 pgann
.gann_hopcount
= ie
.gann_hopcount
+ 1;
2635 pgann
.gann_ttl
= ie
.gann_ttl
- 1;
2636 IEEE80211_ADDR_COPY(pgann
.gann_addr
, ie
.gann_addr
);
2637 pgann
.gann_seq
= ie
.gann_seq
;
2638 pgann
.gann_interval
= ie
.gann_interval
;
2640 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, ie
.gann_addr
,
2641 "%s", "propagate GANN");
2643 ieee80211_send_action(vap
->iv_bss
, IEEE80211_ACTION_CAT_MESH
,
2644 IEEE80211_ACTION_MESH_GANN
, &pgann
);
2650 mesh_send_action(struct ieee80211_node
*ni
,
2651 const uint8_t sa
[IEEE80211_ADDR_LEN
],
2652 const uint8_t da
[IEEE80211_ADDR_LEN
],
2655 struct ieee80211vap
*vap
= ni
->ni_vap
;
2656 struct ieee80211com
*ic
= ni
->ni_ic
;
2657 struct ieee80211_bpf_params params
;
2660 KASSERT(ni
!= NULL
, ("null node"));
2662 if (vap
->iv_state
== IEEE80211_S_CAC
) {
2663 IEEE80211_NOTE(vap
, IEEE80211_MSG_OUTPUT
, ni
,
2664 "block %s frame in CAC state", "Mesh action");
2665 vap
->iv_stats
.is_tx_badstate
++;
2666 ieee80211_free_node(ni
);
2668 return EIO
; /* XXX */
2671 M_PREPEND(m
, sizeof(struct ieee80211_frame
), M_NOWAIT
);
2673 ieee80211_free_node(ni
);
2677 IEEE80211_TX_LOCK(ic
);
2678 ieee80211_send_setup(ni
, m
,
2679 IEEE80211_FC0_TYPE_MGT
| IEEE80211_FC0_SUBTYPE_ACTION
,
2680 IEEE80211_NONQOS_TID
, sa
, da
, sa
);
2681 m
->m_flags
|= M_ENCAP
; /* mark encapsulated */
2683 memset(¶ms
, 0, sizeof(params
));
2684 params
.ibp_pri
= WME_AC_VO
;
2685 params
.ibp_rate0
= ni
->ni_txparms
->mgmtrate
;
2686 if (IEEE80211_IS_MULTICAST(da
))
2687 params
.ibp_try0
= 1;
2689 params
.ibp_try0
= ni
->ni_txparms
->maxretry
;
2690 params
.ibp_power
= ni
->ni_txpower
;
2692 IEEE80211_NODE_STAT(ni
, tx_mgmt
);
2694 ret
= ieee80211_raw_output(vap
, ni
, m
, ¶ms
);
2695 IEEE80211_TX_UNLOCK(ic
);
2699 #define ADDSHORT(frm, v) do { \
2700 frm[0] = (v) & 0xff; \
2701 frm[1] = (v) >> 8; \
2704 #define ADDWORD(frm, v) do { \
2705 frm[0] = (v) & 0xff; \
2706 frm[1] = ((v) >> 8) & 0xff; \
2707 frm[2] = ((v) >> 16) & 0xff; \
2708 frm[3] = ((v) >> 24) & 0xff; \
2713 mesh_send_action_meshpeering_open(struct ieee80211_node
*ni
,
2714 int category
, int action
, void *args0
)
2716 struct ieee80211vap
*vap
= ni
->ni_vap
;
2717 struct ieee80211com
*ic
= ni
->ni_ic
;
2718 uint16_t *args
= args0
;
2719 const struct ieee80211_rateset
*rs
;
2723 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2724 "send PEER OPEN action: localid 0x%x", args
[0]);
2726 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2727 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__
, __LINE__
,
2728 ni
, ether_sprintf(ni
->ni_macaddr
), ieee80211_node_refcnt(ni
)+1);
2729 ieee80211_ref_node(ni
);
2731 m
= ieee80211_getmgtframe(&frm
,
2732 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2733 sizeof(uint16_t) /* action+category */
2734 + sizeof(uint16_t) /* capabilites */
2735 + 2 + IEEE80211_RATE_SIZE
2736 + 2 + (IEEE80211_RATE_MAXSIZE
- IEEE80211_RATE_SIZE
)
2737 + 2 + IEEE80211_MESHID_LEN
2738 + sizeof(struct ieee80211_meshconf_ie
)
2739 + sizeof(struct ieee80211_meshpeer_ie
)
2743 * mesh peer open action frame format:
2751 * [tlv] mesh peer link mgmt
2755 ADDSHORT(frm
, ieee80211_getcapinfo(vap
, ni
->ni_chan
));
2756 rs
= ieee80211_get_suprates(ic
, ic
->ic_curchan
);
2757 frm
= ieee80211_add_rates(frm
, rs
);
2758 frm
= ieee80211_add_xrates(frm
, rs
);
2759 frm
= ieee80211_add_meshid(frm
, vap
);
2760 frm
= ieee80211_add_meshconf(frm
, vap
);
2761 frm
= ieee80211_add_meshpeer(frm
, IEEE80211_ACTION_MESHPEERING_OPEN
,
2763 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2764 return mesh_send_action(ni
, vap
->iv_myaddr
, ni
->ni_macaddr
, m
);
2766 vap
->iv_stats
.is_tx_nobuf
++;
2767 ieee80211_free_node(ni
);
2773 mesh_send_action_meshpeering_confirm(struct ieee80211_node
*ni
,
2774 int category
, int action
, void *args0
)
2776 struct ieee80211vap
*vap
= ni
->ni_vap
;
2777 struct ieee80211com
*ic
= ni
->ni_ic
;
2778 uint16_t *args
= args0
;
2779 const struct ieee80211_rateset
*rs
;
2783 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2784 "send PEER CONFIRM action: localid 0x%x, peerid 0x%x",
2787 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2788 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__
, __LINE__
,
2789 ni
, ether_sprintf(ni
->ni_macaddr
), ieee80211_node_refcnt(ni
)+1);
2790 ieee80211_ref_node(ni
);
2792 m
= ieee80211_getmgtframe(&frm
,
2793 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2794 sizeof(uint16_t) /* action+category */
2795 + sizeof(uint16_t) /* capabilites */
2796 + sizeof(uint16_t) /* status code */
2797 + sizeof(uint16_t) /* AID */
2798 + 2 + IEEE80211_RATE_SIZE
2799 + 2 + (IEEE80211_RATE_MAXSIZE
- IEEE80211_RATE_SIZE
)
2800 + 2 + IEEE80211_MESHID_LEN
2801 + sizeof(struct ieee80211_meshconf_ie
)
2802 + sizeof(struct ieee80211_meshpeer_ie
)
2806 * mesh peer confirm action frame format:
2811 * [2] association id (peer ID)
2816 * [tlv] mesh peer link mgmt
2820 ADDSHORT(frm
, ieee80211_getcapinfo(vap
, ni
->ni_chan
));
2821 ADDSHORT(frm
, 0); /* status code */
2822 ADDSHORT(frm
, args
[1]); /* AID */
2823 rs
= ieee80211_get_suprates(ic
, ic
->ic_curchan
);
2824 frm
= ieee80211_add_rates(frm
, rs
);
2825 frm
= ieee80211_add_xrates(frm
, rs
);
2826 frm
= ieee80211_add_meshid(frm
, vap
);
2827 frm
= ieee80211_add_meshconf(frm
, vap
);
2828 frm
= ieee80211_add_meshpeer(frm
,
2829 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
2830 args
[0], args
[1], 0);
2831 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2832 return mesh_send_action(ni
, vap
->iv_myaddr
, ni
->ni_macaddr
, m
);
2834 vap
->iv_stats
.is_tx_nobuf
++;
2835 ieee80211_free_node(ni
);
2841 mesh_send_action_meshpeering_close(struct ieee80211_node
*ni
,
2842 int category
, int action
, void *args0
)
2844 struct ieee80211vap
*vap
= ni
->ni_vap
;
2845 struct ieee80211com
*ic
= ni
->ni_ic
;
2846 uint16_t *args
= args0
;
2850 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2851 "send PEER CLOSE action: localid 0x%x, peerid 0x%x reason %d (%s)",
2852 args
[0], args
[1], args
[2], ieee80211_reason_to_string(args
[2]));
2854 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2855 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__
, __LINE__
,
2856 ni
, ether_sprintf(ni
->ni_macaddr
), ieee80211_node_refcnt(ni
)+1);
2857 ieee80211_ref_node(ni
);
2859 m
= ieee80211_getmgtframe(&frm
,
2860 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2861 sizeof(uint16_t) /* action+category */
2862 + sizeof(uint16_t) /* reason code */
2863 + 2 + IEEE80211_MESHID_LEN
2864 + sizeof(struct ieee80211_meshpeer_ie
)
2868 * mesh peer close action frame format:
2872 * [tlv] mesh peer link mgmt
2876 frm
= ieee80211_add_meshid(frm
, vap
);
2877 frm
= ieee80211_add_meshpeer(frm
,
2878 IEEE80211_ACTION_MESHPEERING_CLOSE
,
2879 args
[0], args
[1], args
[2]);
2880 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2881 return mesh_send_action(ni
, vap
->iv_myaddr
, ni
->ni_macaddr
, m
);
2883 vap
->iv_stats
.is_tx_nobuf
++;
2884 ieee80211_free_node(ni
);
2890 mesh_send_action_meshlmetric(struct ieee80211_node
*ni
,
2891 int category
, int action
, void *arg0
)
2893 struct ieee80211vap
*vap
= ni
->ni_vap
;
2894 struct ieee80211com
*ic
= ni
->ni_ic
;
2895 struct ieee80211_meshlmetric_ie
*ie
= arg0
;
2899 if (ie
->lm_flags
& IEEE80211_MESH_LMETRIC_FLAGS_REQ
) {
2900 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2901 ni
, "%s", "send LINK METRIC REQUEST action");
2903 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
2904 ni
, "send LINK METRIC REPLY action: metric 0x%x",
2907 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2908 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__
, __LINE__
,
2909 ni
, ether_sprintf(ni
->ni_macaddr
), ieee80211_node_refcnt(ni
)+1);
2910 ieee80211_ref_node(ni
);
2912 m
= ieee80211_getmgtframe(&frm
,
2913 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2914 sizeof(uint16_t) + /* action+category */
2915 sizeof(struct ieee80211_meshlmetric_ie
)
2922 * [tlv] mesh link metric
2926 frm
= ieee80211_add_meshlmetric(frm
,
2927 ie
->lm_flags
, ie
->lm_metric
);
2928 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2929 return mesh_send_action(ni
, vap
->iv_myaddr
, ni
->ni_macaddr
, m
);
2931 vap
->iv_stats
.is_tx_nobuf
++;
2932 ieee80211_free_node(ni
);
2938 mesh_send_action_meshgate(struct ieee80211_node
*ni
,
2939 int category
, int action
, void *arg0
)
2941 struct ieee80211vap
*vap
= ni
->ni_vap
;
2942 struct ieee80211com
*ic
= ni
->ni_ic
;
2943 struct ieee80211_meshgann_ie
*ie
= arg0
;
2947 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2948 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__
, __LINE__
,
2949 ni
, ether_sprintf(ni
->ni_macaddr
), ieee80211_node_refcnt(ni
)+1);
2950 ieee80211_ref_node(ni
);
2952 m
= ieee80211_getmgtframe(&frm
,
2953 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2954 sizeof(uint16_t) + /* action+category */
2955 IEEE80211_MESHGANN_BASE_SZ
2962 * [tlv] mesh gate annoucement
2966 frm
= ieee80211_add_meshgate(frm
, ie
);
2967 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2968 return mesh_send_action(ni
, vap
->iv_myaddr
, broadcastaddr
, m
);
2970 vap
->iv_stats
.is_tx_nobuf
++;
2971 ieee80211_free_node(ni
);
2977 mesh_peer_timeout_setup(struct ieee80211_node
*ni
)
2979 switch (ni
->ni_mlstate
) {
2980 case IEEE80211_NODE_MESH_HOLDING
:
2981 ni
->ni_mltval
= ieee80211_mesh_holdingtimeout
;
2983 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2984 ni
->ni_mltval
= ieee80211_mesh_confirmtimeout
;
2986 case IEEE80211_NODE_MESH_IDLE
:
2990 ni
->ni_mltval
= ieee80211_mesh_retrytimeout
;
2994 callout_reset(&ni
->ni_mltimer
, ni
->ni_mltval
,
2995 mesh_peer_timeout_cb
, ni
);
2999 * Same as above but backoffs timer statisically 50%.
3002 mesh_peer_timeout_backoff(struct ieee80211_node
*ni
)
3007 ni
->ni_mltval
+= r
% ni
->ni_mltval
;
3008 callout_reset(&ni
->ni_mltimer
, ni
->ni_mltval
, mesh_peer_timeout_cb
,
3012 static __inline
void
3013 mesh_peer_timeout_stop(struct ieee80211_node
*ni
)
3015 callout_drain(&ni
->ni_mltimer
);
3019 mesh_peer_backoff_cb(void *arg
)
3021 struct ieee80211_node
*ni
= (struct ieee80211_node
*)arg
;
3023 /* After backoff timeout, try to peer automatically again. */
3028 * Mesh Peer Link Management FSM timeout handling.
3031 mesh_peer_timeout_cb(void *arg
)
3033 struct ieee80211_node
*ni
= (struct ieee80211_node
*)arg
;
3036 IEEE80211_NOTE(ni
->ni_vap
, IEEE80211_MSG_MESH
,
3037 ni
, "mesh link timeout, state %d, retry counter %d",
3038 ni
->ni_mlstate
, ni
->ni_mlrcnt
);
3040 switch (ni
->ni_mlstate
) {
3041 case IEEE80211_NODE_MESH_IDLE
:
3042 case IEEE80211_NODE_MESH_ESTABLISHED
:
3044 case IEEE80211_NODE_MESH_OPENSNT
:
3045 case IEEE80211_NODE_MESH_OPENRCV
:
3046 if (ni
->ni_mlrcnt
== ieee80211_mesh_maxretries
) {
3047 args
[0] = ni
->ni_mlpid
;
3048 args
[2] = IEEE80211_REASON_MESH_MAX_RETRIES
;
3049 ieee80211_send_action(ni
,
3050 IEEE80211_ACTION_CAT_SELF_PROT
,
3051 IEEE80211_ACTION_MESHPEERING_CLOSE
, args
);
3053 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
3054 mesh_peer_timeout_setup(ni
);
3056 args
[0] = ni
->ni_mlpid
;
3057 ieee80211_send_action(ni
,
3058 IEEE80211_ACTION_CAT_SELF_PROT
,
3059 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
3061 mesh_peer_timeout_backoff(ni
);
3064 case IEEE80211_NODE_MESH_CONFIRMRCV
:
3065 args
[0] = ni
->ni_mlpid
;
3066 args
[2] = IEEE80211_REASON_MESH_CONFIRM_TIMEOUT
;
3067 ieee80211_send_action(ni
,
3068 IEEE80211_ACTION_CAT_SELF_PROT
,
3069 IEEE80211_ACTION_MESHPEERING_CLOSE
, args
);
3070 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
3071 mesh_peer_timeout_setup(ni
);
3073 case IEEE80211_NODE_MESH_HOLDING
:
3075 if (ni
->ni_mlhcnt
>= ieee80211_mesh_maxholding
)
3076 callout_reset(&ni
->ni_mlhtimer
,
3077 ieee80211_mesh_backofftimeout
,
3078 mesh_peer_backoff_cb
, ni
);
3079 mesh_linkchange(ni
, IEEE80211_NODE_MESH_IDLE
);
3085 mesh_verify_meshid(struct ieee80211vap
*vap
, const uint8_t *ie
)
3087 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3089 if (ie
== NULL
|| ie
[1] != ms
->ms_idlen
)
3091 return memcmp(ms
->ms_id
, ie
+ 2, ms
->ms_idlen
);
3095 * Check if we are using the same algorithms for this mesh.
3098 mesh_verify_meshconf(struct ieee80211vap
*vap
, const uint8_t *ie
)
3100 const struct ieee80211_meshconf_ie
*meshconf
=
3101 (const struct ieee80211_meshconf_ie
*) ie
;
3102 const struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3104 if (meshconf
== NULL
)
3106 if (meshconf
->conf_pselid
!= ms
->ms_ppath
->mpp_ie
) {
3107 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3108 "unknown path selection algorithm: 0x%x\n",
3109 meshconf
->conf_pselid
);
3112 if (meshconf
->conf_pmetid
!= ms
->ms_pmetric
->mpm_ie
) {
3113 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3114 "unknown path metric algorithm: 0x%x\n",
3115 meshconf
->conf_pmetid
);
3118 if (meshconf
->conf_ccid
!= 0) {
3119 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3120 "unknown congestion control algorithm: 0x%x\n",
3121 meshconf
->conf_ccid
);
3124 if (meshconf
->conf_syncid
!= IEEE80211_MESHCONF_SYNC_NEIGHOFF
) {
3125 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3126 "unknown sync algorithm: 0x%x\n",
3127 meshconf
->conf_syncid
);
3130 if (meshconf
->conf_authid
!= 0) {
3131 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3132 "unknown auth auth algorithm: 0x%x\n",
3133 meshconf
->conf_pselid
);
3136 /* Not accepting peers */
3137 if (!(meshconf
->conf_cap
& IEEE80211_MESHCONF_CAP_AP
)) {
3138 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
3139 "not accepting peers: 0x%x\n", meshconf
->conf_cap
);
3146 mesh_verify_meshpeer(struct ieee80211vap
*vap
, uint8_t subtype
,
3149 const struct ieee80211_meshpeer_ie
*meshpeer
=
3150 (const struct ieee80211_meshpeer_ie
*) ie
;
3152 if (meshpeer
== NULL
||
3153 meshpeer
->peer_len
< IEEE80211_MPM_BASE_SZ
||
3154 meshpeer
->peer_len
> IEEE80211_MPM_MAX_SZ
)
3156 if (meshpeer
->peer_proto
!= IEEE80211_MPPID_MPM
) {
3157 IEEE80211_DPRINTF(vap
,
3158 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
3159 "Only MPM protocol is supported (proto: 0x%02X)",
3160 meshpeer
->peer_proto
);
3164 case IEEE80211_ACTION_MESHPEERING_OPEN
:
3165 if (meshpeer
->peer_len
!= IEEE80211_MPM_BASE_SZ
)
3168 case IEEE80211_ACTION_MESHPEERING_CONFIRM
:
3169 if (meshpeer
->peer_len
!= IEEE80211_MPM_BASE_SZ
+ 2)
3172 case IEEE80211_ACTION_MESHPEERING_CLOSE
:
3173 if (meshpeer
->peer_len
< IEEE80211_MPM_BASE_SZ
+ 2)
3175 if (meshpeer
->peer_len
== (IEEE80211_MPM_BASE_SZ
+ 2) &&
3176 meshpeer
->peer_linkid
!= 0)
3178 if (meshpeer
->peer_rcode
== 0)
3186 * Add a Mesh ID IE to a frame.
3189 ieee80211_add_meshid(uint8_t *frm
, struct ieee80211vap
*vap
)
3191 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3193 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a mbss vap"));
3195 *frm
++ = IEEE80211_ELEMID_MESHID
;
3196 *frm
++ = ms
->ms_idlen
;
3197 memcpy(frm
, ms
->ms_id
, ms
->ms_idlen
);
3198 return frm
+ ms
->ms_idlen
;
3202 * Add a Mesh Configuration IE to a frame.
3203 * For now just use HWMP routing, Airtime link metric, Null Congestion
3204 * Signaling, Null Sync Protocol and Null Authentication.
3207 ieee80211_add_meshconf(uint8_t *frm
, struct ieee80211vap
*vap
)
3209 const struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3212 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a MBSS vap"));
3214 *frm
++ = IEEE80211_ELEMID_MESHCONF
;
3215 *frm
++ = IEEE80211_MESH_CONF_SZ
;
3216 *frm
++ = ms
->ms_ppath
->mpp_ie
; /* path selection */
3217 *frm
++ = ms
->ms_pmetric
->mpm_ie
; /* link metric */
3218 *frm
++ = IEEE80211_MESHCONF_CC_DISABLED
;
3219 *frm
++ = IEEE80211_MESHCONF_SYNC_NEIGHOFF
;
3220 *frm
++ = IEEE80211_MESHCONF_AUTH_DISABLED
;
3221 /* NB: set the number of neighbors before the rest */
3222 *frm
= (ms
->ms_neighbors
> IEEE80211_MESH_MAX_NEIGHBORS
?
3223 IEEE80211_MESH_MAX_NEIGHBORS
: ms
->ms_neighbors
) << 1;
3224 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
)
3225 *frm
|= IEEE80211_MESHCONF_FORM_GATE
;
3228 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
)
3229 caps
|= IEEE80211_MESHCONF_CAP_AP
;
3230 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)
3231 caps
|= IEEE80211_MESHCONF_CAP_FWRD
;
3237 * Add a Mesh Peer Management IE to a frame.
3240 ieee80211_add_meshpeer(uint8_t *frm
, uint8_t subtype
, uint16_t localid
,
3241 uint16_t peerid
, uint16_t reason
)
3244 KASSERT(localid
!= 0, ("localid == 0"));
3246 *frm
++ = IEEE80211_ELEMID_MESHPEER
;
3248 case IEEE80211_ACTION_MESHPEERING_OPEN
:
3249 *frm
++ = IEEE80211_MPM_BASE_SZ
; /* length */
3250 ADDSHORT(frm
, IEEE80211_MPPID_MPM
); /* proto */
3251 ADDSHORT(frm
, localid
); /* local ID */
3253 case IEEE80211_ACTION_MESHPEERING_CONFIRM
:
3254 KASSERT(peerid
!= 0, ("sending peer confirm without peer id"));
3255 *frm
++ = IEEE80211_MPM_BASE_SZ
+ 2; /* length */
3256 ADDSHORT(frm
, IEEE80211_MPPID_MPM
); /* proto */
3257 ADDSHORT(frm
, localid
); /* local ID */
3258 ADDSHORT(frm
, peerid
); /* peer ID */
3260 case IEEE80211_ACTION_MESHPEERING_CLOSE
:
3262 *frm
++ = IEEE80211_MPM_MAX_SZ
; /* length */
3264 *frm
++ = IEEE80211_MPM_BASE_SZ
+ 2; /* length */
3265 ADDSHORT(frm
, IEEE80211_MPPID_MPM
); /* proto */
3266 ADDSHORT(frm
, localid
); /* local ID */
3268 ADDSHORT(frm
, peerid
); /* peer ID */
3269 ADDSHORT(frm
, reason
);
3276 * Compute an Airtime Link Metric for the link with this node.
3278 * Based on Draft 3.0 spec (11B.10, p.149).
3281 * Max 802.11s overhead.
3283 #define IEEE80211_MESH_MAXOVERHEAD \
3284 (sizeof(struct ieee80211_qosframe_addr4) \
3285 + sizeof(struct ieee80211_meshcntl_ae10) \
3286 + sizeof(struct llc) \
3287 + IEEE80211_ADDR_LEN \
3288 + IEEE80211_WEP_IVLEN \
3289 + IEEE80211_WEP_KIDLEN \
3290 + IEEE80211_WEP_CRCLEN \
3291 + IEEE80211_WEP_MICLEN \
3292 + IEEE80211_CRC_LEN)
3294 mesh_airtime_calc(struct ieee80211_node
*ni
)
3297 #define S_FACTOR (2 * M_BITS)
3298 struct ieee80211com
*ic
= ni
->ni_ic
;
3299 struct ifnet
*ifp
= ni
->ni_vap
->iv_ifp
;
3300 const static int nbits
= 8192 << M_BITS
;
3301 uint32_t overhead
, rate
, errrate
;
3304 /* Time to transmit a frame */
3305 rate
= ni
->ni_txrate
;
3306 overhead
= ieee80211_compute_duration(ic
->ic_rt
,
3307 ifp
->if_mtu
+ IEEE80211_MESH_MAXOVERHEAD
, rate
, 0) << M_BITS
;
3308 /* Error rate in percentage */
3309 /* XXX assuming small failures are ok */
3310 errrate
= (((ifp
->if_get_counter(ifp
, IFCOUNTER_OERRORS
) +
3311 ifp
->if_get_counter(ifp
, IFCOUNTER_IERRORS
)) / 100) << M_BITS
)
3313 res
= (overhead
+ (nbits
/ rate
)) *
3314 ((1 << S_FACTOR
) / ((1 << M_BITS
) - errrate
));
3316 return (uint32_t)(res
>> S_FACTOR
);
3322 * Add a Mesh Link Metric report IE to a frame.
3325 ieee80211_add_meshlmetric(uint8_t *frm
, uint8_t flags
, uint32_t metric
)
3327 *frm
++ = IEEE80211_ELEMID_MESHLINK
;
3330 ADDWORD(frm
, metric
);
3335 * Add a Mesh Gate Announcement IE to a frame.
3338 ieee80211_add_meshgate(uint8_t *frm
, struct ieee80211_meshgann_ie
*ie
)
3340 *frm
++ = IEEE80211_ELEMID_MESHGANN
; /* ie */
3341 *frm
++ = IEEE80211_MESHGANN_BASE_SZ
; /* len */
3342 *frm
++ = ie
->gann_flags
;
3343 *frm
++ = ie
->gann_hopcount
;
3344 *frm
++ = ie
->gann_ttl
;
3345 IEEE80211_ADDR_COPY(frm
, ie
->gann_addr
);
3347 ADDWORD(frm
, ie
->gann_seq
);
3348 ADDSHORT(frm
, ie
->gann_interval
);
3355 * Initialize any mesh-specific node state.
3358 ieee80211_mesh_node_init(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
)
3360 ni
->ni_flags
|= IEEE80211_NODE_QOS
;
3361 callout_init(&ni
->ni_mltimer
, 1);
3362 callout_init(&ni
->ni_mlhtimer
, 1);
3366 * Cleanup any mesh-specific node state.
3369 ieee80211_mesh_node_cleanup(struct ieee80211_node
*ni
)
3371 struct ieee80211vap
*vap
= ni
->ni_vap
;
3372 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3374 callout_drain(&ni
->ni_mltimer
);
3375 callout_drain(&ni
->ni_mlhtimer
);
3376 /* NB: short-circuit callbacks after mesh_vdetach */
3377 if (vap
->iv_mesh
!= NULL
)
3378 ms
->ms_ppath
->mpp_peerdown(ni
);
3382 ieee80211_parse_meshid(struct ieee80211_node
*ni
, const uint8_t *ie
)
3384 ni
->ni_meshidlen
= ie
[1];
3385 memcpy(ni
->ni_meshid
, ie
+ 2, ie
[1]);
3389 * Setup mesh-specific node state on neighbor discovery.
3392 ieee80211_mesh_init_neighbor(struct ieee80211_node
*ni
,
3393 const struct ieee80211_frame
*wh
,
3394 const struct ieee80211_scanparams
*sp
)
3396 ieee80211_parse_meshid(ni
, sp
->meshid
);
3400 ieee80211_mesh_update_beacon(struct ieee80211vap
*vap
,
3401 struct ieee80211_beacon_offsets
*bo
)
3403 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a MBSS vap"));
3405 if (isset(bo
->bo_flags
, IEEE80211_BEACON_MESHCONF
)) {
3406 (void)ieee80211_add_meshconf(bo
->bo_meshconf
, vap
);
3407 clrbit(bo
->bo_flags
, IEEE80211_BEACON_MESHCONF
);
3412 mesh_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
3414 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3415 uint8_t tmpmeshid
[IEEE80211_NWID_LEN
];
3416 struct ieee80211_mesh_route
*rt
;
3417 struct ieee80211req_mesh_route
*imr
;
3422 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
3426 switch (ireq
->i_type
) {
3427 case IEEE80211_IOC_MESH_ID
:
3428 ireq
->i_len
= ms
->ms_idlen
;
3429 memcpy(tmpmeshid
, ms
->ms_id
, ireq
->i_len
);
3430 error
= copyout(tmpmeshid
, ireq
->i_data
, ireq
->i_len
);
3432 case IEEE80211_IOC_MESH_AP
:
3433 ireq
->i_val
= (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
) != 0;
3435 case IEEE80211_IOC_MESH_FWRD
:
3436 ireq
->i_val
= (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) != 0;
3438 case IEEE80211_IOC_MESH_GATE
:
3439 ireq
->i_val
= (ms
->ms_flags
& IEEE80211_MESHFLAGS_GATE
) != 0;
3441 case IEEE80211_IOC_MESH_TTL
:
3442 ireq
->i_val
= ms
->ms_ttl
;
3444 case IEEE80211_IOC_MESH_RTCMD
:
3445 switch (ireq
->i_val
) {
3446 case IEEE80211_MESH_RTCMD_LIST
:
3449 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
3450 len
+= sizeof(*imr
);
3453 if (len
> ireq
->i_len
|| ireq
->i_len
< sizeof(*imr
)) {
3459 p
= IEEE80211_MALLOC(len
, M_TEMP
,
3460 IEEE80211_M_NOWAIT
| IEEE80211_M_ZERO
);
3465 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
3468 imr
= (struct ieee80211req_mesh_route
*)
3470 IEEE80211_ADDR_COPY(imr
->imr_dest
,
3472 IEEE80211_ADDR_COPY(imr
->imr_nexthop
,
3474 imr
->imr_metric
= rt
->rt_metric
;
3475 imr
->imr_nhops
= rt
->rt_nhops
;
3477 ieee80211_mesh_rt_update(rt
, 0);
3478 imr
->imr_lastmseq
= rt
->rt_lastmseq
;
3479 imr
->imr_flags
= rt
->rt_flags
; /* last */
3480 off
+= sizeof(*imr
);
3483 error
= copyout(p
, (uint8_t *)ireq
->i_data
,
3485 IEEE80211_FREE(p
, M_TEMP
);
3487 case IEEE80211_MESH_RTCMD_FLUSH
:
3488 case IEEE80211_MESH_RTCMD_ADD
:
3489 case IEEE80211_MESH_RTCMD_DELETE
:
3495 case IEEE80211_IOC_MESH_PR_METRIC
:
3496 len
= strlen(ms
->ms_pmetric
->mpm_descr
);
3497 if (ireq
->i_len
< len
)
3500 error
= copyout(ms
->ms_pmetric
->mpm_descr
,
3501 (uint8_t *)ireq
->i_data
, len
);
3503 case IEEE80211_IOC_MESH_PR_PATH
:
3504 len
= strlen(ms
->ms_ppath
->mpp_descr
);
3505 if (ireq
->i_len
< len
)
3508 error
= copyout(ms
->ms_ppath
->mpp_descr
,
3509 (uint8_t *)ireq
->i_data
, len
);
3517 IEEE80211_IOCTL_GET(mesh
, mesh_ioctl_get80211
);
3520 mesh_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
3522 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
3523 uint8_t tmpmeshid
[IEEE80211_NWID_LEN
];
3524 uint8_t tmpaddr
[IEEE80211_ADDR_LEN
];
3525 char tmpproto
[IEEE80211_MESH_PROTO_DSZ
];
3528 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
3532 switch (ireq
->i_type
) {
3533 case IEEE80211_IOC_MESH_ID
:
3534 if (ireq
->i_val
!= 0 || ireq
->i_len
> IEEE80211_MESHID_LEN
)
3536 error
= copyin(ireq
->i_data
, tmpmeshid
, ireq
->i_len
);
3539 memset(ms
->ms_id
, 0, IEEE80211_NWID_LEN
);
3540 ms
->ms_idlen
= ireq
->i_len
;
3541 memcpy(ms
->ms_id
, tmpmeshid
, ireq
->i_len
);
3544 case IEEE80211_IOC_MESH_AP
:
3546 ms
->ms_flags
|= IEEE80211_MESHFLAGS_AP
;
3548 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_AP
;
3551 case IEEE80211_IOC_MESH_FWRD
:
3553 ms
->ms_flags
|= IEEE80211_MESHFLAGS_FWD
;
3555 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_FWD
;
3556 mesh_gatemode_setup(vap
);
3558 case IEEE80211_IOC_MESH_GATE
:
3560 ms
->ms_flags
|= IEEE80211_MESHFLAGS_GATE
;
3562 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_GATE
;
3564 case IEEE80211_IOC_MESH_TTL
:
3565 ms
->ms_ttl
= (uint8_t) ireq
->i_val
;
3567 case IEEE80211_IOC_MESH_RTCMD
:
3568 switch (ireq
->i_val
) {
3569 case IEEE80211_MESH_RTCMD_LIST
:
3571 case IEEE80211_MESH_RTCMD_FLUSH
:
3572 ieee80211_mesh_rt_flush(vap
);
3574 case IEEE80211_MESH_RTCMD_ADD
:
3575 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, ireq
->i_data
) ||
3576 IEEE80211_ADDR_EQ(broadcastaddr
, ireq
->i_data
))
3578 error
= copyin(ireq
->i_data
, &tmpaddr
,
3579 IEEE80211_ADDR_LEN
);
3581 ieee80211_mesh_discover(vap
, tmpaddr
, NULL
);
3583 case IEEE80211_MESH_RTCMD_DELETE
:
3584 ieee80211_mesh_rt_del(vap
, ireq
->i_data
);
3590 case IEEE80211_IOC_MESH_PR_METRIC
:
3591 error
= copyin(ireq
->i_data
, tmpproto
, sizeof(tmpproto
));
3593 error
= mesh_select_proto_metric(vap
, tmpproto
);
3598 case IEEE80211_IOC_MESH_PR_PATH
:
3599 error
= copyin(ireq
->i_data
, tmpproto
, sizeof(tmpproto
));
3601 error
= mesh_select_proto_path(vap
, tmpproto
);
3611 IEEE80211_IOCTL_SET(mesh
, mesh_ioctl_set80211
);