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 * $FreeBSD: head/sys/net80211/ieee80211_mesh.c 203423 2010-02-03 10:12:49Z rpaulo $
33 * IEEE 802.11s Mesh Point (MBSS) support.
35 * Based on March 2009, D3.0 802.11s draft spec.
40 #include <sys/param.h>
41 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/kernel.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/endian.h>
49 #include <sys/errno.h>
51 #include <sys/sysctl.h>
54 #include <net/if_media.h>
55 #include <net/if_llc.h>
56 #include <net/ethernet.h>
57 #include <net/route.h>
59 #include <netproto/802_11/ieee80211_var.h>
60 #include <netproto/802_11/ieee80211_action.h>
61 #include <netproto/802_11/ieee80211_input.h>
62 #include <netproto/802_11/ieee80211_mesh.h>
64 static void mesh_rt_flush_invalid(struct ieee80211vap
*);
65 static int mesh_select_proto_path(struct ieee80211vap
*, const char *);
66 static int mesh_select_proto_metric(struct ieee80211vap
*, const char *);
67 static void mesh_vattach(struct ieee80211vap
*);
68 static int mesh_newstate(struct ieee80211vap
*, enum ieee80211_state
, int);
69 static void mesh_rt_cleanup_callout(void *);
70 static void mesh_linkchange(struct ieee80211_node
*,
71 enum ieee80211_mesh_mlstate
);
72 static void mesh_checkid(void *, struct ieee80211_node
*);
73 static uint32_t mesh_generateid(struct ieee80211vap
*);
74 static int mesh_checkpseq(struct ieee80211vap
*,
75 const uint8_t [IEEE80211_ADDR_LEN
], uint32_t);
76 static struct ieee80211_node
*
77 mesh_find_txnode(struct ieee80211vap
*,
78 const uint8_t [IEEE80211_ADDR_LEN
]);
79 static void mesh_forward(struct ieee80211vap
*, struct mbuf
*,
80 const struct ieee80211_meshcntl
*);
81 static int mesh_input(struct ieee80211_node
*, struct mbuf
*, int, int);
82 static void mesh_recv_mgmt(struct ieee80211_node
*, struct mbuf
*, int,
84 static void mesh_peer_timeout_setup(struct ieee80211_node
*);
85 static void mesh_peer_timeout_backoff(struct ieee80211_node
*);
86 static void mesh_peer_timeout_callout(void *);
88 mesh_peer_timeout_stop(struct ieee80211_node
*);
89 static int mesh_verify_meshid(struct ieee80211vap
*, const uint8_t *);
90 static int mesh_verify_meshconf(struct ieee80211vap
*, const uint8_t *);
91 static int mesh_verify_meshpeer(struct ieee80211vap
*, uint8_t,
93 uint32_t mesh_airtime_calc(struct ieee80211_node
*);
96 * Timeout values come from the specification and are in milliseconds.
98 SYSCTL_NODE(_net_wlan
, OID_AUTO
, mesh
, CTLFLAG_RD
, 0,
99 "IEEE 802.11s parameters");
100 static int ieee80211_mesh_retrytimeout
= -1;
101 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, retrytimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
102 &ieee80211_mesh_retrytimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
103 "Retry timeout (msec)");
104 static int ieee80211_mesh_holdingtimeout
= -1;
105 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, holdingtimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
106 &ieee80211_mesh_holdingtimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
107 "Holding state timeout (msec)");
108 static int ieee80211_mesh_confirmtimeout
= -1;
109 SYSCTL_PROC(_net_wlan_mesh
, OID_AUTO
, confirmtimeout
, CTLTYPE_INT
| CTLFLAG_RW
,
110 &ieee80211_mesh_confirmtimeout
, 0, ieee80211_sysctl_msecs_ticks
, "I",
111 "Confirm state timeout (msec)");
112 static int ieee80211_mesh_maxretries
= 2;
113 SYSCTL_INT(_net_wlan_mesh
, OID_AUTO
, maxretries
, CTLTYPE_INT
| CTLFLAG_RW
,
114 &ieee80211_mesh_maxretries
, 0,
115 "Maximum retries during peer link establishment");
117 static const uint8_t broadcastaddr
[IEEE80211_ADDR_LEN
] =
118 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
120 static ieee80211_recv_action_func mesh_recv_action_meshpeering_open
;
121 static ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm
;
122 static ieee80211_recv_action_func mesh_recv_action_meshpeering_close
;
123 static ieee80211_recv_action_func mesh_recv_action_meshlmetric_req
;
124 static ieee80211_recv_action_func mesh_recv_action_meshlmetric_rep
;
126 static ieee80211_send_action_func mesh_send_action_meshpeering_open
;
127 static ieee80211_send_action_func mesh_send_action_meshpeering_confirm
;
128 static ieee80211_send_action_func mesh_send_action_meshpeering_close
;
129 static ieee80211_send_action_func mesh_send_action_meshlink_request
;
130 static ieee80211_send_action_func mesh_send_action_meshlink_reply
;
132 static const struct ieee80211_mesh_proto_metric mesh_metric_airtime
= {
133 .mpm_descr
= "AIRTIME",
134 .mpm_ie
= IEEE80211_MESHCONF_METRIC_AIRTIME
,
135 .mpm_metric
= mesh_airtime_calc
,
138 static struct ieee80211_mesh_proto_path mesh_proto_paths
[4];
139 static struct ieee80211_mesh_proto_metric mesh_proto_metrics
[4];
141 MALLOC_DEFINE(M_80211_MESH_RT
, "80211mesh", "802.11s routing table");
144 * Helper functions to manipulate the Mesh routing table.
147 static struct ieee80211_mesh_route
*
148 mesh_rt_find_locked(struct ieee80211_mesh_state
*ms
,
149 const uint8_t dest
[IEEE80211_ADDR_LEN
])
151 struct ieee80211_mesh_route
*rt
;
153 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
154 if (IEEE80211_ADDR_EQ(dest
, rt
->rt_dest
))
160 static struct ieee80211_mesh_route
*
161 mesh_rt_add_locked(struct ieee80211_mesh_state
*ms
,
162 const uint8_t dest
[IEEE80211_ADDR_LEN
])
164 struct ieee80211_mesh_route
*rt
;
166 KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr
, dest
),
167 ("%s: adding broadcast to the routing table", __func__
));
169 rt
= kmalloc(ALIGN(sizeof(struct ieee80211_mesh_route
)) +
170 ms
->ms_ppath
->mpp_privlen
, M_80211_MESH_RT
, M_INTWAIT
| M_ZERO
);
172 IEEE80211_ADDR_COPY(rt
->rt_dest
, dest
);
173 rt
->rt_priv
= (void *)ALIGN(&rt
[1]);
174 rt
->rt_crtime
= ticks
;
175 TAILQ_INSERT_TAIL(&ms
->ms_routes
, rt
, rt_next
);
180 struct ieee80211_mesh_route
*
181 ieee80211_mesh_rt_find(struct ieee80211vap
*vap
,
182 const uint8_t dest
[IEEE80211_ADDR_LEN
])
184 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
185 struct ieee80211_mesh_route
*rt
;
187 rt
= mesh_rt_find_locked(ms
, dest
);
191 struct ieee80211_mesh_route
*
192 ieee80211_mesh_rt_add(struct ieee80211vap
*vap
,
193 const uint8_t dest
[IEEE80211_ADDR_LEN
])
195 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
196 struct ieee80211_mesh_route
*rt
;
198 KASSERT(ieee80211_mesh_rt_find(vap
, dest
) == NULL
,
199 ("%s: duplicate entry in the routing table", __func__
));
200 KASSERT(!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, dest
),
201 ("%s: adding self to the routing table", __func__
));
203 rt
= mesh_rt_add_locked(ms
, dest
);
208 * Add a proxy route (as needed) for the specified destination.
211 ieee80211_mesh_proxy_check(struct ieee80211vap
*vap
,
212 const uint8_t dest
[IEEE80211_ADDR_LEN
])
214 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
215 struct ieee80211_mesh_route
*rt
;
217 rt
= mesh_rt_find_locked(ms
, dest
);
219 rt
= mesh_rt_add_locked(ms
, dest
);
221 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
222 "%s", "unable to add proxy entry");
223 vap
->iv_stats
.is_mesh_rtaddfailed
++;
225 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
226 "%s", "add proxy entry");
227 IEEE80211_ADDR_COPY(rt
->rt_nexthop
, vap
->iv_myaddr
);
228 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
229 | IEEE80211_MESHRT_FLAGS_PROXY
;
231 /* XXX assert PROXY? */
232 } else if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0) {
233 struct ieee80211com
*ic
= vap
->iv_ic
;
235 * Fix existing entry created by received frames from
236 * stations that have some memory of dest. We also
237 * flush any frames held on the staging queue; delivering
238 * them is too much trouble right now.
240 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
241 "%s", "fix proxy entry");
242 IEEE80211_ADDR_COPY(rt
->rt_nexthop
, vap
->iv_myaddr
);
243 rt
->rt_flags
|= IEEE80211_MESHRT_FLAGS_VALID
244 | IEEE80211_MESHRT_FLAGS_PROXY
;
245 /* XXX belongs in hwmp */
246 ieee80211_ageq_drain_node(&ic
->ic_stageq
,
247 (void *)(uintptr_t) ieee80211_mac_hash(ic
, dest
));
253 mesh_rt_del(struct ieee80211_mesh_state
*ms
, struct ieee80211_mesh_route
*rt
)
255 TAILQ_REMOVE(&ms
->ms_routes
, rt
, rt_next
);
256 kfree(rt
, M_80211_MESH_RT
);
260 ieee80211_mesh_rt_del(struct ieee80211vap
*vap
,
261 const uint8_t dest
[IEEE80211_ADDR_LEN
])
263 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
264 struct ieee80211_mesh_route
*rt
, *next
;
266 TAILQ_FOREACH_MUTABLE(rt
, &ms
->ms_routes
, rt_next
, next
) {
267 if (IEEE80211_ADDR_EQ(rt
->rt_dest
, dest
)) {
275 ieee80211_mesh_rt_flush(struct ieee80211vap
*vap
)
277 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
278 struct ieee80211_mesh_route
*rt
, *next
;
282 TAILQ_FOREACH_MUTABLE(rt
, &ms
->ms_routes
, rt_next
, next
)
287 ieee80211_mesh_rt_flush_peer(struct ieee80211vap
*vap
,
288 const uint8_t peer
[IEEE80211_ADDR_LEN
])
290 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
291 struct ieee80211_mesh_route
*rt
, *next
;
293 TAILQ_FOREACH_MUTABLE(rt
, &ms
->ms_routes
, rt_next
, next
) {
294 if (IEEE80211_ADDR_EQ(rt
->rt_nexthop
, peer
))
300 * Flush expired routing entries, i.e. those in invalid state for
304 mesh_rt_flush_invalid(struct ieee80211vap
*vap
)
306 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
307 struct ieee80211_mesh_route
*rt
, *next
;
311 TAILQ_FOREACH_MUTABLE(rt
, &ms
->ms_routes
, rt_next
, next
) {
312 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0 &&
313 ticks
- rt
->rt_crtime
>= ms
->ms_ppath
->mpp_inact
)
319 ieee80211_mesh_register_proto_path(const struct ieee80211_mesh_proto_path
*mpp
)
321 int i
, firstempty
= -1;
323 for (i
= 0; i
< NELEM(mesh_proto_paths
); i
++) {
324 if (strncmp(mpp
->mpp_descr
, mesh_proto_paths
[i
].mpp_descr
,
325 IEEE80211_MESH_PROTO_DSZ
) == 0)
327 if (!mesh_proto_paths
[i
].mpp_active
&& firstempty
== -1)
332 memcpy(&mesh_proto_paths
[firstempty
], mpp
, sizeof(*mpp
));
333 mesh_proto_paths
[firstempty
].mpp_active
= 1;
338 ieee80211_mesh_register_proto_metric(const struct
339 ieee80211_mesh_proto_metric
*mpm
)
341 int i
, firstempty
= -1;
343 for (i
= 0; i
< NELEM(mesh_proto_metrics
); i
++) {
344 if (strncmp(mpm
->mpm_descr
, mesh_proto_metrics
[i
].mpm_descr
,
345 IEEE80211_MESH_PROTO_DSZ
) == 0)
347 if (!mesh_proto_metrics
[i
].mpm_active
&& firstempty
== -1)
352 memcpy(&mesh_proto_metrics
[firstempty
], mpm
, sizeof(*mpm
));
353 mesh_proto_metrics
[firstempty
].mpm_active
= 1;
358 mesh_select_proto_path(struct ieee80211vap
*vap
, const char *name
)
360 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
363 for (i
= 0; i
< NELEM(mesh_proto_paths
); i
++) {
364 if (strcasecmp(mesh_proto_paths
[i
].mpp_descr
, name
) == 0) {
365 ms
->ms_ppath
= &mesh_proto_paths
[i
];
373 mesh_select_proto_metric(struct ieee80211vap
*vap
, const char *name
)
375 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
378 for (i
= 0; i
< NELEM(mesh_proto_metrics
); i
++) {
379 if (strcasecmp(mesh_proto_metrics
[i
].mpm_descr
, name
) == 0) {
380 ms
->ms_pmetric
= &mesh_proto_metrics
[i
];
388 ieee80211_mesh_init(void)
391 memset(mesh_proto_paths
, 0, sizeof(mesh_proto_paths
));
392 memset(mesh_proto_metrics
, 0, sizeof(mesh_proto_metrics
));
395 * Setup mesh parameters that depends on the clock frequency.
397 ieee80211_mesh_retrytimeout
= msecs_to_ticks(40);
398 ieee80211_mesh_holdingtimeout
= msecs_to_ticks(40);
399 ieee80211_mesh_confirmtimeout
= msecs_to_ticks(40);
402 * Register action frame handlers.
404 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
405 IEEE80211_ACTION_MESHPEERING_OPEN
,
406 mesh_recv_action_meshpeering_open
);
407 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
408 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
409 mesh_recv_action_meshpeering_confirm
);
410 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
411 IEEE80211_ACTION_MESHPEERING_CLOSE
,
412 mesh_recv_action_meshpeering_close
);
413 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC
,
414 IEEE80211_ACTION_MESHLMETRIC_REQ
, mesh_recv_action_meshlmetric_req
);
415 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC
,
416 IEEE80211_ACTION_MESHLMETRIC_REP
, mesh_recv_action_meshlmetric_rep
);
418 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
419 IEEE80211_ACTION_MESHPEERING_OPEN
,
420 mesh_send_action_meshpeering_open
);
421 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
422 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
423 mesh_send_action_meshpeering_confirm
);
424 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING
,
425 IEEE80211_ACTION_MESHPEERING_CLOSE
,
426 mesh_send_action_meshpeering_close
);
427 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC
,
428 IEEE80211_ACTION_MESHLMETRIC_REQ
,
429 mesh_send_action_meshlink_request
);
430 ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC
,
431 IEEE80211_ACTION_MESHLMETRIC_REP
,
432 mesh_send_action_meshlink_reply
);
435 * Register Airtime Link Metric.
437 ieee80211_mesh_register_proto_metric(&mesh_metric_airtime
);
440 SYSINIT(wlan_mesh
, SI_SUB_DRIVERS
, SI_ORDER_FIRST
, ieee80211_mesh_init
, NULL
);
443 ieee80211_mesh_attach(struct ieee80211com
*ic
)
445 ic
->ic_vattach
[IEEE80211_M_MBSS
] = mesh_vattach
;
449 ieee80211_mesh_detach(struct ieee80211com
*ic
)
454 mesh_vdetach_peers(void *arg
, struct ieee80211_node
*ni
)
456 struct ieee80211com
*ic
= ni
->ni_ic
;
459 if (ni
->ni_mlstate
== IEEE80211_NODE_MESH_ESTABLISHED
) {
460 args
[0] = ni
->ni_mlpid
;
461 args
[1] = ni
->ni_mllid
;
462 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
463 ieee80211_send_action(ni
,
464 IEEE80211_ACTION_CAT_MESHPEERING
,
465 IEEE80211_ACTION_MESHPEERING_CLOSE
,
468 callout_stop(&ni
->ni_mltimer
);
469 /* XXX belongs in hwmp */
470 ieee80211_ageq_drain_node(&ic
->ic_stageq
,
471 (void *)(uintptr_t) ieee80211_mac_hash(ic
, ni
->ni_macaddr
));
475 mesh_vdetach(struct ieee80211vap
*vap
)
477 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
479 callout_stop(&ms
->ms_cleantimer
);
480 ieee80211_iterate_nodes(&vap
->iv_ic
->ic_sta
, mesh_vdetach_peers
,
482 ieee80211_mesh_rt_flush(vap
);
483 ms
->ms_ppath
->mpp_vdetach(vap
);
484 kfree(vap
->iv_mesh
, M_80211_VAP
);
489 mesh_vattach(struct ieee80211vap
*vap
)
491 struct ieee80211_mesh_state
*ms
;
492 vap
->iv_newstate
= mesh_newstate
;
493 vap
->iv_input
= mesh_input
;
494 vap
->iv_opdetach
= mesh_vdetach
;
495 vap
->iv_recv_mgmt
= mesh_recv_mgmt
;
496 ms
= kmalloc(sizeof(struct ieee80211_mesh_state
), M_80211_VAP
,
499 kprintf("%s: couldn't alloc MBSS state\n", __func__
);
504 ms
->ms_flags
= (IEEE80211_MESHFLAGS_AP
| IEEE80211_MESHFLAGS_FWD
);
505 ms
->ms_ttl
= IEEE80211_MESH_DEFAULT_TTL
;
506 TAILQ_INIT(&ms
->ms_routes
);
507 callout_init_mp(&ms
->ms_cleantimer
);
508 mesh_select_proto_metric(vap
, "AIRTIME");
509 KASSERT(ms
->ms_pmetric
, ("ms_pmetric == NULL"));
510 mesh_select_proto_path(vap
, "HWMP");
511 KASSERT(ms
->ms_ppath
, ("ms_ppath == NULL"));
512 ms
->ms_ppath
->mpp_vattach(vap
);
516 * IEEE80211_M_MBSS vap state machine handler.
519 mesh_newstate(struct ieee80211vap
*vap
, enum ieee80211_state nstate
, int arg
)
521 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
522 struct ieee80211com
*ic
= vap
->iv_ic
;
523 struct ieee80211_node
*ni
;
524 enum ieee80211_state ostate
;
526 ostate
= vap
->iv_state
;
527 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
528 __func__
, ieee80211_state_name
[ostate
],
529 ieee80211_state_name
[nstate
], arg
);
530 vap
->iv_state
= nstate
; /* state transition */
531 if (ostate
!= IEEE80211_S_SCAN
)
532 ieee80211_cancel_scan(vap
); /* background scan */
533 ni
= vap
->iv_bss
; /* NB: no reference held */
534 if (nstate
!= IEEE80211_S_RUN
&& ostate
== IEEE80211_S_RUN
)
535 callout_stop(&ms
->ms_cleantimer
);
537 case IEEE80211_S_INIT
:
539 case IEEE80211_S_SCAN
:
540 ieee80211_cancel_scan(vap
);
542 case IEEE80211_S_CAC
:
543 ieee80211_dfs_cac_stop(vap
);
545 case IEEE80211_S_RUN
:
546 ieee80211_iterate_nodes(&ic
->ic_sta
,
547 mesh_vdetach_peers
, NULL
);
552 if (ostate
!= IEEE80211_S_INIT
) {
553 /* NB: optimize INIT -> INIT case */
554 ieee80211_reset_bss(vap
);
555 ieee80211_mesh_rt_flush(vap
);
558 case IEEE80211_S_SCAN
:
560 case IEEE80211_S_INIT
:
561 if (vap
->iv_des_chan
!= IEEE80211_CHAN_ANYC
&&
562 !IEEE80211_IS_CHAN_RADAR(vap
->iv_des_chan
) &&
565 * Already have a channel and a mesh ID; bypass
566 * the scan and startup immediately.
568 ieee80211_create_ibss(vap
, vap
->iv_des_chan
);
572 * Initiate a scan. We can come here as a result
573 * of an IEEE80211_IOC_SCAN_REQ too in which case
574 * the vap will be marked with IEEE80211_FEXT_SCANREQ
575 * and the scan request parameters will be present
576 * in iv_scanreq. Otherwise we do the default.
578 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SCANREQ
) {
579 ieee80211_check_scan(vap
,
580 vap
->iv_scanreq_flags
,
581 vap
->iv_scanreq_duration
,
582 vap
->iv_scanreq_mindwell
,
583 vap
->iv_scanreq_maxdwell
,
584 vap
->iv_scanreq_nssid
, vap
->iv_scanreq_ssid
);
585 vap
->iv_flags_ext
&= ~IEEE80211_FEXT_SCANREQ
;
587 ieee80211_check_scan_current(vap
);
593 case IEEE80211_S_CAC
:
595 * Start CAC on a DFS channel. We come here when starting
596 * a bss on a DFS channel (see ieee80211_create_ibss).
598 ieee80211_dfs_cac_start(vap
);
600 case IEEE80211_S_RUN
:
602 case IEEE80211_S_INIT
:
604 * Already have a channel; bypass the
605 * scan and startup immediately.
606 * Note that ieee80211_create_ibss will call
607 * back to do a RUN->RUN state change.
609 ieee80211_create_ibss(vap
,
610 ieee80211_ht_adjust_channel(ic
,
611 ic
->ic_curchan
, vap
->iv_flags_ht
));
612 /* NB: iv_bss is changed on return */
614 case IEEE80211_S_CAC
:
616 * NB: This is the normal state change when CAC
617 * expires and no radar was detected; no need to
618 * clear the CAC timer as it's already expired.
621 case IEEE80211_S_CSA
:
624 * Shorten inactivity timer of associated stations
625 * to weed out sta's that don't follow a CSA.
627 ieee80211_iterate_nodes(&ic
->ic_sta
, sta_csa
, vap
);
630 * Update bss node channel to reflect where
631 * we landed after CSA.
633 ieee80211_node_set_chan(vap
->iv_bss
,
634 ieee80211_ht_adjust_channel(ic
, ic
->ic_curchan
,
635 ieee80211_htchanflags(vap
->iv_bss
->ni_chan
)));
636 /* XXX bypass debug msgs */
638 case IEEE80211_S_SCAN
:
639 case IEEE80211_S_RUN
:
640 #ifdef IEEE80211_DEBUG
641 if (ieee80211_msg_debug(vap
)) {
642 struct ieee80211_node
*ni
= vap
->iv_bss
;
644 "synchronized with %6D meshid ",
646 ieee80211_print_essid(ni
->ni_meshid
,
649 kprintf(" channel %d\n",
650 ieee80211_chan2ieee(ic
, ic
->ic_curchan
));
657 ieee80211_node_authorize(vap
->iv_bss
);
658 callout_reset(&ms
->ms_cleantimer
, ms
->ms_ppath
->mpp_inact
,
659 mesh_rt_cleanup_callout
, vap
);
664 /* NB: ostate not nstate */
665 ms
->ms_ppath
->mpp_newstate(vap
, ostate
, arg
);
670 mesh_rt_cleanup_callout(void *arg
)
672 struct ieee80211vap
*vap
= arg
;
673 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
675 wlan_serialize_enter();
676 mesh_rt_flush_invalid(vap
);
677 callout_reset(&ms
->ms_cleantimer
, ms
->ms_ppath
->mpp_inact
,
678 mesh_rt_cleanup_callout
, vap
);
679 wlan_serialize_exit();
684 * Helper function to note the Mesh Peer Link FSM change.
687 mesh_linkchange(struct ieee80211_node
*ni
, enum ieee80211_mesh_mlstate state
)
689 struct ieee80211vap
*vap
= ni
->ni_vap
;
690 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
691 #ifdef IEEE80211_DEBUG
692 static const char *meshlinkstates
[] = {
693 [IEEE80211_NODE_MESH_IDLE
] = "IDLE",
694 [IEEE80211_NODE_MESH_OPENSNT
] = "OPEN SENT",
695 [IEEE80211_NODE_MESH_OPENRCV
] = "OPEN RECEIVED",
696 [IEEE80211_NODE_MESH_CONFIRMRCV
] = "CONFIRM RECEIVED",
697 [IEEE80211_NODE_MESH_ESTABLISHED
] = "ESTABLISHED",
698 [IEEE80211_NODE_MESH_HOLDING
] = "HOLDING"
701 IEEE80211_NOTE(vap
, IEEE80211_MSG_MESH
,
702 ni
, "peer link: %s -> %s",
703 meshlinkstates
[ni
->ni_mlstate
], meshlinkstates
[state
]);
705 /* track neighbor count */
706 if (state
== IEEE80211_NODE_MESH_ESTABLISHED
&&
707 ni
->ni_mlstate
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
708 KASSERT(ms
->ms_neighbors
< 65535, ("neighbor count overflow"));
710 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_MESHCONF
);
711 } else if (ni
->ni_mlstate
== IEEE80211_NODE_MESH_ESTABLISHED
&&
712 state
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
713 KASSERT(ms
->ms_neighbors
> 0, ("neighbor count 0"));
715 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_MESHCONF
);
717 ni
->ni_mlstate
= state
;
719 case IEEE80211_NODE_MESH_HOLDING
:
720 ms
->ms_ppath
->mpp_peerdown(ni
);
722 case IEEE80211_NODE_MESH_ESTABLISHED
:
723 ieee80211_mesh_discover(vap
, ni
->ni_macaddr
, NULL
);
731 * Helper function to generate a unique local ID required for mesh
732 * peer establishment.
735 mesh_checkid(void *arg
, struct ieee80211_node
*ni
)
739 if (*r
== ni
->ni_mllid
)
740 *(uint16_t *)arg
= 0;
744 mesh_generateid(struct ieee80211vap
*vap
)
750 get_random_bytes(&r
, 2);
751 ieee80211_iterate_nodes(&vap
->iv_ic
->ic_sta
, mesh_checkid
, &r
);
753 } while (r
== 0 && maxiter
> 0);
758 * Verifies if we already received this packet by checking its
760 * Returns 0 if the frame is to be accepted, 1 otherwise.
763 mesh_checkpseq(struct ieee80211vap
*vap
,
764 const uint8_t source
[IEEE80211_ADDR_LEN
], uint32_t seq
)
766 struct ieee80211_mesh_route
*rt
;
768 rt
= ieee80211_mesh_rt_find(vap
, source
);
770 rt
= ieee80211_mesh_rt_add(vap
, source
);
772 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, source
,
773 "%s", "add mcast route failed");
774 vap
->iv_stats
.is_mesh_rtaddfailed
++;
777 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, source
,
778 "add mcast route, mesh seqno %d", seq
);
779 rt
->rt_lastmseq
= seq
;
782 if (IEEE80211_MESH_SEQ_GEQ(rt
->rt_lastmseq
, seq
)) {
785 rt
->rt_lastmseq
= seq
;
791 * Iterate the routing table and locate the next hop.
793 static struct ieee80211_node
*
794 mesh_find_txnode(struct ieee80211vap
*vap
,
795 const uint8_t dest
[IEEE80211_ADDR_LEN
])
797 struct ieee80211_mesh_route
*rt
;
799 rt
= ieee80211_mesh_rt_find(vap
, dest
);
802 if ((rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_VALID
) == 0 ||
803 (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
)) {
804 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_MESH
, dest
,
805 "%s: !valid or proxy, flags 0x%x", __func__
, rt
->rt_flags
);
809 return ieee80211_find_txnode(vap
, rt
->rt_nexthop
);
813 * Forward the specified frame.
814 * Decrement the TTL and set TA to our MAC address.
817 mesh_forward(struct ieee80211vap
*vap
, struct mbuf
*m
,
818 const struct ieee80211_meshcntl
*mc
)
820 struct ieee80211com
*ic
= vap
->iv_ic
;
821 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
822 struct ifnet
*ifp
= vap
->iv_ifp
;
823 struct ifnet
*parent
= ic
->ic_ifp
;
824 const struct ieee80211_frame
*wh
=
825 mtod(m
, const struct ieee80211_frame
*);
827 struct ieee80211_meshcntl
*mccopy
;
828 struct ieee80211_frame
*whcopy
;
829 struct ieee80211_node
*ni
;
832 if (mc
->mc_ttl
== 0) {
833 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
834 "%s", "frame not fwd'd, ttl 0");
835 vap
->iv_stats
.is_mesh_fwd_ttl
++;
838 if (!(ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)) {
839 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
840 "%s", "frame not fwd'd, fwding disabled");
841 vap
->iv_stats
.is_mesh_fwd_disabled
++;
844 mcopy
= m_dup(m
, MB_DONTWAIT
);
846 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
847 "%s", "frame not fwd'd, cannot dup");
848 vap
->iv_stats
.is_mesh_fwd_nobuf
++;
852 mcopy
= m_pullup(mcopy
, ieee80211_hdrspace(ic
, wh
) +
853 sizeof(struct ieee80211_meshcntl
));
855 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
856 "%s", "frame not fwd'd, too short");
857 vap
->iv_stats
.is_mesh_fwd_tooshort
++;
862 whcopy
= mtod(mcopy
, struct ieee80211_frame
*);
863 mccopy
= (struct ieee80211_meshcntl
*)
864 (mtod(mcopy
, uint8_t *) + ieee80211_hdrspace(ic
, wh
));
865 /* XXX clear other bits? */
866 whcopy
->i_fc
[1] &= ~IEEE80211_FC1_RETRY
;
867 IEEE80211_ADDR_COPY(whcopy
->i_addr2
, vap
->iv_myaddr
);
868 if (IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
869 ni
= ieee80211_ref_node(vap
->iv_bss
);
870 mcopy
->m_flags
|= M_MCAST
;
872 ni
= mesh_find_txnode(vap
, whcopy
->i_addr3
);
874 IEEE80211_NOTE_FRAME(vap
, IEEE80211_MSG_MESH
, wh
,
875 "%s", "frame not fwd'd, no path");
876 vap
->iv_stats
.is_mesh_fwd_nopath
++;
880 IEEE80211_ADDR_COPY(whcopy
->i_addr1
, ni
->ni_macaddr
);
882 KASSERT(mccopy
->mc_ttl
> 0, ("%s called with wrong ttl", __func__
));
885 /* XXX calculate priority so drivers can find the tx queue */
886 M_WME_SETAC(mcopy
, WME_AC_BE
);
888 /* XXX do we know m_nextpkt is NULL? */
889 mcopy
->m_pkthdr
.rcvif
= (void *) ni
;
890 err
= ieee80211_handoff(parent
, mcopy
);
892 /* NB: IFQ_HANDOFF reclaims mbuf */
893 ieee80211_free_node(ni
);
900 mesh_decap(struct ieee80211vap
*vap
, struct mbuf
*m
, int hdrlen
, int meshdrlen
)
902 #define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
903 uint8_t b
[sizeof(struct ieee80211_qosframe_addr4
) +
904 sizeof(struct ieee80211_meshcntl_ae11
)];
905 const struct ieee80211_qosframe_addr4
*wh
;
906 const struct ieee80211_meshcntl_ae10
*mc
;
907 struct ether_header
*eh
;
911 if (m
->m_len
< hdrlen
+ sizeof(*llc
) &&
912 (m
= m_pullup(m
, hdrlen
+ sizeof(*llc
))) == NULL
) {
913 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_ANY
,
914 "discard data frame: %s", "m_pullup failed");
915 vap
->iv_stats
.is_rx_tooshort
++;
918 memcpy(b
, mtod(m
, caddr_t
), hdrlen
);
919 wh
= (const struct ieee80211_qosframe_addr4
*)&b
[0];
920 mc
= (const struct ieee80211_meshcntl_ae10
*)&b
[hdrlen
- meshdrlen
];
921 KASSERT(WHDIR(wh
) == IEEE80211_FC1_DIR_FROMDS
||
922 WHDIR(wh
) == IEEE80211_FC1_DIR_DSTODS
,
923 ("bogus dir, fc 0x%x:0x%x", wh
->i_fc
[0], wh
->i_fc
[1]));
925 llc
= (struct llc
*)(mtod(m
, caddr_t
) + hdrlen
);
926 if (llc
->llc_dsap
== LLC_SNAP_LSAP
&& llc
->llc_ssap
== LLC_SNAP_LSAP
&&
927 llc
->llc_control
== LLC_UI
&& llc
->llc_snap
.org_code
[0] == 0 &&
928 llc
->llc_snap
.org_code
[1] == 0 && llc
->llc_snap
.org_code
[2] == 0 &&
929 !(llc
->llc_snap
.ether_type
== htons(ETHERTYPE_IPX
))) {
930 m_adj(m
, hdrlen
+ sizeof(struct llc
) - sizeof(*eh
));
933 m_adj(m
, hdrlen
- sizeof(*eh
));
935 eh
= mtod(m
, struct ether_header
*);
936 ae
= mc
->mc_flags
& 3;
937 if (WHDIR(wh
) == IEEE80211_FC1_DIR_FROMDS
) {
938 IEEE80211_ADDR_COPY(eh
->ether_dhost
, wh
->i_addr1
);
940 IEEE80211_ADDR_COPY(eh
->ether_shost
, wh
->i_addr3
);
941 } else if (ae
== 1) {
942 IEEE80211_ADDR_COPY(eh
->ether_shost
, mc
->mc_addr4
);
944 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
945 (const struct ieee80211_frame
*)wh
, NULL
,
947 vap
->iv_stats
.is_mesh_badae
++;
953 IEEE80211_ADDR_COPY(eh
->ether_dhost
, wh
->i_addr3
);
954 IEEE80211_ADDR_COPY(eh
->ether_shost
, wh
->i_addr4
);
955 } else if (ae
== 2) {
956 IEEE80211_ADDR_COPY(eh
->ether_dhost
, mc
->mc_addr4
);
957 IEEE80211_ADDR_COPY(eh
->ether_shost
, mc
->mc_addr5
);
959 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
960 (const struct ieee80211_frame
*)wh
, NULL
,
962 vap
->iv_stats
.is_mesh_badae
++;
967 #ifdef ALIGNED_POINTER
968 if (!ALIGNED_POINTER(mtod(m
, caddr_t
) + sizeof(*eh
), uint32_t)) {
969 m
= ieee80211_realign(vap
, m
, sizeof(*eh
));
973 #endif /* ALIGNED_POINTER */
975 eh
= mtod(m
, struct ether_header
*);
976 eh
->ether_type
= htons(m
->m_pkthdr
.len
- sizeof(*eh
));
983 * Return non-zero if the unicast mesh data frame should be processed
984 * locally. Frames that are not proxy'd have our address, otherwise
985 * we need to consult the routing table to look for a proxy entry.
988 mesh_isucastforme(struct ieee80211vap
*vap
, const struct ieee80211_frame
*wh
,
989 const struct ieee80211_meshcntl
*mc
)
991 int ae
= mc
->mc_flags
& 3;
993 KASSERT((wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
) == IEEE80211_FC1_DIR_DSTODS
,
994 ("bad dir 0x%x:0x%x", wh
->i_fc
[0], wh
->i_fc
[1]));
995 KASSERT(ae
== 0 || ae
== 2, ("bad AE %d", ae
));
996 if (ae
== 2) { /* ucast w/ proxy */
997 const struct ieee80211_meshcntl_ae10
*mc10
=
998 (const struct ieee80211_meshcntl_ae10
*) mc
;
999 struct ieee80211_mesh_route
*rt
=
1000 ieee80211_mesh_rt_find(vap
, mc10
->mc_addr4
);
1001 /* check for proxy route to ourself */
1002 return (rt
!= NULL
&&
1003 (rt
->rt_flags
& IEEE80211_MESHRT_FLAGS_PROXY
));
1004 } else /* ucast w/o proxy */
1005 return IEEE80211_ADDR_EQ(wh
->i_addr3
, vap
->iv_myaddr
);
1009 mesh_input(struct ieee80211_node
*ni
, struct mbuf
*m
, int rssi
, int nf
)
1011 #define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
1012 #define HAS_SEQ(type) ((type & 0x4) == 0)
1013 struct ieee80211vap
*vap
= ni
->ni_vap
;
1014 struct ieee80211com
*ic
= ni
->ni_ic
;
1015 struct ifnet
*ifp
= vap
->iv_ifp
;
1016 struct ieee80211_frame
*wh
;
1017 const struct ieee80211_meshcntl
*mc
;
1018 int hdrspace
, meshdrlen
, need_tap
;
1019 uint8_t dir
, type
, subtype
, qos
;
1022 ieee80211_seq rxseq
;
1024 KASSERT(ni
!= NULL
, ("null node"));
1025 ni
->ni_inact
= ni
->ni_inact_reload
;
1027 need_tap
= 1; /* mbuf need to be tapped. */
1028 type
= -1; /* undefined */
1030 if (m
->m_pkthdr
.len
< sizeof(struct ieee80211_frame_min
)) {
1031 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1032 ni
->ni_macaddr
, NULL
,
1033 "too short (1): len %u", m
->m_pkthdr
.len
);
1034 vap
->iv_stats
.is_rx_tooshort
++;
1038 * Bit of a cheat here, we use a pointer for a 3-address
1039 * frame format but don't reference fields past outside
1040 * ieee80211_frame_min w/o first validating the data is
1043 wh
= mtod(m
, struct ieee80211_frame
*);
1045 if ((wh
->i_fc
[0] & IEEE80211_FC0_VERSION_MASK
) !=
1046 IEEE80211_FC0_VERSION_0
) {
1047 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1048 ni
->ni_macaddr
, NULL
, "wrong version %x", wh
->i_fc
[0]);
1049 vap
->iv_stats
.is_rx_badversion
++;
1052 dir
= wh
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
;
1053 type
= wh
->i_fc
[0] & IEEE80211_FC0_TYPE_MASK
;
1054 subtype
= wh
->i_fc
[0] & IEEE80211_FC0_SUBTYPE_MASK
;
1055 if ((ic
->ic_flags
& IEEE80211_F_SCAN
) == 0) {
1056 IEEE80211_RSSI_LPF(ni
->ni_avgrssi
, rssi
);
1058 if (HAS_SEQ(type
)) {
1059 uint8_t tid
= ieee80211_gettid(wh
);
1061 if (IEEE80211_QOS_HAS_SEQ(wh
) &&
1062 TID_TO_WME_AC(tid
) >= WME_AC_VI
)
1063 ic
->ic_wme
.wme_hipri_traffic
++;
1064 rxseq
= le16toh(*(uint16_t *)wh
->i_seq
);
1065 if ((ni
->ni_flags
& IEEE80211_NODE_HT
) == 0 &&
1066 (wh
->i_fc
[1] & IEEE80211_FC1_RETRY
) &&
1067 SEQ_LEQ(rxseq
, ni
->ni_rxseqs
[tid
])) {
1068 /* duplicate, discard */
1069 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_INPUT
,
1070 wh
->i_addr1
, "duplicate",
1071 "seqno <%u,%u> fragno <%u,%u> tid %u",
1072 rxseq
>> IEEE80211_SEQ_SEQ_SHIFT
,
1073 ni
->ni_rxseqs
[tid
] >>
1074 IEEE80211_SEQ_SEQ_SHIFT
,
1075 rxseq
& IEEE80211_SEQ_FRAG_MASK
,
1076 ni
->ni_rxseqs
[tid
] &
1077 IEEE80211_SEQ_FRAG_MASK
,
1079 vap
->iv_stats
.is_rx_dup
++;
1080 IEEE80211_NODE_STAT(ni
, rx_dup
);
1083 ni
->ni_rxseqs
[tid
] = rxseq
;
1086 #ifdef IEEE80211_DEBUG
1088 * It's easier, but too expensive, to simulate different mesh
1089 * topologies by consulting the ACL policy very early, so do this
1092 * NB: this check is also done upon peering link initiation.
1094 if (vap
->iv_acl
!= NULL
&& !vap
->iv_acl
->iac_check(vap
, wh
->i_addr2
)) {
1095 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ACL
,
1096 wh
, NULL
, "%s", "disallowed by ACL");
1097 vap
->iv_stats
.is_rx_acl
++;
1102 case IEEE80211_FC0_TYPE_DATA
:
1103 if (ni
== vap
->iv_bss
)
1105 if (ni
->ni_mlstate
!= IEEE80211_NODE_MESH_ESTABLISHED
) {
1106 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_MESH
,
1107 ni
->ni_macaddr
, NULL
,
1108 "peer link not yet established (%d)",
1110 vap
->iv_stats
.is_mesh_nolink
++;
1113 if (dir
!= IEEE80211_FC1_DIR_FROMDS
&&
1114 dir
!= IEEE80211_FC1_DIR_DSTODS
) {
1115 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1116 wh
, "data", "incorrect dir 0x%x", dir
);
1117 vap
->iv_stats
.is_rx_wrongdir
++;
1120 /* pull up enough to get to the mesh control */
1121 hdrspace
= ieee80211_hdrspace(ic
, wh
);
1122 if (m
->m_len
< hdrspace
+ sizeof(struct ieee80211_meshcntl
) &&
1123 (m
= m_pullup(m
, hdrspace
+
1124 sizeof(struct ieee80211_meshcntl
))) == NULL
) {
1125 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1126 ni
->ni_macaddr
, NULL
,
1127 "data too short: expecting %u", hdrspace
);
1128 vap
->iv_stats
.is_rx_tooshort
++;
1132 * Now calculate the full extent of the headers. Note
1133 * mesh_decap will pull up anything we didn't get
1134 * above when it strips the 802.11 headers.
1136 mc
= (const struct ieee80211_meshcntl
*)
1137 (mtod(m
, const uint8_t *) + hdrspace
);
1138 meshdrlen
= sizeof(struct ieee80211_meshcntl
) +
1139 (mc
->mc_flags
& 3) * IEEE80211_ADDR_LEN
;
1140 hdrspace
+= meshdrlen
;
1141 seq
= LE_READ_4(mc
->mc_seq
);
1142 if (IEEE80211_IS_MULTICAST(wh
->i_addr1
))
1145 addr
= ((struct ieee80211_qosframe_addr4
*)wh
)->i_addr4
;
1146 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, addr
)) {
1147 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_INPUT
,
1148 addr
, "data", "%s", "not to me");
1149 vap
->iv_stats
.is_rx_wrongbss
++; /* XXX kinda */
1152 if (mesh_checkpseq(vap
, addr
, seq
) != 0) {
1153 vap
->iv_stats
.is_rx_dup
++;
1158 * Potentially forward packet. See table s36 (p140)
1159 * for the rules. XXX tap fwd'd packets not for us?
1161 if (dir
== IEEE80211_FC1_DIR_FROMDS
||
1162 !mesh_isucastforme(vap
, wh
, mc
)) {
1163 mesh_forward(vap
, m
, mc
);
1164 if (dir
== IEEE80211_FC1_DIR_DSTODS
)
1166 /* NB: fall thru to deliver mcast frames locally */
1170 * Save QoS bits for use below--before we strip the header.
1172 if (subtype
== IEEE80211_FC0_SUBTYPE_QOS
) {
1173 qos
= (dir
== IEEE80211_FC1_DIR_DSTODS
) ?
1174 ((struct ieee80211_qosframe_addr4
*)wh
)->i_qos
[0] :
1175 ((struct ieee80211_qosframe
*)wh
)->i_qos
[0];
1179 * Next up, any fragmentation.
1181 if (!IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
1182 m
= ieee80211_defrag(ni
, m
, hdrspace
);
1184 /* Fragment dropped or frame not complete yet */
1188 wh
= NULL
; /* no longer valid, catch any uses */
1190 if (ieee80211_radiotap_active_vap(vap
))
1191 ieee80211_radiotap_rx(vap
, m
);
1195 * Finally, strip the 802.11 header.
1197 m
= mesh_decap(vap
, m
, hdrspace
, meshdrlen
);
1199 /* XXX mask bit to check for both */
1200 /* don't count Null data frames as errors */
1201 if (subtype
== IEEE80211_FC0_SUBTYPE_NODATA
||
1202 subtype
== IEEE80211_FC0_SUBTYPE_QOS_NULL
)
1204 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_INPUT
,
1205 ni
->ni_macaddr
, "data", "%s", "decap error");
1206 vap
->iv_stats
.is_rx_decap
++;
1207 IEEE80211_NODE_STAT(ni
, rx_decap
);
1210 if (qos
& IEEE80211_QOS_AMSDU
) {
1211 m
= ieee80211_decap_amsdu(ni
, m
);
1213 return IEEE80211_FC0_TYPE_DATA
;
1215 ieee80211_deliver_data(vap
, ni
, m
);
1217 case IEEE80211_FC0_TYPE_MGT
:
1218 vap
->iv_stats
.is_rx_mgmt
++;
1219 IEEE80211_NODE_STAT(ni
, rx_mgmt
);
1220 if (dir
!= IEEE80211_FC1_DIR_NODS
) {
1221 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1222 wh
, "mgt", "incorrect dir 0x%x", dir
);
1223 vap
->iv_stats
.is_rx_wrongdir
++;
1226 if (m
->m_pkthdr
.len
< sizeof(struct ieee80211_frame
)) {
1227 IEEE80211_DISCARD_MAC(vap
, IEEE80211_MSG_ANY
,
1228 ni
->ni_macaddr
, "mgt", "too short: len %u",
1230 vap
->iv_stats
.is_rx_tooshort
++;
1233 #ifdef IEEE80211_DEBUG
1234 if ((ieee80211_msg_debug(vap
) &&
1235 (vap
->iv_ic
->ic_flags
& IEEE80211_F_SCAN
)) ||
1236 ieee80211_msg_dumppkts(vap
)) {
1237 if_printf(ifp
, "received %s from %6D rssi %d\n",
1238 ieee80211_mgt_subtype_name
[subtype
>>
1239 IEEE80211_FC0_SUBTYPE_SHIFT
],
1240 wh
->i_addr2
, ":", rssi
);
1243 if (wh
->i_fc
[1] & IEEE80211_FC1_WEP
) {
1244 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1245 wh
, NULL
, "%s", "WEP set but not permitted");
1246 vap
->iv_stats
.is_rx_mgtdiscard
++; /* XXX */
1249 vap
->iv_recv_mgmt(ni
, m
, subtype
, rssi
, nf
);
1251 case IEEE80211_FC0_TYPE_CTL
:
1252 vap
->iv_stats
.is_rx_ctl
++;
1253 IEEE80211_NODE_STAT(ni
, rx_ctrl
);
1256 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
1257 wh
, "bad", "frame type 0x%x", type
);
1258 /* should not come here */
1265 if (need_tap
&& ieee80211_radiotap_active_vap(vap
))
1266 ieee80211_radiotap_rx(vap
, m
);
1273 mesh_recv_mgmt(struct ieee80211_node
*ni
, struct mbuf
*m0
, int subtype
,
1276 struct ieee80211vap
*vap
= ni
->ni_vap
;
1277 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
1278 struct ieee80211com
*ic
= ni
->ni_ic
;
1279 struct ieee80211_frame
*wh
;
1280 uint8_t *frm
, *efrm
;
1282 wh
= mtod(m0
, struct ieee80211_frame
*);
1283 frm
= (uint8_t *)&wh
[1];
1284 efrm
= mtod(m0
, uint8_t *) + m0
->m_len
;
1286 case IEEE80211_FC0_SUBTYPE_PROBE_RESP
:
1287 case IEEE80211_FC0_SUBTYPE_BEACON
:
1289 struct ieee80211_scanparams scan
;
1291 * We process beacon/probe response
1292 * frames to discover neighbors.
1294 if (ieee80211_parse_beacon(ni
, m0
, &scan
) != 0)
1297 * Count frame now that we know it's to be processed.
1299 if (subtype
== IEEE80211_FC0_SUBTYPE_BEACON
) {
1300 vap
->iv_stats
.is_rx_beacon
++; /* XXX remove */
1301 IEEE80211_NODE_STAT(ni
, rx_beacons
);
1303 IEEE80211_NODE_STAT(ni
, rx_proberesp
);
1305 * If scanning, just pass information to the scan module.
1307 if (ic
->ic_flags
& IEEE80211_F_SCAN
) {
1308 if (ic
->ic_flags_ext
& IEEE80211_FEXT_PROBECHAN
) {
1310 * Actively scanning a channel marked passive;
1311 * send a probe request now that we know there
1312 * is 802.11 traffic present.
1314 * XXX check if the beacon we recv'd gives
1315 * us what we need and suppress the probe req
1317 ieee80211_probe_curchan(vap
, 1);
1318 ic
->ic_flags_ext
&= ~IEEE80211_FEXT_PROBECHAN
;
1320 ieee80211_add_scan(vap
, &scan
, wh
,
1325 /* The rest of this code assumes we are running */
1326 if (vap
->iv_state
!= IEEE80211_S_RUN
)
1329 * Ignore non-mesh STAs.
1332 (IEEE80211_CAPINFO_ESS
|IEEE80211_CAPINFO_IBSS
)) ||
1333 scan
.meshid
== NULL
|| scan
.meshconf
== NULL
) {
1334 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1335 wh
, "beacon", "%s", "not a mesh sta");
1336 vap
->iv_stats
.is_mesh_wrongmesh
++;
1340 * Ignore STAs for other mesh networks.
1342 if (memcmp(scan
.meshid
+2, ms
->ms_id
, ms
->ms_idlen
) != 0 ||
1343 mesh_verify_meshconf(vap
, scan
.meshconf
)) {
1344 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1345 wh
, "beacon", "%s", "not for our mesh");
1346 vap
->iv_stats
.is_mesh_wrongmesh
++;
1350 * Peer only based on the current ACL policy.
1352 if (vap
->iv_acl
!= NULL
&&
1353 !vap
->iv_acl
->iac_check(vap
, wh
->i_addr2
)) {
1354 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ACL
,
1355 wh
, NULL
, "%s", "disallowed by ACL");
1356 vap
->iv_stats
.is_rx_acl
++;
1360 * Do neighbor discovery.
1362 if (!IEEE80211_ADDR_EQ(wh
->i_addr2
, ni
->ni_macaddr
)) {
1364 * Create a new entry in the neighbor table.
1366 ni
= ieee80211_add_neighbor(vap
, wh
, &scan
);
1369 * Automatically peer with discovered nodes if possible.
1370 * XXX backoff on repeated failure
1372 if (ni
!= vap
->iv_bss
&&
1373 (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
) &&
1374 ni
->ni_mlstate
== IEEE80211_NODE_MESH_IDLE
) {
1377 ni
->ni_mlpid
= mesh_generateid(vap
);
1378 if (ni
->ni_mlpid
== 0)
1380 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENSNT
);
1381 args
[0] = ni
->ni_mlpid
;
1382 ieee80211_send_action(ni
,
1383 IEEE80211_ACTION_CAT_MESHPEERING
,
1384 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
1386 mesh_peer_timeout_setup(ni
);
1390 case IEEE80211_FC0_SUBTYPE_PROBE_REQ
:
1392 uint8_t *ssid
, *meshid
, *rates
, *xrates
;
1395 if (vap
->iv_state
!= IEEE80211_S_RUN
) {
1396 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1397 wh
, NULL
, "wrong state %s",
1398 ieee80211_state_name
[vap
->iv_state
]);
1399 vap
->iv_stats
.is_rx_mgtdiscard
++;
1402 if (IEEE80211_IS_MULTICAST(wh
->i_addr2
)) {
1403 /* frame must be directed */
1404 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1405 wh
, NULL
, "%s", "not unicast");
1406 vap
->iv_stats
.is_rx_mgtdiscard
++; /* XXX stat */
1410 * prreq frame format
1412 * [tlv] supported rates
1413 * [tlv] extended supported rates
1416 ssid
= meshid
= rates
= xrates
= NULL
;
1418 while (efrm
- frm
> 1) {
1419 IEEE80211_VERIFY_LENGTH(efrm
- frm
, frm
[1] + 2, return);
1421 case IEEE80211_ELEMID_SSID
:
1424 case IEEE80211_ELEMID_RATES
:
1427 case IEEE80211_ELEMID_XRATES
:
1430 case IEEE80211_ELEMID_MESHID
:
1436 IEEE80211_VERIFY_ELEMENT(ssid
, IEEE80211_NWID_LEN
, return);
1437 IEEE80211_VERIFY_ELEMENT(rates
, IEEE80211_RATE_MAXSIZE
, return);
1439 IEEE80211_VERIFY_ELEMENT(xrates
,
1440 IEEE80211_RATE_MAXSIZE
- rates
[1], return);
1441 if (meshid
!= NULL
) {
1442 IEEE80211_VERIFY_ELEMENT(meshid
,
1443 IEEE80211_MESHID_LEN
, return);
1444 /* NB: meshid, not ssid */
1445 IEEE80211_VERIFY_SSID(vap
->iv_bss
, meshid
, return);
1448 /* XXX find a better class or define it's own */
1449 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_INPUT
, wh
->i_addr2
,
1450 "%s", "recv probe req");
1452 * Some legacy 11b clients cannot hack a complete
1453 * probe response frame. When the request includes
1454 * only a bare-bones rate set, communicate this to
1455 * the transmit side.
1457 ieee80211_send_proberesp(vap
, wh
->i_addr2
, 0);
1460 case IEEE80211_FC0_SUBTYPE_ACTION
:
1461 if (vap
->iv_state
!= IEEE80211_S_RUN
) {
1462 vap
->iv_stats
.is_rx_mgtdiscard
++;
1466 * We received an action for an unknown neighbor.
1467 * XXX: wait for it to beacon or create ieee80211_node?
1469 if (ni
== vap
->iv_bss
) {
1470 IEEE80211_DISCARD(vap
, IEEE80211_MSG_MESH
,
1471 wh
, NULL
, "%s", "unknown node");
1472 vap
->iv_stats
.is_rx_mgtdiscard
++;
1476 * Discard if not for us.
1478 if (!IEEE80211_ADDR_EQ(vap
->iv_myaddr
, wh
->i_addr1
) &&
1479 !IEEE80211_IS_MULTICAST(wh
->i_addr1
)) {
1480 IEEE80211_DISCARD(vap
, IEEE80211_MSG_MESH
,
1481 wh
, NULL
, "%s", "not for me");
1482 vap
->iv_stats
.is_rx_mgtdiscard
++;
1485 /* XXX parse_action is a bit useless now */
1486 if (ieee80211_parse_action(ni
, m0
) == 0)
1487 ic
->ic_recv_action(ni
, wh
, frm
, efrm
);
1489 case IEEE80211_FC0_SUBTYPE_AUTH
:
1490 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ
:
1491 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ
:
1492 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP
:
1493 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP
:
1494 case IEEE80211_FC0_SUBTYPE_DEAUTH
:
1495 case IEEE80211_FC0_SUBTYPE_DISASSOC
:
1496 IEEE80211_DISCARD(vap
, IEEE80211_MSG_INPUT
,
1497 wh
, NULL
, "%s", "not handled");
1498 vap
->iv_stats
.is_rx_mgtdiscard
++;
1501 IEEE80211_DISCARD(vap
, IEEE80211_MSG_ANY
,
1502 wh
, "mgt", "subtype 0x%x not handled", subtype
);
1503 vap
->iv_stats
.is_rx_badsubtype
++;
1509 * Parse meshpeering action ie's for open+confirm frames; the
1510 * important bits are returned in the supplied structure.
1512 static const struct ieee80211_meshpeer_ie
*
1513 mesh_parse_meshpeering_action(struct ieee80211_node
*ni
,
1514 const struct ieee80211_frame
*wh
, /* XXX for VERIFY_LENGTH */
1515 const uint8_t *frm
, const uint8_t *efrm
,
1516 struct ieee80211_meshpeer_ie
*mp
, uint8_t subtype
)
1518 struct ieee80211vap
*vap
= ni
->ni_vap
;
1519 const struct ieee80211_meshpeer_ie
*mpie
;
1520 const uint8_t *meshid
, *meshconf
, *meshpeer
;
1522 meshid
= meshconf
= meshpeer
= NULL
;
1523 while (efrm
- frm
> 1) {
1524 IEEE80211_VERIFY_LENGTH(efrm
- frm
, frm
[1] + 2, return NULL
);
1526 case IEEE80211_ELEMID_MESHID
:
1529 case IEEE80211_ELEMID_MESHCONF
:
1532 case IEEE80211_ELEMID_MESHPEER
:
1534 mpie
= (const struct ieee80211_meshpeer_ie
*) frm
;
1535 memset(mp
, 0, sizeof(*mp
));
1536 mp
->peer_llinkid
= LE_READ_2(&mpie
->peer_llinkid
);
1537 /* NB: peer link ID is optional on these frames */
1538 if (subtype
== IEEE80211_MESH_PEER_LINK_CLOSE
&&
1539 mpie
->peer_len
== 8) {
1540 mp
->peer_linkid
= 0;
1541 mp
->peer_rcode
= LE_READ_2(&mpie
->peer_linkid
);
1543 mp
->peer_linkid
= LE_READ_2(&mpie
->peer_linkid
);
1544 mp
->peer_rcode
= LE_READ_2(&mpie
->peer_rcode
);
1552 * Verify the contents of the frame. Action frames with
1553 * close subtype don't have a Mesh Configuration IE.
1554 * If if fails validation, close the peer link.
1556 KASSERT(meshpeer
!= NULL
&&
1557 subtype
!= IEEE80211_ACTION_MESHPEERING_CLOSE
,
1558 ("parsing close action"));
1560 if (mesh_verify_meshid(vap
, meshid
) ||
1561 mesh_verify_meshpeer(vap
, subtype
, meshpeer
) ||
1562 mesh_verify_meshconf(vap
, meshconf
)) {
1565 IEEE80211_DISCARD(vap
,
1566 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
1567 wh
, NULL
, "%s", "not for our mesh");
1568 vap
->iv_stats
.is_rx_mgtdiscard
++;
1569 switch (ni
->ni_mlstate
) {
1570 case IEEE80211_NODE_MESH_IDLE
:
1571 case IEEE80211_NODE_MESH_ESTABLISHED
:
1572 case IEEE80211_NODE_MESH_HOLDING
:
1575 case IEEE80211_NODE_MESH_OPENSNT
:
1576 case IEEE80211_NODE_MESH_OPENRCV
:
1577 case IEEE80211_NODE_MESH_CONFIRMRCV
:
1578 args
[0] = ni
->ni_mlpid
;
1579 args
[1] = ni
->ni_mllid
;
1580 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
1581 ieee80211_send_action(ni
,
1582 IEEE80211_ACTION_CAT_MESHPEERING
,
1583 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1585 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
1586 mesh_peer_timeout_setup(ni
);
1591 return (const struct ieee80211_meshpeer_ie
*) mp
;
1595 mesh_recv_action_meshpeering_open(struct ieee80211_node
*ni
,
1596 const struct ieee80211_frame
*wh
,
1597 const uint8_t *frm
, const uint8_t *efrm
)
1599 struct ieee80211vap
*vap
= ni
->ni_vap
;
1600 struct ieee80211_meshpeer_ie ie
;
1601 const struct ieee80211_meshpeer_ie
*meshpeer
;
1604 /* +2+2 for action + code + capabilites */
1605 meshpeer
= mesh_parse_meshpeering_action(ni
, wh
, frm
+2+2, efrm
, &ie
,
1606 IEEE80211_ACTION_MESHPEERING_OPEN
);
1607 if (meshpeer
== NULL
) {
1612 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
1613 "recv PEER OPEN, lid 0x%x", meshpeer
->peer_llinkid
);
1615 switch (ni
->ni_mlstate
) {
1616 case IEEE80211_NODE_MESH_IDLE
:
1617 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENRCV
);
1618 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
1619 ni
->ni_mlpid
= mesh_generateid(vap
);
1620 if (ni
->ni_mlpid
== 0)
1622 args
[0] = ni
->ni_mlpid
;
1623 /* Announce we're open too... */
1624 ieee80211_send_action(ni
,
1625 IEEE80211_ACTION_CAT_MESHPEERING
,
1626 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
1627 /* ...and confirm the link. */
1628 args
[0] = ni
->ni_mlpid
;
1629 args
[1] = ni
->ni_mllid
;
1630 ieee80211_send_action(ni
,
1631 IEEE80211_ACTION_CAT_MESHPEERING
,
1632 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
1634 mesh_peer_timeout_setup(ni
);
1636 case IEEE80211_NODE_MESH_OPENRCV
:
1638 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
1639 args
[0] = ni
->ni_mllid
;
1640 args
[1] = ni
->ni_mlpid
;
1641 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
1642 ieee80211_send_action(ni
,
1643 IEEE80211_ACTION_CAT_MESHPEERING
,
1644 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1646 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
1647 mesh_peer_timeout_setup(ni
);
1650 /* Duplicate open, confirm again. */
1651 args
[0] = ni
->ni_mlpid
;
1652 args
[1] = ni
->ni_mllid
;
1653 ieee80211_send_action(ni
,
1654 IEEE80211_ACTION_CAT_MESHPEERING
,
1655 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
1658 case IEEE80211_NODE_MESH_OPENSNT
:
1659 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
1660 mesh_linkchange(ni
, IEEE80211_NODE_MESH_OPENRCV
);
1661 args
[0] = ni
->ni_mlpid
;
1662 args
[1] = ni
->ni_mllid
;
1663 ieee80211_send_action(ni
,
1664 IEEE80211_ACTION_CAT_MESHPEERING
,
1665 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
1667 /* NB: don't setup/clear any timeout */
1669 case IEEE80211_NODE_MESH_CONFIRMRCV
:
1670 if (ni
->ni_mlpid
!= meshpeer
->peer_linkid
||
1671 ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
1672 args
[0] = ni
->ni_mlpid
;
1673 args
[1] = ni
->ni_mllid
;
1674 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
1675 ieee80211_send_action(ni
,
1676 IEEE80211_ACTION_CAT_MESHPEERING
,
1677 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1680 IEEE80211_NODE_MESH_HOLDING
);
1681 mesh_peer_timeout_setup(ni
);
1684 mesh_linkchange(ni
, IEEE80211_NODE_MESH_ESTABLISHED
);
1685 ni
->ni_mllid
= meshpeer
->peer_llinkid
;
1686 args
[0] = ni
->ni_mlpid
;
1687 args
[1] = ni
->ni_mllid
;
1688 ieee80211_send_action(ni
,
1689 IEEE80211_ACTION_CAT_MESHPEERING
,
1690 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
1692 mesh_peer_timeout_stop(ni
);
1694 case IEEE80211_NODE_MESH_ESTABLISHED
:
1695 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
1696 args
[0] = ni
->ni_mllid
;
1697 args
[1] = ni
->ni_mlpid
;
1698 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
1699 ieee80211_send_action(ni
,
1700 IEEE80211_ACTION_CAT_MESHPEERING
,
1701 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1703 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
1704 mesh_peer_timeout_setup(ni
);
1707 args
[0] = ni
->ni_mlpid
;
1708 args
[1] = ni
->ni_mllid
;
1709 ieee80211_send_action(ni
,
1710 IEEE80211_ACTION_CAT_MESHPEERING
,
1711 IEEE80211_ACTION_MESHPEERING_CONFIRM
,
1714 case IEEE80211_NODE_MESH_HOLDING
:
1715 args
[0] = ni
->ni_mlpid
;
1716 args
[1] = meshpeer
->peer_llinkid
;
1717 args
[2] = IEEE80211_REASON_MESH_MAX_RETRIES
;
1718 ieee80211_send_action(ni
,
1719 IEEE80211_ACTION_CAT_MESHPEERING
,
1720 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1728 mesh_recv_action_meshpeering_confirm(struct ieee80211_node
*ni
,
1729 const struct ieee80211_frame
*wh
,
1730 const uint8_t *frm
, const uint8_t *efrm
)
1732 struct ieee80211vap
*vap
= ni
->ni_vap
;
1733 struct ieee80211_meshpeer_ie ie
;
1734 const struct ieee80211_meshpeer_ie
*meshpeer
;
1737 /* +2+2+2+2 for action + code + capabilites + status code + AID */
1738 meshpeer
= mesh_parse_meshpeering_action(ni
, wh
, frm
+2+2+2+2, efrm
, &ie
,
1739 IEEE80211_ACTION_MESHPEERING_CONFIRM
);
1740 if (meshpeer
== NULL
) {
1744 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
1745 "recv PEER CONFIRM, local id 0x%x, peer id 0x%x",
1746 meshpeer
->peer_llinkid
, meshpeer
->peer_linkid
);
1748 switch (ni
->ni_mlstate
) {
1749 case IEEE80211_NODE_MESH_OPENRCV
:
1750 mesh_linkchange(ni
, IEEE80211_NODE_MESH_ESTABLISHED
);
1751 mesh_peer_timeout_stop(ni
);
1753 case IEEE80211_NODE_MESH_OPENSNT
:
1754 mesh_linkchange(ni
, IEEE80211_NODE_MESH_CONFIRMRCV
);
1756 case IEEE80211_NODE_MESH_HOLDING
:
1757 args
[0] = ni
->ni_mlpid
;
1758 args
[1] = meshpeer
->peer_llinkid
;
1759 args
[2] = IEEE80211_REASON_MESH_MAX_RETRIES
;
1760 ieee80211_send_action(ni
,
1761 IEEE80211_ACTION_CAT_MESHPEERING
,
1762 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1765 case IEEE80211_NODE_MESH_CONFIRMRCV
:
1766 if (ni
->ni_mllid
!= meshpeer
->peer_llinkid
) {
1767 args
[0] = ni
->ni_mlpid
;
1768 args
[1] = ni
->ni_mllid
;
1769 args
[2] = IEEE80211_REASON_PEER_LINK_CANCELED
;
1770 ieee80211_send_action(ni
,
1771 IEEE80211_ACTION_CAT_MESHPEERING
,
1772 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1774 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
1775 mesh_peer_timeout_setup(ni
);
1779 IEEE80211_DISCARD(vap
,
1780 IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
1781 wh
, NULL
, "received confirm in invalid state %d",
1783 vap
->iv_stats
.is_rx_mgtdiscard
++;
1790 mesh_recv_action_meshpeering_close(struct ieee80211_node
*ni
,
1791 const struct ieee80211_frame
*wh
,
1792 const uint8_t *frm
, const uint8_t *efrm
)
1796 IEEE80211_NOTE(ni
->ni_vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
,
1797 ni
, "%s", "recv PEER CLOSE");
1799 switch (ni
->ni_mlstate
) {
1800 case IEEE80211_NODE_MESH_IDLE
:
1803 case IEEE80211_NODE_MESH_OPENRCV
:
1804 case IEEE80211_NODE_MESH_OPENSNT
:
1805 case IEEE80211_NODE_MESH_CONFIRMRCV
:
1806 case IEEE80211_NODE_MESH_ESTABLISHED
:
1807 args
[0] = ni
->ni_mlpid
;
1808 args
[1] = ni
->ni_mllid
;
1809 args
[2] = IEEE80211_REASON_MESH_CLOSE_RCVD
;
1810 ieee80211_send_action(ni
,
1811 IEEE80211_ACTION_CAT_MESHPEERING
,
1812 IEEE80211_ACTION_MESHPEERING_CLOSE
,
1814 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
1815 mesh_peer_timeout_setup(ni
);
1817 case IEEE80211_NODE_MESH_HOLDING
:
1818 mesh_linkchange(ni
, IEEE80211_NODE_MESH_IDLE
);
1819 mesh_peer_timeout_setup(ni
);
1826 * Link Metric handling.
1829 mesh_recv_action_meshlmetric_req(struct ieee80211_node
*ni
,
1830 const struct ieee80211_frame
*wh
,
1831 const uint8_t *frm
, const uint8_t *efrm
)
1835 metric
= mesh_airtime_calc(ni
);
1836 ieee80211_send_action(ni
,
1837 IEEE80211_ACTION_CAT_MESHLMETRIC
,
1838 IEEE80211_ACTION_MESHLMETRIC_REP
,
1844 mesh_recv_action_meshlmetric_rep(struct ieee80211_node
*ni
,
1845 const struct ieee80211_frame
*wh
,
1846 const uint8_t *frm
, const uint8_t *efrm
)
1852 mesh_send_action(struct ieee80211_node
*ni
, struct mbuf
*m
)
1854 struct ieee80211_bpf_params params
;
1856 memset(¶ms
, 0, sizeof(params
));
1857 params
.ibp_pri
= WME_AC_VO
;
1858 params
.ibp_rate0
= ni
->ni_txparms
->mgmtrate
;
1859 /* XXX ucast/mcast */
1860 params
.ibp_try0
= ni
->ni_txparms
->maxretry
;
1861 params
.ibp_power
= ni
->ni_txpower
;
1862 return ieee80211_mgmt_output(ni
, m
, IEEE80211_FC0_SUBTYPE_ACTION
,
1866 #define ADDSHORT(frm, v) do { \
1867 frm[0] = (v) & 0xff; \
1868 frm[1] = (v) >> 8; \
1871 #define ADDWORD(frm, v) do { \
1872 frm[0] = (v) & 0xff; \
1873 frm[1] = ((v) >> 8) & 0xff; \
1874 frm[2] = ((v) >> 16) & 0xff; \
1875 frm[3] = ((v) >> 24) & 0xff; \
1880 mesh_send_action_meshpeering_open(struct ieee80211_node
*ni
,
1881 int category
, int action
, void *args0
)
1883 struct ieee80211vap
*vap
= ni
->ni_vap
;
1884 struct ieee80211com
*ic
= ni
->ni_ic
;
1885 uint16_t *args
= args0
;
1886 const struct ieee80211_rateset
*rs
;
1890 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
1891 "send PEER OPEN action: localid 0x%x", args
[0]);
1893 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
1894 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__
, __LINE__
,
1895 ni
, ni
->ni_macaddr
, ":", ieee80211_node_refcnt(ni
)+1);
1896 ieee80211_ref_node(ni
);
1898 m
= ieee80211_getmgtframe(&frm
,
1899 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
1900 sizeof(uint16_t) /* action+category */
1901 + sizeof(uint16_t) /* capabilites */
1902 + 2 + IEEE80211_RATE_SIZE
1903 + 2 + (IEEE80211_RATE_MAXSIZE
- IEEE80211_RATE_SIZE
)
1904 + 2 + IEEE80211_MESHID_LEN
1905 + sizeof(struct ieee80211_meshconf_ie
)
1906 + sizeof(struct ieee80211_meshpeer_ie
)
1910 * mesh peer open action frame format:
1918 * [tlv] mesh peer link mgmt
1922 ADDSHORT(frm
, ieee80211_getcapinfo(vap
, ni
->ni_chan
));
1923 rs
= ieee80211_get_suprates(ic
, ic
->ic_curchan
);
1924 frm
= ieee80211_add_rates(frm
, rs
);
1925 frm
= ieee80211_add_xrates(frm
, rs
);
1926 frm
= ieee80211_add_meshid(frm
, vap
);
1927 frm
= ieee80211_add_meshconf(frm
, vap
);
1928 frm
= ieee80211_add_meshpeer(frm
, IEEE80211_MESH_PEER_LINK_OPEN
,
1930 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
1931 return mesh_send_action(ni
, m
);
1933 vap
->iv_stats
.is_tx_nobuf
++;
1934 ieee80211_free_node(ni
);
1940 mesh_send_action_meshpeering_confirm(struct ieee80211_node
*ni
,
1941 int category
, int action
, void *args0
)
1943 struct ieee80211vap
*vap
= ni
->ni_vap
;
1944 struct ieee80211com
*ic
= ni
->ni_ic
;
1945 uint16_t *args
= args0
;
1946 const struct ieee80211_rateset
*rs
;
1950 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
1951 "send PEER CONFIRM action: localid 0x%x, peerid 0x%x",
1954 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
1955 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__
, __LINE__
,
1956 ni
, ni
->ni_macaddr
, ":", ieee80211_node_refcnt(ni
)+1);
1957 ieee80211_ref_node(ni
);
1959 m
= ieee80211_getmgtframe(&frm
,
1960 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
1961 sizeof(uint16_t) /* action+category */
1962 + sizeof(uint16_t) /* capabilites */
1963 + sizeof(uint16_t) /* status code */
1964 + sizeof(uint16_t) /* AID */
1965 + 2 + IEEE80211_RATE_SIZE
1966 + 2 + (IEEE80211_RATE_MAXSIZE
- IEEE80211_RATE_SIZE
)
1967 + 2 + IEEE80211_MESHID_LEN
1968 + sizeof(struct ieee80211_meshconf_ie
)
1969 + sizeof(struct ieee80211_meshpeer_ie
)
1973 * mesh peer confirm action frame format:
1978 * [2] association id (peer ID)
1983 * [tlv] mesh peer link mgmt
1987 ADDSHORT(frm
, ieee80211_getcapinfo(vap
, ni
->ni_chan
));
1988 ADDSHORT(frm
, 0); /* status code */
1989 ADDSHORT(frm
, args
[1]); /* AID */
1990 rs
= ieee80211_get_suprates(ic
, ic
->ic_curchan
);
1991 frm
= ieee80211_add_rates(frm
, rs
);
1992 frm
= ieee80211_add_xrates(frm
, rs
);
1993 frm
= ieee80211_add_meshid(frm
, vap
);
1994 frm
= ieee80211_add_meshconf(frm
, vap
);
1995 frm
= ieee80211_add_meshpeer(frm
,
1996 IEEE80211_MESH_PEER_LINK_CONFIRM
,
1997 args
[0], args
[1], 0);
1998 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
1999 return mesh_send_action(ni
, m
);
2001 vap
->iv_stats
.is_tx_nobuf
++;
2002 ieee80211_free_node(ni
);
2008 mesh_send_action_meshpeering_close(struct ieee80211_node
*ni
,
2009 int category
, int action
, void *args0
)
2011 struct ieee80211vap
*vap
= ni
->ni_vap
;
2012 struct ieee80211com
*ic
= ni
->ni_ic
;
2013 uint16_t *args
= args0
;
2017 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2018 "send PEER CLOSE action: localid 0x%x, peerid 0x%x reason %d",
2019 args
[0], args
[1], args
[2]);
2021 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2022 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__
, __LINE__
,
2023 ni
, ni
->ni_macaddr
, ":", ieee80211_node_refcnt(ni
)+1);
2024 ieee80211_ref_node(ni
);
2026 m
= ieee80211_getmgtframe(&frm
,
2027 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2028 sizeof(uint16_t) /* action+category */
2029 + sizeof(uint16_t) /* reason code */
2030 + 2 + IEEE80211_MESHID_LEN
2031 + sizeof(struct ieee80211_meshpeer_ie
)
2035 * mesh peer close action frame format:
2040 * [tlv] mesh peer link mgmt
2044 ADDSHORT(frm
, args
[2]); /* reason code */
2045 frm
= ieee80211_add_meshid(frm
, vap
);
2046 frm
= ieee80211_add_meshpeer(frm
,
2047 IEEE80211_MESH_PEER_LINK_CLOSE
,
2048 args
[0], args
[1], args
[2]);
2049 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2050 return mesh_send_action(ni
, m
);
2052 vap
->iv_stats
.is_tx_nobuf
++;
2053 ieee80211_free_node(ni
);
2059 mesh_send_action_meshlink_request(struct ieee80211_node
*ni
,
2060 int category
, int action
, void *arg0
)
2062 struct ieee80211vap
*vap
= ni
->ni_vap
;
2063 struct ieee80211com
*ic
= ni
->ni_ic
;
2067 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2068 "%s", "send LINK METRIC REQUEST action");
2070 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2071 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__
, __LINE__
,
2072 ni
, ni
->ni_macaddr
, ":", ieee80211_node_refcnt(ni
)+1);
2073 ieee80211_ref_node(ni
);
2075 m
= ieee80211_getmgtframe(&frm
,
2076 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2077 sizeof(uint16_t) /* action+category */
2081 * mesh link metric request
2087 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2088 return mesh_send_action(ni
, m
);
2090 vap
->iv_stats
.is_tx_nobuf
++;
2091 ieee80211_free_node(ni
);
2097 mesh_send_action_meshlink_reply(struct ieee80211_node
*ni
,
2098 int category
, int action
, void *args0
)
2100 struct ieee80211vap
*vap
= ni
->ni_vap
;
2101 struct ieee80211com
*ic
= ni
->ni_ic
;
2102 uint32_t *metric
= args0
;
2106 IEEE80211_NOTE(vap
, IEEE80211_MSG_ACTION
| IEEE80211_MSG_MESH
, ni
,
2107 "send LINK METRIC REPLY action: metric 0x%x", *metric
);
2109 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_NODE
,
2110 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__
, __LINE__
,
2111 ni
, ni
->ni_macaddr
, ":", ieee80211_node_refcnt(ni
)+1);
2112 ieee80211_ref_node(ni
);
2114 m
= ieee80211_getmgtframe(&frm
,
2115 ic
->ic_headroom
+ sizeof(struct ieee80211_frame
),
2116 sizeof(uint16_t) /* action+category */
2117 + sizeof(struct ieee80211_meshlmetric_ie
)
2121 * mesh link metric reply
2124 * [tlv] mesh link metric
2128 frm
= ieee80211_add_meshlmetric(frm
, *metric
);
2129 m
->m_pkthdr
.len
= m
->m_len
= frm
- mtod(m
, uint8_t *);
2130 return mesh_send_action(ni
, m
);
2132 vap
->iv_stats
.is_tx_nobuf
++;
2133 ieee80211_free_node(ni
);
2139 mesh_peer_timeout_setup(struct ieee80211_node
*ni
)
2141 switch (ni
->ni_mlstate
) {
2142 case IEEE80211_NODE_MESH_HOLDING
:
2143 ni
->ni_mltval
= ieee80211_mesh_holdingtimeout
;
2145 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2146 ni
->ni_mltval
= ieee80211_mesh_confirmtimeout
;
2148 case IEEE80211_NODE_MESH_IDLE
:
2152 ni
->ni_mltval
= ieee80211_mesh_retrytimeout
;
2155 if (ni
->ni_mltval
) {
2156 callout_reset(&ni
->ni_mltimer
, ni
->ni_mltval
,
2157 mesh_peer_timeout_callout
, ni
);
2162 * Same as above but backoffs timer statisically 50%.
2165 mesh_peer_timeout_backoff(struct ieee80211_node
*ni
)
2170 ni
->ni_mltval
+= r
% ni
->ni_mltval
;
2171 callout_reset(&ni
->ni_mltimer
, ni
->ni_mltval
,
2172 mesh_peer_timeout_callout
, ni
);
2175 static __inline
void
2176 mesh_peer_timeout_stop(struct ieee80211_node
*ni
)
2178 callout_stop(&ni
->ni_mltimer
);
2182 * Mesh Peer Link Management FSM timeout handling.
2185 mesh_peer_timeout_callout(void *arg
)
2187 struct ieee80211_node
*ni
= (struct ieee80211_node
*)arg
;
2190 wlan_serialize_enter();
2191 IEEE80211_NOTE(ni
->ni_vap
, IEEE80211_MSG_MESH
,
2192 ni
, "mesh link timeout, state %d, retry counter %d",
2193 ni
->ni_mlstate
, ni
->ni_mlrcnt
);
2195 switch (ni
->ni_mlstate
) {
2196 case IEEE80211_NODE_MESH_IDLE
:
2197 case IEEE80211_NODE_MESH_ESTABLISHED
:
2199 case IEEE80211_NODE_MESH_OPENSNT
:
2200 case IEEE80211_NODE_MESH_OPENRCV
:
2201 if (ni
->ni_mlrcnt
== ieee80211_mesh_maxretries
) {
2202 args
[0] = ni
->ni_mlpid
;
2203 args
[2] = IEEE80211_REASON_MESH_MAX_RETRIES
;
2204 ieee80211_send_action(ni
,
2205 IEEE80211_ACTION_CAT_MESHPEERING
,
2206 IEEE80211_ACTION_MESHPEERING_CLOSE
, args
);
2208 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2209 mesh_peer_timeout_setup(ni
);
2211 args
[0] = ni
->ni_mlpid
;
2212 ieee80211_send_action(ni
,
2213 IEEE80211_ACTION_CAT_MESHPEERING
,
2214 IEEE80211_ACTION_MESHPEERING_OPEN
, args
);
2216 mesh_peer_timeout_backoff(ni
);
2219 case IEEE80211_NODE_MESH_CONFIRMRCV
:
2220 if (ni
->ni_mlrcnt
== ieee80211_mesh_maxretries
) {
2221 args
[0] = ni
->ni_mlpid
;
2222 args
[2] = IEEE80211_REASON_MESH_CONFIRM_TIMEOUT
;
2223 ieee80211_send_action(ni
,
2224 IEEE80211_ACTION_CAT_MESHPEERING
,
2225 IEEE80211_ACTION_MESHPEERING_CLOSE
, args
);
2227 mesh_linkchange(ni
, IEEE80211_NODE_MESH_HOLDING
);
2228 mesh_peer_timeout_setup(ni
);
2231 mesh_peer_timeout_setup(ni
);
2234 case IEEE80211_NODE_MESH_HOLDING
:
2235 mesh_linkchange(ni
, IEEE80211_NODE_MESH_IDLE
);
2238 wlan_serialize_exit();
2242 mesh_verify_meshid(struct ieee80211vap
*vap
, const uint8_t *ie
)
2244 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2246 if (ie
== NULL
|| ie
[1] != ms
->ms_idlen
)
2248 return memcmp(ms
->ms_id
, ie
+ 2, ms
->ms_idlen
);
2252 * Check if we are using the same algorithms for this mesh.
2255 mesh_verify_meshconf(struct ieee80211vap
*vap
, const uint8_t *ie
)
2257 const struct ieee80211_meshconf_ie
*meshconf
=
2258 (const struct ieee80211_meshconf_ie
*) ie
;
2259 const struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2262 if (meshconf
== NULL
)
2264 if (meshconf
->conf_pselid
!= ms
->ms_ppath
->mpp_ie
) {
2265 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2266 "unknown path selection algorithm: 0x%x\n",
2267 meshconf
->conf_pselid
);
2270 if (meshconf
->conf_pmetid
!= ms
->ms_pmetric
->mpm_ie
) {
2271 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2272 "unknown path metric algorithm: 0x%x\n",
2273 meshconf
->conf_pmetid
);
2276 if (meshconf
->conf_ccid
!= 0) {
2277 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2278 "unknown congestion control algorithm: 0x%x\n",
2279 meshconf
->conf_ccid
);
2282 if (meshconf
->conf_syncid
!= IEEE80211_MESHCONF_SYNC_NEIGHOFF
) {
2283 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2284 "unknown sync algorithm: 0x%x\n",
2285 meshconf
->conf_syncid
);
2288 if (meshconf
->conf_authid
!= 0) {
2289 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2290 "unknown auth auth algorithm: 0x%x\n",
2291 meshconf
->conf_pselid
);
2294 /* NB: conf_cap is only read correctly here */
2295 cap
= LE_READ_2(&meshconf
->conf_cap
);
2296 /* Not accepting peers */
2297 if (!(cap
& IEEE80211_MESHCONF_CAP_AP
)) {
2298 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_MESH
,
2299 "not accepting peers: 0x%x\n", meshconf
->conf_cap
);
2306 mesh_verify_meshpeer(struct ieee80211vap
*vap
, uint8_t subtype
,
2309 const struct ieee80211_meshpeer_ie
*meshpeer
=
2310 (const struct ieee80211_meshpeer_ie
*) ie
;
2312 if (meshpeer
== NULL
|| meshpeer
->peer_len
< 6 ||
2313 meshpeer
->peer_len
> 10)
2316 case IEEE80211_MESH_PEER_LINK_OPEN
:
2317 if (meshpeer
->peer_len
!= 6)
2320 case IEEE80211_MESH_PEER_LINK_CONFIRM
:
2321 if (meshpeer
->peer_len
!= 8)
2324 case IEEE80211_MESH_PEER_LINK_CLOSE
:
2325 if (meshpeer
->peer_len
< 8)
2327 if (meshpeer
->peer_len
== 8 && meshpeer
->peer_linkid
!= 0)
2329 if (meshpeer
->peer_rcode
== 0)
2337 * Add a Mesh ID IE to a frame.
2340 ieee80211_add_meshid(uint8_t *frm
, struct ieee80211vap
*vap
)
2342 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2344 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a mbss vap"));
2346 *frm
++ = IEEE80211_ELEMID_MESHID
;
2347 *frm
++ = ms
->ms_idlen
;
2348 memcpy(frm
, ms
->ms_id
, ms
->ms_idlen
);
2349 return frm
+ ms
->ms_idlen
;
2353 * Add a Mesh Configuration IE to a frame.
2354 * For now just use HWMP routing, Airtime link metric, Null Congestion
2355 * Signaling, Null Sync Protocol and Null Authentication.
2358 ieee80211_add_meshconf(uint8_t *frm
, struct ieee80211vap
*vap
)
2360 const struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2363 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a MBSS vap"));
2365 *frm
++ = IEEE80211_ELEMID_MESHCONF
;
2366 *frm
++ = sizeof(struct ieee80211_meshconf_ie
) - 2;
2367 *frm
++ = ms
->ms_ppath
->mpp_ie
; /* path selection */
2368 *frm
++ = ms
->ms_pmetric
->mpm_ie
; /* link metric */
2369 *frm
++ = IEEE80211_MESHCONF_CC_DISABLED
;
2370 *frm
++ = IEEE80211_MESHCONF_SYNC_NEIGHOFF
;
2371 *frm
++ = IEEE80211_MESHCONF_AUTH_DISABLED
;
2372 /* NB: set the number of neighbors before the rest */
2373 *frm
= (ms
->ms_neighbors
> 15 ? 15 : ms
->ms_neighbors
) << 1;
2374 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_PORTAL
)
2375 *frm
|= IEEE80211_MESHCONF_FORM_MP
;
2378 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
)
2379 caps
|= IEEE80211_MESHCONF_CAP_AP
;
2380 if (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
)
2381 caps
|= IEEE80211_MESHCONF_CAP_FWRD
;
2382 ADDSHORT(frm
, caps
);
2387 * Add a Mesh Peer Management IE to a frame.
2390 ieee80211_add_meshpeer(uint8_t *frm
, uint8_t subtype
, uint16_t localid
,
2391 uint16_t peerid
, uint16_t reason
)
2393 /* XXX change for AH */
2394 static const uint8_t meshpeerproto
[4] = IEEE80211_MESH_PEER_PROTO
;
2396 KASSERT(localid
!= 0, ("localid == 0"));
2398 *frm
++ = IEEE80211_ELEMID_MESHPEER
;
2400 case IEEE80211_MESH_PEER_LINK_OPEN
:
2401 *frm
++ = 6; /* length */
2402 memcpy(frm
, meshpeerproto
, 4);
2404 ADDSHORT(frm
, localid
); /* local ID */
2406 case IEEE80211_MESH_PEER_LINK_CONFIRM
:
2407 KASSERT(peerid
!= 0, ("sending peer confirm without peer id"));
2408 *frm
++ = 8; /* length */
2409 memcpy(frm
, meshpeerproto
, 4);
2411 ADDSHORT(frm
, localid
); /* local ID */
2412 ADDSHORT(frm
, peerid
); /* peer ID */
2414 case IEEE80211_MESH_PEER_LINK_CLOSE
:
2416 *frm
++ = 10; /* length */
2418 *frm
++ = 8; /* length */
2419 memcpy(frm
, meshpeerproto
, 4);
2421 ADDSHORT(frm
, localid
); /* local ID */
2423 ADDSHORT(frm
, peerid
); /* peer ID */
2424 ADDSHORT(frm
, reason
);
2431 * Compute an Airtime Link Metric for the link with this node.
2433 * Based on Draft 3.0 spec (11B.10, p.149).
2436 * Max 802.11s overhead.
2438 #define IEEE80211_MESH_MAXOVERHEAD \
2439 (sizeof(struct ieee80211_qosframe_addr4) \
2440 + sizeof(struct ieee80211_meshcntl_ae11) \
2441 + sizeof(struct llc) \
2442 + IEEE80211_ADDR_LEN \
2443 + IEEE80211_WEP_IVLEN \
2444 + IEEE80211_WEP_KIDLEN \
2445 + IEEE80211_WEP_CRCLEN \
2446 + IEEE80211_WEP_MICLEN \
2447 + IEEE80211_CRC_LEN)
2449 mesh_airtime_calc(struct ieee80211_node
*ni
)
2452 #define S_FACTOR (2 * M_BITS)
2453 struct ieee80211com
*ic
= ni
->ni_ic
;
2454 struct ifnet
*ifp
= ni
->ni_vap
->iv_ifp
;
2455 static const int nbits
= 8192 << M_BITS
;
2456 uint32_t overhead
, rate
, errrate
;
2459 /* Time to transmit a frame */
2460 rate
= ni
->ni_txrate
;
2461 overhead
= ieee80211_compute_duration(ic
->ic_rt
,
2462 ifp
->if_mtu
+ IEEE80211_MESH_MAXOVERHEAD
, rate
, 0) << M_BITS
;
2463 /* Error rate in percentage */
2464 /* XXX assuming small failures are ok */
2465 errrate
= (((ifp
->if_oerrors
+
2466 ifp
->if_ierrors
) / 100) << M_BITS
) / 100;
2467 res
= (overhead
+ (nbits
/ rate
)) *
2468 ((1 << S_FACTOR
) / ((1 << M_BITS
) - errrate
));
2470 return (uint32_t)(res
>> S_FACTOR
);
2476 * Add a Mesh Link Metric report IE to a frame.
2479 ieee80211_add_meshlmetric(uint8_t *frm
, uint32_t metric
)
2481 *frm
++ = IEEE80211_ELEMID_MESHLINK
;
2483 ADDWORD(frm
, metric
);
2490 * Initialize any mesh-specific node state.
2493 ieee80211_mesh_node_init(struct ieee80211vap
*vap
, struct ieee80211_node
*ni
)
2495 ni
->ni_flags
|= IEEE80211_NODE_QOS
;
2496 callout_init_mp(&ni
->ni_mltimer
);
2500 * Cleanup any mesh-specific node state.
2503 ieee80211_mesh_node_cleanup(struct ieee80211_node
*ni
)
2505 struct ieee80211vap
*vap
= ni
->ni_vap
;
2506 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2508 callout_stop(&ni
->ni_mltimer
);
2509 /* NB: short-circuit callbacks after mesh_vdetach */
2510 if (vap
->iv_mesh
!= NULL
)
2511 ms
->ms_ppath
->mpp_peerdown(ni
);
2515 ieee80211_parse_meshid(struct ieee80211_node
*ni
, const uint8_t *ie
)
2517 ni
->ni_meshidlen
= ie
[1];
2518 memcpy(ni
->ni_meshid
, ie
+ 2, ie
[1]);
2522 * Setup mesh-specific node state on neighbor discovery.
2525 ieee80211_mesh_init_neighbor(struct ieee80211_node
*ni
,
2526 const struct ieee80211_frame
*wh
,
2527 const struct ieee80211_scanparams
*sp
)
2529 ieee80211_parse_meshid(ni
, sp
->meshid
);
2533 ieee80211_mesh_update_beacon(struct ieee80211vap
*vap
,
2534 struct ieee80211_beacon_offsets
*bo
)
2536 KASSERT(vap
->iv_opmode
== IEEE80211_M_MBSS
, ("not a MBSS vap"));
2538 if (isset(bo
->bo_flags
, IEEE80211_BEACON_MESHCONF
)) {
2539 (void)ieee80211_add_meshconf(bo
->bo_meshconf
, vap
);
2540 clrbit(bo
->bo_flags
, IEEE80211_BEACON_MESHCONF
);
2545 mesh_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2547 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2548 uint8_t tmpmeshid
[IEEE80211_NWID_LEN
];
2549 struct ieee80211_mesh_route
*rt
;
2550 struct ieee80211req_mesh_route
*imr
;
2555 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2559 switch (ireq
->i_type
) {
2560 case IEEE80211_IOC_MESH_ID
:
2561 ireq
->i_len
= ms
->ms_idlen
;
2562 memcpy(tmpmeshid
, ms
->ms_id
, ireq
->i_len
);
2563 error
= copyout(tmpmeshid
, ireq
->i_data
, ireq
->i_len
);
2565 case IEEE80211_IOC_MESH_AP
:
2566 ireq
->i_val
= (ms
->ms_flags
& IEEE80211_MESHFLAGS_AP
) != 0;
2568 case IEEE80211_IOC_MESH_FWRD
:
2569 ireq
->i_val
= (ms
->ms_flags
& IEEE80211_MESHFLAGS_FWD
) != 0;
2571 case IEEE80211_IOC_MESH_TTL
:
2572 ireq
->i_val
= ms
->ms_ttl
;
2574 case IEEE80211_IOC_MESH_RTCMD
:
2575 switch (ireq
->i_val
) {
2576 case IEEE80211_MESH_RTCMD_LIST
:
2578 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
2579 len
+= sizeof(*imr
);
2581 if (len
> ireq
->i_len
|| ireq
->i_len
< sizeof(*imr
)) {
2587 p
= kmalloc(len
, M_TEMP
, M_INTWAIT
| M_ZERO
);
2591 TAILQ_FOREACH(rt
, &ms
->ms_routes
, rt_next
) {
2594 imr
= (struct ieee80211req_mesh_route
*)
2596 imr
->imr_flags
= rt
->rt_flags
;
2597 IEEE80211_ADDR_COPY(imr
->imr_dest
,
2599 IEEE80211_ADDR_COPY(imr
->imr_nexthop
,
2601 imr
->imr_metric
= rt
->rt_metric
;
2602 imr
->imr_nhops
= rt
->rt_nhops
;
2603 imr
->imr_lifetime
= rt
->rt_lifetime
;
2604 imr
->imr_lastmseq
= rt
->rt_lastmseq
;
2605 off
+= sizeof(*imr
);
2607 error
= copyout(p
, (uint8_t *)ireq
->i_data
,
2611 case IEEE80211_MESH_RTCMD_FLUSH
:
2612 case IEEE80211_MESH_RTCMD_ADD
:
2613 case IEEE80211_MESH_RTCMD_DELETE
:
2619 case IEEE80211_IOC_MESH_PR_METRIC
:
2620 len
= strlen(ms
->ms_pmetric
->mpm_descr
);
2621 if (ireq
->i_len
< len
)
2624 error
= copyout(ms
->ms_pmetric
->mpm_descr
,
2625 (uint8_t *)ireq
->i_data
, len
);
2627 case IEEE80211_IOC_MESH_PR_PATH
:
2628 len
= strlen(ms
->ms_ppath
->mpp_descr
);
2629 if (ireq
->i_len
< len
)
2632 error
= copyout(ms
->ms_ppath
->mpp_descr
,
2633 (uint8_t *)ireq
->i_data
, len
);
2641 IEEE80211_IOCTL_GET(mesh
, mesh_ioctl_get80211
);
2644 mesh_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
2646 struct ieee80211_mesh_state
*ms
= vap
->iv_mesh
;
2647 uint8_t tmpmeshid
[IEEE80211_NWID_LEN
];
2648 uint8_t tmpaddr
[IEEE80211_ADDR_LEN
];
2649 char tmpproto
[IEEE80211_MESH_PROTO_DSZ
];
2652 if (vap
->iv_opmode
!= IEEE80211_M_MBSS
)
2656 switch (ireq
->i_type
) {
2657 case IEEE80211_IOC_MESH_ID
:
2658 if (ireq
->i_val
!= 0 || ireq
->i_len
> IEEE80211_MESHID_LEN
)
2660 error
= copyin(ireq
->i_data
, tmpmeshid
, ireq
->i_len
);
2663 memset(ms
->ms_id
, 0, IEEE80211_NWID_LEN
);
2664 ms
->ms_idlen
= ireq
->i_len
;
2665 memcpy(ms
->ms_id
, tmpmeshid
, ireq
->i_len
);
2668 case IEEE80211_IOC_MESH_AP
:
2670 ms
->ms_flags
|= IEEE80211_MESHFLAGS_AP
;
2672 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_AP
;
2675 case IEEE80211_IOC_MESH_FWRD
:
2677 ms
->ms_flags
|= IEEE80211_MESHFLAGS_FWD
;
2679 ms
->ms_flags
&= ~IEEE80211_MESHFLAGS_FWD
;
2681 case IEEE80211_IOC_MESH_TTL
:
2682 ms
->ms_ttl
= (uint8_t) ireq
->i_val
;
2684 case IEEE80211_IOC_MESH_RTCMD
:
2685 switch (ireq
->i_val
) {
2686 case IEEE80211_MESH_RTCMD_LIST
:
2688 case IEEE80211_MESH_RTCMD_FLUSH
:
2689 ieee80211_mesh_rt_flush(vap
);
2691 case IEEE80211_MESH_RTCMD_ADD
:
2692 if (IEEE80211_ADDR_EQ(vap
->iv_myaddr
, ireq
->i_data
) ||
2693 IEEE80211_ADDR_EQ(broadcastaddr
, ireq
->i_data
))
2695 error
= copyin(ireq
->i_data
, &tmpaddr
,
2696 IEEE80211_ADDR_LEN
);
2698 ieee80211_mesh_discover(vap
, tmpaddr
, NULL
);
2700 case IEEE80211_MESH_RTCMD_DELETE
:
2701 ieee80211_mesh_rt_del(vap
, ireq
->i_data
);
2707 case IEEE80211_IOC_MESH_PR_METRIC
:
2708 error
= copyin(ireq
->i_data
, tmpproto
, sizeof(tmpproto
));
2710 error
= mesh_select_proto_metric(vap
, tmpproto
);
2715 case IEEE80211_IOC_MESH_PR_PATH
:
2716 error
= copyin(ireq
->i_data
, tmpproto
, sizeof(tmpproto
));
2718 error
= mesh_select_proto_path(vap
, tmpproto
);
2728 IEEE80211_IOCTL_SET(mesh
, mesh_ioctl_set80211
);