18244a9baSAugustin Cavalier/*-
28244a9baSAugustin Cavalier * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
388c3c4faSAugustin Cavalier *
48244a9baSAugustin Cavalier * Copyright (c) 2009 The FreeBSD Foundation
58244a9baSAugustin Cavalier * All rights reserved.
68244a9baSAugustin Cavalier *
7293a2caeSAugustin Cavalier * This software was developed by Rui Paulo under sponsorship from the
88244a9baSAugustin Cavalier * FreeBSD Foundation.
98244a9baSAugustin Cavalier *
108244a9baSAugustin Cavalier * Redistribution and use in source and binary forms, with or without
118244a9baSAugustin Cavalier * modification, are permitted provided that the following conditions
128244a9baSAugustin Cavalier * are met:
138244a9baSAugustin Cavalier * 1. Redistributions of source code must retain the above copyright
148244a9baSAugustin Cavalier *    notice, this list of conditions and the following disclaimer.
158244a9baSAugustin Cavalier * 2. Redistributions in binary form must reproduce the above copyright
168244a9baSAugustin Cavalier *    notice, this list of conditions and the following disclaimer in the
178244a9baSAugustin Cavalier *    documentation and/or other materials provided with the distribution.
188244a9baSAugustin Cavalier *
198244a9baSAugustin Cavalier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
208244a9baSAugustin Cavalier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218244a9baSAugustin Cavalier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228244a9baSAugustin Cavalier * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
238244a9baSAugustin Cavalier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248244a9baSAugustin Cavalier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258244a9baSAugustin Cavalier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268244a9baSAugustin Cavalier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278244a9baSAugustin Cavalier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288244a9baSAugustin Cavalier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298244a9baSAugustin Cavalier * SUCH DAMAGE.
308244a9baSAugustin Cavalier */
31293a2caeSAugustin Cavalier#include <sys/cdefs.h>
32293a2caeSAugustin Cavalier#ifdef __FreeBSD__
338244a9baSAugustin Cavalier__FBSDID("$FreeBSD: releng/12.0/sys/net80211/ieee80211_mesh.c 326272 2017-11-27 15:23:17Z pfg $");
34293a2caeSAugustin Cavalier#endif
35293a2caeSAugustin Cavalier
36293a2caeSAugustin Cavalier/*
37293a2caeSAugustin Cavalier * IEEE 802.11s Mesh Point (MBSS) support.
38293a2caeSAugustin Cavalier *
39293a2caeSAugustin Cavalier * Based on March 2009, D3.0 802.11s draft spec.
40293a2caeSAugustin Cavalier */
41293a2caeSAugustin Cavalier#include "opt_inet.h"
42293a2caeSAugustin Cavalier#include "opt_wlan.h"
43293a2caeSAugustin Cavalier
44293a2caeSAugustin Cavalier#include <sys/param.h>
458244a9baSAugustin Cavalier#include <sys/systm.h>
468244a9baSAugustin Cavalier#include <sys/mbuf.h>
47293a2caeSAugustin Cavalier#include <sys/malloc.h>
48293a2caeSAugustin Cavalier#include <sys/kernel.h>
49293a2caeSAugustin Cavalier
50293a2caeSAugustin Cavalier#include <sys/socket.h>
51293a2caeSAugustin Cavalier#include <sys/sockio.h>
52293a2caeSAugustin Cavalier#include <sys/endian.h>
53293a2caeSAugustin Cavalier#include <sys/errno.h>
54293a2caeSAugustin Cavalier#include <sys/proc.h>
55293a2caeSAugustin Cavalier#include <sys/sysctl.h>
56293a2caeSAugustin Cavalier
57293a2caeSAugustin Cavalier#include <net/bpf.h>
58293a2caeSAugustin Cavalier#include <net/if.h>
59293a2caeSAugustin Cavalier#include <net/if_var.h>
60293a2caeSAugustin Cavalier#include <net/if_media.h>
61293a2caeSAugustin Cavalier#include <net/if_llc.h>
62293a2caeSAugustin Cavalier#include <net/ethernet.h>
63293a2caeSAugustin Cavalier
64293a2caeSAugustin Cavalier#include <net80211/ieee80211_var.h>
65293a2caeSAugustin Cavalier#include <net80211/ieee80211_action.h>
66293a2caeSAugustin Cavalier#ifdef IEEE80211_SUPPORT_SUPERG
67293a2caeSAugustin Cavalier#include <net80211/ieee80211_superg.h>
68293a2caeSAugustin Cavalier#endif
69293a2caeSAugustin Cavalier#include <net80211/ieee80211_input.h>
70293a2caeSAugustin Cavalier#include <net80211/ieee80211_mesh.h>
71293a2caeSAugustin Cavalier
72293a2caeSAugustin Cavalierstatic void	mesh_rt_flush_invalid(struct ieee80211vap *);
73293a2caeSAugustin Cavalierstatic int	mesh_select_proto_path(struct ieee80211vap *, const char *);
74293a2caeSAugustin Cavalierstatic int	mesh_select_proto_metric(struct ieee80211vap *, const char *);
75293a2caeSAugustin Cavalierstatic void	mesh_vattach(struct ieee80211vap *);
76293a2caeSAugustin Cavalierstatic int	mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
77293a2caeSAugustin Cavalierstatic void	mesh_rt_cleanup_cb(void *);
78293a2caeSAugustin Cavalierstatic void	mesh_gatemode_setup(struct ieee80211vap *);
79293a2caeSAugustin Cavalierstatic void	mesh_gatemode_cb(void *);
80293a2caeSAugustin Cavalierstatic void	mesh_linkchange(struct ieee80211_node *,
81293a2caeSAugustin Cavalier		    enum ieee80211_mesh_mlstate);
82293a2caeSAugustin Cavalierstatic void	mesh_checkid(void *, struct ieee80211_node *);
83293a2caeSAugustin Cavalierstatic uint32_t	mesh_generateid(struct ieee80211vap *);
84293a2caeSAugustin Cavalierstatic int	mesh_checkpseq(struct ieee80211vap *,
85293a2caeSAugustin Cavalier		    const uint8_t [IEEE80211_ADDR_LEN], uint32_t);
86293a2caeSAugustin Cavalierstatic void	mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
87293a2caeSAugustin Cavalier		    struct ieee80211_mesh_route *);
88293a2caeSAugustin Cavalierstatic void	mesh_forward(struct ieee80211vap *, struct mbuf *,
89293a2caeSAugustin Cavalier		    const struct ieee80211_meshcntl *);
90293a2caeSAugustin Cavalierstatic int	mesh_input(struct ieee80211_node *, struct mbuf *,
91293a2caeSAugustin Cavalier		    const struct ieee80211_rx_stats *rxs, int, int);
92293a2caeSAugustin Cavalierstatic void	mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
93293a2caeSAugustin Cavalier		    const struct ieee80211_rx_stats *rxs, int, int);
94293a2caeSAugustin Cavalierstatic void	mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
95293a2caeSAugustin Cavalierstatic void	mesh_peer_timeout_setup(struct ieee80211_node *);
96293a2caeSAugustin Cavalierstatic void	mesh_peer_timeout_backoff(struct ieee80211_node *);
97293a2caeSAugustin Cavalierstatic void	mesh_peer_timeout_cb(void *);
98293a2caeSAugustin Cavalierstatic __inline void
99293a2caeSAugustin Cavalier		mesh_peer_timeout_stop(struct ieee80211_node *);
100293a2caeSAugustin Cavalierstatic int	mesh_verify_meshid(struct ieee80211vap *, const uint8_t *);
101293a2caeSAugustin Cavalierstatic int	mesh_verify_meshconf(struct ieee80211vap *, const uint8_t *);
102293a2caeSAugustin Cavalierstatic int	mesh_verify_meshpeer(struct ieee80211vap *, uint8_t,
103293a2caeSAugustin Cavalier    		    const uint8_t *);
104293a2caeSAugustin Cavalieruint32_t	mesh_airtime_calc(struct ieee80211_node *);
105293a2caeSAugustin Cavalier
106293a2caeSAugustin Cavalier/*
107293a2caeSAugustin Cavalier * Timeout values come from the specification and are in milliseconds.
108293a2caeSAugustin Cavalier */
109293a2caeSAugustin Cavalierstatic SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0,
110293a2caeSAugustin Cavalier    "IEEE 802.11s parameters");
111293a2caeSAugustin Cavalierstatic int	ieee80211_mesh_gateint = -1;
112293a2caeSAugustin CavalierSYSCTL_PROC(_net_wlan_mesh, OID_AUTO, gateint, CTLTYPE_INT | CTLFLAG_RW,
113293a2caeSAugustin Cavalier    &ieee80211_mesh_gateint, 0, ieee80211_sysctl_msecs_ticks, "I",
114293a2caeSAugustin Cavalier    "mesh gate interval (ms)");
115293a2caeSAugustin Cavalierstatic int ieee80211_mesh_retrytimeout = -1;
116293a2caeSAugustin CavalierSYSCTL_PROC(_net_wlan_mesh, OID_AUTO, retrytimeout, CTLTYPE_INT | CTLFLAG_RW,
117293a2caeSAugustin Cavalier    &ieee80211_mesh_retrytimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
118293a2caeSAugustin Cavalier    "Retry timeout (msec)");
119293a2caeSAugustin Cavalierstatic int ieee80211_mesh_holdingtimeout = -1;
120293a2caeSAugustin Cavalier
121293a2caeSAugustin CavalierSYSCTL_PROC(_net_wlan_mesh, OID_AUTO, holdingtimeout, CTLTYPE_INT | CTLFLAG_RW,
122293a2caeSAugustin Cavalier    &ieee80211_mesh_holdingtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
123293a2caeSAugustin Cavalier    "Holding state timeout (msec)");
124293a2caeSAugustin Cavalierstatic int ieee80211_mesh_confirmtimeout = -1;
125293a2caeSAugustin CavalierSYSCTL_PROC(_net_wlan_mesh, OID_AUTO, confirmtimeout, CTLTYPE_INT | CTLFLAG_RW,
126293a2caeSAugustin Cavalier    &ieee80211_mesh_confirmtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
127293a2caeSAugustin Cavalier    "Confirm state timeout (msec)");
128293a2caeSAugustin Cavalierstatic int ieee80211_mesh_backofftimeout = -1;
129293a2caeSAugustin CavalierSYSCTL_PROC(_net_wlan_mesh, OID_AUTO, backofftimeout, CTLTYPE_INT | CTLFLAG_RW,
130293a2caeSAugustin Cavalier    &ieee80211_mesh_backofftimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
131293a2caeSAugustin Cavalier    "Backoff timeout (msec). This is to throutles peering forever when "
132293a2caeSAugustin Cavalier    "not receiving answer or is rejected by a neighbor");
133293a2caeSAugustin Cavalierstatic int ieee80211_mesh_maxretries = 2;
134293a2caeSAugustin CavalierSYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLFLAG_RW,
135293a2caeSAugustin Cavalier    &ieee80211_mesh_maxretries, 0,
136293a2caeSAugustin Cavalier    "Maximum retries during peer link establishment");
137293a2caeSAugustin Cavalierstatic int ieee80211_mesh_maxholding = 2;
138293a2caeSAugustin CavalierSYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxholding, CTLFLAG_RW,
139293a2caeSAugustin Cavalier    &ieee80211_mesh_maxholding, 0,
140293a2caeSAugustin Cavalier    "Maximum times we are allowed to transition to HOLDING state before "
141293a2caeSAugustin Cavalier    "backinoff during peer link establishment");
142293a2caeSAugustin Cavalier
143293a2caeSAugustin Cavalierstatic const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
144293a2caeSAugustin Cavalier	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
145293a2caeSAugustin Cavalier
146293a2caeSAugustin Cavalierstatic	ieee80211_recv_action_func mesh_recv_action_meshpeering_open;
147293a2caeSAugustin Cavalierstatic	ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm;
148293a2caeSAugustin Cavalierstatic	ieee80211_recv_action_func mesh_recv_action_meshpeering_close;
149293a2caeSAugustin Cavalierstatic	ieee80211_recv_action_func mesh_recv_action_meshlmetric;
150293a2caeSAugustin Cavalierstatic	ieee80211_recv_action_func mesh_recv_action_meshgate;
151293a2caeSAugustin Cavalier
152293a2caeSAugustin Cavalierstatic	ieee80211_send_action_func mesh_send_action_meshpeering_open;
153293a2caeSAugustin Cavalierstatic	ieee80211_send_action_func mesh_send_action_meshpeering_confirm;
154293a2caeSAugustin Cavalierstatic	ieee80211_send_action_func mesh_send_action_meshpeering_close;
155293a2caeSAugustin Cavalierstatic	ieee80211_send_action_func mesh_send_action_meshlmetric;
156293a2caeSAugustin Cavalierstatic	ieee80211_send_action_func mesh_send_action_meshgate;
157293a2caeSAugustin Cavalier
158293a2caeSAugustin Cavalierstatic const struct ieee80211_mesh_proto_metric mesh_metric_airtime = {
159293a2caeSAugustin Cavalier	.mpm_descr	= "AIRTIME",
160293a2caeSAugustin Cavalier	.mpm_ie		= IEEE80211_MESHCONF_METRIC_AIRTIME,
161293a2caeSAugustin Cavalier	.mpm_metric	= mesh_airtime_calc,
162293a2caeSAugustin Cavalier};
163293a2caeSAugustin Cavalier
164293a2caeSAugustin Cavalierstatic struct ieee80211_mesh_proto_path		mesh_proto_paths[4];
165293a2caeSAugustin Cavalierstatic struct ieee80211_mesh_proto_metric	mesh_proto_metrics[4];
166293a2caeSAugustin Cavalier
167293a2caeSAugustin CavalierMALLOC_DEFINE(M_80211_MESH_PREQ, "80211preq", "802.11 MESH Path Request frame");
168293a2caeSAugustin CavalierMALLOC_DEFINE(M_80211_MESH_PREP, "80211prep", "802.11 MESH Path Reply frame");
169293a2caeSAugustin CavalierMALLOC_DEFINE(M_80211_MESH_PERR, "80211perr", "802.11 MESH Path Error frame");
170293a2caeSAugustin Cavalier
171293a2caeSAugustin Cavalier/* The longer one of the lifetime should be stored as new lifetime */
172293a2caeSAugustin Cavalier#define MESH_ROUTE_LIFETIME_MAX(a, b)	(a > b ? a : b)
173293a2caeSAugustin Cavalier
174293a2caeSAugustin CavalierMALLOC_DEFINE(M_80211_MESH_RT, "80211mesh_rt", "802.11s routing table");
175293a2caeSAugustin CavalierMALLOC_DEFINE(M_80211_MESH_GT_RT, "80211mesh_gt", "802.11s known gates table");
176293a2caeSAugustin Cavalier
177293a2caeSAugustin Cavalier/*
178293a2caeSAugustin Cavalier * Helper functions to manipulate the Mesh routing table.
179293a2caeSAugustin Cavalier */
180293a2caeSAugustin Cavalier
181293a2caeSAugustin Cavalierstatic struct ieee80211_mesh_route *
182293a2caeSAugustin Cavaliermesh_rt_find_locked(struct ieee80211_mesh_state *ms,
183293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
184293a2caeSAugustin Cavalier{
185293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
186293a2caeSAugustin Cavalier
187293a2caeSAugustin Cavalier	MESH_RT_LOCK_ASSERT(ms);
188293a2caeSAugustin Cavalier
189293a2caeSAugustin Cavalier	TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
190293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(dest, rt->rt_dest))
191293a2caeSAugustin Cavalier			return rt;
192293a2caeSAugustin Cavalier	}
193293a2caeSAugustin Cavalier	return NULL;
194293a2caeSAugustin Cavalier}
195293a2caeSAugustin Cavalier
196293a2caeSAugustin Cavalierstatic struct ieee80211_mesh_route *
197293a2caeSAugustin Cavaliermesh_rt_add_locked(struct ieee80211vap *vap,
198293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
199293a2caeSAugustin Cavalier{
200293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
201293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
202293a2caeSAugustin Cavalier
203293a2caeSAugustin Cavalier	KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
204293a2caeSAugustin Cavalier	    ("%s: adding broadcast to the routing table", __func__));
205293a2caeSAugustin Cavalier
206293a2caeSAugustin Cavalier	MESH_RT_LOCK_ASSERT(ms);
207293a2caeSAugustin Cavalier
208293a2caeSAugustin Cavalier	rt = IEEE80211_MALLOC(ALIGN(sizeof(struct ieee80211_mesh_route)) +
209293a2caeSAugustin Cavalier	    ms->ms_ppath->mpp_privlen, M_80211_MESH_RT,
210293a2caeSAugustin Cavalier	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
211293a2caeSAugustin Cavalier	if (rt != NULL) {
212293a2caeSAugustin Cavalier		rt->rt_vap = vap;
213293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(rt->rt_dest, dest);
214293a2caeSAugustin Cavalier		rt->rt_priv = (void *)ALIGN(&rt[1]);
215293a2caeSAugustin Cavalier		MESH_RT_ENTRY_LOCK_INIT(rt, "MBSS_RT");
216293a2caeSAugustin Cavalier		callout_init(&rt->rt_discovery, 1);
217293a2caeSAugustin Cavalier		rt->rt_updtime = ticks;	/* create time */
218293a2caeSAugustin Cavalier		TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
219293a2caeSAugustin Cavalier	}
220293a2caeSAugustin Cavalier	return rt;
221293a2caeSAugustin Cavalier}
222293a2caeSAugustin Cavalier
223293a2caeSAugustin Cavalierstruct ieee80211_mesh_route *
224293a2caeSAugustin Cavalierieee80211_mesh_rt_find(struct ieee80211vap *vap,
225293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
226293a2caeSAugustin Cavalier{
227293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
228293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
229293a2caeSAugustin Cavalier
230293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
231293a2caeSAugustin Cavalier	rt = mesh_rt_find_locked(ms, dest);
232293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
233293a2caeSAugustin Cavalier	return rt;
234293a2caeSAugustin Cavalier}
235293a2caeSAugustin Cavalier
236293a2caeSAugustin Cavalierstruct ieee80211_mesh_route *
237293a2caeSAugustin Cavalierieee80211_mesh_rt_add(struct ieee80211vap *vap,
238293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
239293a2caeSAugustin Cavalier{
240293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
241293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
242293a2caeSAugustin Cavalier
243293a2caeSAugustin Cavalier	KASSERT(ieee80211_mesh_rt_find(vap, dest) == NULL,
244293a2caeSAugustin Cavalier	    ("%s: duplicate entry in the routing table", __func__));
245293a2caeSAugustin Cavalier	KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
246293a2caeSAugustin Cavalier	    ("%s: adding self to the routing table", __func__));
247293a2caeSAugustin Cavalier
248293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
249293a2caeSAugustin Cavalier	rt = mesh_rt_add_locked(vap, dest);
250293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
251293a2caeSAugustin Cavalier	return rt;
252293a2caeSAugustin Cavalier}
253293a2caeSAugustin Cavalier
254293a2caeSAugustin Cavalier/*
255293a2caeSAugustin Cavalier * Update the route lifetime and returns the updated lifetime.
256293a2caeSAugustin Cavalier * If new_lifetime is zero and route is timedout it will be invalidated.
257293a2caeSAugustin Cavalier * new_lifetime is in msec
258293a2caeSAugustin Cavalier */
259293a2caeSAugustin Cavalierint
260293a2caeSAugustin Cavalierieee80211_mesh_rt_update(struct ieee80211_mesh_route *rt, int new_lifetime)
261293a2caeSAugustin Cavalier{
262293a2caeSAugustin Cavalier	int timesince, now;
263293a2caeSAugustin Cavalier	uint32_t lifetime = 0;
264293a2caeSAugustin Cavalier
265293a2caeSAugustin Cavalier	KASSERT(rt != NULL, ("route is NULL"));
266293a2caeSAugustin Cavalier
267293a2caeSAugustin Cavalier	now = ticks;
268293a2caeSAugustin Cavalier	MESH_RT_ENTRY_LOCK(rt);
269293a2caeSAugustin Cavalier
270293a2caeSAugustin Cavalier	/* dont clobber a proxy entry gated by us */
271293a2caeSAugustin Cavalier	if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY && rt->rt_nhops == 0) {
272293a2caeSAugustin Cavalier		MESH_RT_ENTRY_UNLOCK(rt);
273293a2caeSAugustin Cavalier		return rt->rt_lifetime;
274293a2caeSAugustin Cavalier	}
275293a2caeSAugustin Cavalier
276293a2caeSAugustin Cavalier	timesince = ticks_to_msecs(now - rt->rt_updtime);
277293a2caeSAugustin Cavalier	rt->rt_updtime = now;
278293a2caeSAugustin Cavalier	if (timesince >= rt->rt_lifetime) {
279293a2caeSAugustin Cavalier		if (new_lifetime != 0) {
280293a2caeSAugustin Cavalier			rt->rt_lifetime = new_lifetime;
281293a2caeSAugustin Cavalier		}
282293a2caeSAugustin Cavalier		else {
283293a2caeSAugustin Cavalier			rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
284293a2caeSAugustin Cavalier			rt->rt_lifetime = 0;
285293a2caeSAugustin Cavalier		}
286293a2caeSAugustin Cavalier	} else {
287293a2caeSAugustin Cavalier		/* update what is left of lifetime */
288293a2caeSAugustin Cavalier		rt->rt_lifetime = rt->rt_lifetime - timesince;
289293a2caeSAugustin Cavalier		rt->rt_lifetime  = MESH_ROUTE_LIFETIME_MAX(
290293a2caeSAugustin Cavalier			new_lifetime, rt->rt_lifetime);
291293a2caeSAugustin Cavalier	}
292293a2caeSAugustin Cavalier	lifetime = rt->rt_lifetime;
293293a2caeSAugustin Cavalier	MESH_RT_ENTRY_UNLOCK(rt);
294293a2caeSAugustin Cavalier
295293a2caeSAugustin Cavalier	return lifetime;
296293a2caeSAugustin Cavalier}
297293a2caeSAugustin Cavalier
298293a2caeSAugustin Cavalier/*
299293a2caeSAugustin Cavalier * Add a proxy route (as needed) for the specified destination.
300293a2caeSAugustin Cavalier */
301293a2caeSAugustin Cavaliervoid
302293a2caeSAugustin Cavalierieee80211_mesh_proxy_check(struct ieee80211vap *vap,
303293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
304293a2caeSAugustin Cavalier{
305293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
306293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
307293a2caeSAugustin Cavalier
308293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
309293a2caeSAugustin Cavalier	rt = mesh_rt_find_locked(ms, dest);
310293a2caeSAugustin Cavalier	if (rt == NULL) {
311293a2caeSAugustin Cavalier		rt = mesh_rt_add_locked(vap, dest);
312293a2caeSAugustin Cavalier		if (rt == NULL) {
313293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
314293a2caeSAugustin Cavalier			    "%s", "unable to add proxy entry");
315293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_rtaddfailed++;
316293a2caeSAugustin Cavalier		} else {
317293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
318293a2caeSAugustin Cavalier			    "%s", "add proxy entry");
319293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(rt->rt_mesh_gate, vap->iv_myaddr);
320293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
321293a2caeSAugustin Cavalier			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
322293a2caeSAugustin Cavalier				     |  IEEE80211_MESHRT_FLAGS_PROXY;
323293a2caeSAugustin Cavalier		}
324293a2caeSAugustin Cavalier	} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
325293a2caeSAugustin Cavalier		KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
326293a2caeSAugustin Cavalier		    ("no proxy flag for poxy entry"));
327293a2caeSAugustin Cavalier		struct ieee80211com *ic = vap->iv_ic;
328293a2caeSAugustin Cavalier		/*
329293a2caeSAugustin Cavalier		 * Fix existing entry created by received frames from
330293a2caeSAugustin Cavalier		 * stations that have some memory of dest.  We also
331293a2caeSAugustin Cavalier		 * flush any frames held on the staging queue; delivering
332293a2caeSAugustin Cavalier		 * them is too much trouble right now.
333293a2caeSAugustin Cavalier		 */
334293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
335293a2caeSAugustin Cavalier		    "%s", "fix proxy entry");
336293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
337293a2caeSAugustin Cavalier		rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
338293a2caeSAugustin Cavalier			     |  IEEE80211_MESHRT_FLAGS_PROXY;
339293a2caeSAugustin Cavalier		/* XXX belongs in hwmp */
340293a2caeSAugustin Cavalier		ieee80211_ageq_drain_node(&ic->ic_stageq,
341293a2caeSAugustin Cavalier		   (void *)(uintptr_t) ieee80211_mac_hash(ic, dest));
342293a2caeSAugustin Cavalier		/* XXX stat? */
343293a2caeSAugustin Cavalier	}
344293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
345293a2caeSAugustin Cavalier}
346293a2caeSAugustin Cavalier
347293a2caeSAugustin Cavalierstatic __inline void
348293a2caeSAugustin Cavaliermesh_rt_del(struct ieee80211_mesh_state *ms, struct ieee80211_mesh_route *rt)
349293a2caeSAugustin Cavalier{
350293a2caeSAugustin Cavalier	TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
351293a2caeSAugustin Cavalier	/*
352293a2caeSAugustin Cavalier	 * Grab the lock before destroying it, to be sure no one else
353293a2caeSAugustin Cavalier	 * is holding the route.
354293a2caeSAugustin Cavalier	 */
355293a2caeSAugustin Cavalier	MESH_RT_ENTRY_LOCK(rt);
356293a2caeSAugustin Cavalier	callout_drain(&rt->rt_discovery);
357293a2caeSAugustin Cavalier	MESH_RT_ENTRY_LOCK_DESTROY(rt);
358293a2caeSAugustin Cavalier	IEEE80211_FREE(rt, M_80211_MESH_RT);
359293a2caeSAugustin Cavalier}
360293a2caeSAugustin Cavalier
361293a2caeSAugustin Cavaliervoid
362293a2caeSAugustin Cavalierieee80211_mesh_rt_del(struct ieee80211vap *vap,
363293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
364293a2caeSAugustin Cavalier{
365293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
366293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt, *next;
367293a2caeSAugustin Cavalier
368293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
369293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
370293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) {
371293a2caeSAugustin Cavalier			if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
372293a2caeSAugustin Cavalier				ms->ms_ppath->mpp_senderror(vap, dest, rt,
373293a2caeSAugustin Cavalier				    IEEE80211_REASON_MESH_PERR_NO_PROXY);
374293a2caeSAugustin Cavalier			} else {
375293a2caeSAugustin Cavalier				ms->ms_ppath->mpp_senderror(vap, dest, rt,
376293a2caeSAugustin Cavalier				    IEEE80211_REASON_MESH_PERR_DEST_UNREACH);
377293a2caeSAugustin Cavalier			}
378293a2caeSAugustin Cavalier			mesh_rt_del(ms, rt);
379293a2caeSAugustin Cavalier			MESH_RT_UNLOCK(ms);
380293a2caeSAugustin Cavalier			return;
381293a2caeSAugustin Cavalier		}
382293a2caeSAugustin Cavalier	}
383293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
384293a2caeSAugustin Cavalier}
385293a2caeSAugustin Cavalier
386293a2caeSAugustin Cavaliervoid
387293a2caeSAugustin Cavalierieee80211_mesh_rt_flush(struct ieee80211vap *vap)
388293a2caeSAugustin Cavalier{
389293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
390293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt, *next;
391293a2caeSAugustin Cavalier
392293a2caeSAugustin Cavalier	if (ms == NULL)
393293a2caeSAugustin Cavalier		return;
394293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
395293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next)
396293a2caeSAugustin Cavalier		mesh_rt_del(ms, rt);
397293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
398293a2caeSAugustin Cavalier}
399293a2caeSAugustin Cavalier
400293a2caeSAugustin Cavaliervoid
401293a2caeSAugustin Cavalierieee80211_mesh_rt_flush_peer(struct ieee80211vap *vap,
402293a2caeSAugustin Cavalier    const uint8_t peer[IEEE80211_ADDR_LEN])
403293a2caeSAugustin Cavalier{
404293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
405293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt, *next;
406293a2caeSAugustin Cavalier
407293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
408293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
409293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(rt->rt_nexthop, peer))
410293a2caeSAugustin Cavalier			mesh_rt_del(ms, rt);
411293a2caeSAugustin Cavalier	}
412293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
413293a2caeSAugustin Cavalier}
414293a2caeSAugustin Cavalier
415293a2caeSAugustin Cavalier/*
416293a2caeSAugustin Cavalier * Flush expired routing entries, i.e. those in invalid state for
417293a2caeSAugustin Cavalier * some time.
418293a2caeSAugustin Cavalier */
419293a2caeSAugustin Cavalierstatic void
420293a2caeSAugustin Cavaliermesh_rt_flush_invalid(struct ieee80211vap *vap)
421293a2caeSAugustin Cavalier{
422293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
423293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt, *next;
424293a2caeSAugustin Cavalier
425293a2caeSAugustin Cavalier	if (ms == NULL)
426293a2caeSAugustin Cavalier		return;
427293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
428293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
429293a2caeSAugustin Cavalier		/* Discover paths will be deleted by their own callout */
430293a2caeSAugustin Cavalier		if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER)
431293a2caeSAugustin Cavalier			continue;
432293a2caeSAugustin Cavalier		ieee80211_mesh_rt_update(rt, 0);
433293a2caeSAugustin Cavalier		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
434293a2caeSAugustin Cavalier			mesh_rt_del(ms, rt);
435293a2caeSAugustin Cavalier	}
436293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
437293a2caeSAugustin Cavalier}
438293a2caeSAugustin Cavalier
439293a2caeSAugustin Cavalierint
440293a2caeSAugustin Cavalierieee80211_mesh_register_proto_path(const struct ieee80211_mesh_proto_path *mpp)
441293a2caeSAugustin Cavalier{
442293a2caeSAugustin Cavalier	int i, firstempty = -1;
443293a2caeSAugustin Cavalier
444293a2caeSAugustin Cavalier	for (i = 0; i < nitems(mesh_proto_paths); i++) {
445293a2caeSAugustin Cavalier		if (strncmp(mpp->mpp_descr, mesh_proto_paths[i].mpp_descr,
446293a2caeSAugustin Cavalier		    IEEE80211_MESH_PROTO_DSZ) == 0)
447293a2caeSAugustin Cavalier			return EEXIST;
448293a2caeSAugustin Cavalier		if (!mesh_proto_paths[i].mpp_active && firstempty == -1)
449293a2caeSAugustin Cavalier			firstempty = i;
450293a2caeSAugustin Cavalier	}
451293a2caeSAugustin Cavalier	if (firstempty < 0)
452293a2caeSAugustin Cavalier		return ENOSPC;
453293a2caeSAugustin Cavalier	memcpy(&mesh_proto_paths[firstempty], mpp, sizeof(*mpp));
454293a2caeSAugustin Cavalier	mesh_proto_paths[firstempty].mpp_active = 1;
455293a2caeSAugustin Cavalier	return 0;
456293a2caeSAugustin Cavalier}
457293a2caeSAugustin Cavalier
458293a2caeSAugustin Cavalierint
459293a2caeSAugustin Cavalierieee80211_mesh_register_proto_metric(const struct
460293a2caeSAugustin Cavalier    ieee80211_mesh_proto_metric *mpm)
461293a2caeSAugustin Cavalier{
462293a2caeSAugustin Cavalier	int i, firstempty = -1;
463293a2caeSAugustin Cavalier
464293a2caeSAugustin Cavalier	for (i = 0; i < nitems(mesh_proto_metrics); i++) {
465293a2caeSAugustin Cavalier		if (strncmp(mpm->mpm_descr, mesh_proto_metrics[i].mpm_descr,
466293a2caeSAugustin Cavalier		    IEEE80211_MESH_PROTO_DSZ) == 0)
467293a2caeSAugustin Cavalier			return EEXIST;
468293a2caeSAugustin Cavalier		if (!mesh_proto_metrics[i].mpm_active && firstempty == -1)
469293a2caeSAugustin Cavalier			firstempty = i;
470293a2caeSAugustin Cavalier	}
471293a2caeSAugustin Cavalier	if (firstempty < 0)
472293a2caeSAugustin Cavalier		return ENOSPC;
473293a2caeSAugustin Cavalier	memcpy(&mesh_proto_metrics[firstempty], mpm, sizeof(*mpm));
474293a2caeSAugustin Cavalier	mesh_proto_metrics[firstempty].mpm_active = 1;
475293a2caeSAugustin Cavalier	return 0;
476293a2caeSAugustin Cavalier}
477293a2caeSAugustin Cavalier
478293a2caeSAugustin Cavalierstatic int
479293a2caeSAugustin Cavaliermesh_select_proto_path(struct ieee80211vap *vap, const char *name)
480293a2caeSAugustin Cavalier{
481293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
482293a2caeSAugustin Cavalier	int i;
483293a2caeSAugustin Cavalier
484293a2caeSAugustin Cavalier	for (i = 0; i < nitems(mesh_proto_paths); i++) {
485293a2caeSAugustin Cavalier		if (strcasecmp(mesh_proto_paths[i].mpp_descr, name) == 0) {
486293a2caeSAugustin Cavalier			ms->ms_ppath = &mesh_proto_paths[i];
487293a2caeSAugustin Cavalier			return 0;
488293a2caeSAugustin Cavalier		}
489293a2caeSAugustin Cavalier	}
490293a2caeSAugustin Cavalier	return ENOENT;
491293a2caeSAugustin Cavalier}
492293a2caeSAugustin Cavalier
493293a2caeSAugustin Cavalierstatic int
494293a2caeSAugustin Cavaliermesh_select_proto_metric(struct ieee80211vap *vap, const char *name)
495293a2caeSAugustin Cavalier{
496293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
497293a2caeSAugustin Cavalier	int i;
498293a2caeSAugustin Cavalier
499293a2caeSAugustin Cavalier	for (i = 0; i < nitems(mesh_proto_metrics); i++) {
500293a2caeSAugustin Cavalier		if (strcasecmp(mesh_proto_metrics[i].mpm_descr, name) == 0) {
501293a2caeSAugustin Cavalier			ms->ms_pmetric = &mesh_proto_metrics[i];
502293a2caeSAugustin Cavalier			return 0;
503293a2caeSAugustin Cavalier		}
504293a2caeSAugustin Cavalier	}
505293a2caeSAugustin Cavalier	return ENOENT;
506293a2caeSAugustin Cavalier}
507293a2caeSAugustin Cavalier
508293a2caeSAugustin Cavalierstatic void
509293a2caeSAugustin Cavaliermesh_gatemode_setup(struct ieee80211vap *vap)
510293a2caeSAugustin Cavalier{
511293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
512293a2caeSAugustin Cavalier
513293a2caeSAugustin Cavalier	/*
514293a2caeSAugustin Cavalier	 * NB: When a mesh gate is running as a ROOT it shall
515293a2caeSAugustin Cavalier	 * not send out periodic GANNs but instead mark the
516293a2caeSAugustin Cavalier	 * mesh gate flag for the corresponding proactive PREQ
517293a2caeSAugustin Cavalier	 * and RANN frames.
518293a2caeSAugustin Cavalier	 */
519293a2caeSAugustin Cavalier	if (ms->ms_flags & IEEE80211_MESHFLAGS_ROOT ||
520293a2caeSAugustin Cavalier	    (ms->ms_flags & IEEE80211_MESHFLAGS_GATE) == 0) {
521293a2caeSAugustin Cavalier		callout_drain(&ms->ms_gatetimer);
522293a2caeSAugustin Cavalier		return ;
523293a2caeSAugustin Cavalier	}
524293a2caeSAugustin Cavalier	callout_reset(&ms->ms_gatetimer, ieee80211_mesh_gateint,
525293a2caeSAugustin Cavalier	    mesh_gatemode_cb, vap);
526293a2caeSAugustin Cavalier}
527293a2caeSAugustin Cavalier
528293a2caeSAugustin Cavalierstatic void
529293a2caeSAugustin Cavaliermesh_gatemode_cb(void *arg)
530293a2caeSAugustin Cavalier{
531293a2caeSAugustin Cavalier	struct ieee80211vap *vap = (struct ieee80211vap *)arg;
532293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
533293a2caeSAugustin Cavalier	struct ieee80211_meshgann_ie gann;
534293a2caeSAugustin Cavalier
535293a2caeSAugustin Cavalier	gann.gann_flags = 0; /* Reserved */
536293a2caeSAugustin Cavalier	gann.gann_hopcount = 0;
537293a2caeSAugustin Cavalier	gann.gann_ttl = ms->ms_ttl;
538293a2caeSAugustin Cavalier	IEEE80211_ADDR_COPY(gann.gann_addr, vap->iv_myaddr);
539293a2caeSAugustin Cavalier	gann.gann_seq = ms->ms_gateseq++;
540293a2caeSAugustin Cavalier	gann.gann_interval = ieee80211_mesh_gateint;
541293a2caeSAugustin Cavalier
542293a2caeSAugustin Cavalier	IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, vap->iv_bss,
543293a2caeSAugustin Cavalier	    "send broadcast GANN (seq %u)", gann.gann_seq);
544293a2caeSAugustin Cavalier
545293a2caeSAugustin Cavalier	ieee80211_send_action(vap->iv_bss, IEEE80211_ACTION_CAT_MESH,
546293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESH_GANN, &gann);
547293a2caeSAugustin Cavalier	mesh_gatemode_setup(vap);
548293a2caeSAugustin Cavalier}
549293a2caeSAugustin Cavalier
5508244a9baSAugustin Cavalierstatic void
551293a2caeSAugustin Cavalierieee80211_mesh_init(void)
552293a2caeSAugustin Cavalier{
553293a2caeSAugustin Cavalier
554293a2caeSAugustin Cavalier	memset(mesh_proto_paths, 0, sizeof(mesh_proto_paths));
555293a2caeSAugustin Cavalier	memset(mesh_proto_metrics, 0, sizeof(mesh_proto_metrics));
556293a2caeSAugustin Cavalier
557293a2caeSAugustin Cavalier	/*
558293a2caeSAugustin Cavalier	 * Setup mesh parameters that depends on the clock frequency.
559293a2caeSAugustin Cavalier	 */
560293a2caeSAugustin Cavalier	ieee80211_mesh_gateint = msecs_to_ticks(10000);
561293a2caeSAugustin Cavalier	ieee80211_mesh_retrytimeout = msecs_to_ticks(40);
562293a2caeSAugustin Cavalier	ieee80211_mesh_holdingtimeout = msecs_to_ticks(40);
563293a2caeSAugustin Cavalier	ieee80211_mesh_confirmtimeout = msecs_to_ticks(40);
564293a2caeSAugustin Cavalier	ieee80211_mesh_backofftimeout = msecs_to_ticks(5000);
565293a2caeSAugustin Cavalier
566293a2caeSAugustin Cavalier	/*
567293a2caeSAugustin Cavalier	 * Register action frame handlers.
568293a2caeSAugustin Cavalier	 */
569293a2caeSAugustin Cavalier	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
570293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_OPEN,
571293a2caeSAugustin Cavalier	    mesh_recv_action_meshpeering_open);
572293a2caeSAugustin Cavalier	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
573293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_CONFIRM,
574293a2caeSAugustin Cavalier	    mesh_recv_action_meshpeering_confirm);
575293a2caeSAugustin Cavalier	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
576293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_CLOSE,
577293a2caeSAugustin Cavalier	    mesh_recv_action_meshpeering_close);
578293a2caeSAugustin Cavalier	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
579293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESH_LMETRIC, mesh_recv_action_meshlmetric);
580293a2caeSAugustin Cavalier	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
581293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESH_GANN, mesh_recv_action_meshgate);
582293a2caeSAugustin Cavalier
583293a2caeSAugustin Cavalier	ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
584293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_OPEN,
585293a2caeSAugustin Cavalier	    mesh_send_action_meshpeering_open);
586293a2caeSAugustin Cavalier	ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
587293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_CONFIRM,
588293a2caeSAugustin Cavalier	    mesh_send_action_meshpeering_confirm);
589293a2caeSAugustin Cavalier	ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
590293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESHPEERING_CLOSE,
591293a2caeSAugustin Cavalier	    mesh_send_action_meshpeering_close);
592293a2caeSAugustin Cavalier	ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
593293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESH_LMETRIC,
594293a2caeSAugustin Cavalier	    mesh_send_action_meshlmetric);
595293a2caeSAugustin Cavalier	ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
596293a2caeSAugustin Cavalier	    IEEE80211_ACTION_MESH_GANN,
597293a2caeSAugustin Cavalier	    mesh_send_action_meshgate);
598293a2caeSAugustin Cavalier
599293a2caeSAugustin Cavalier	/*
600293a2caeSAugustin Cavalier	 * Register Airtime Link Metric.
601293a2caeSAugustin Cavalier	 */
602293a2caeSAugustin Cavalier	ieee80211_mesh_register_proto_metric(&mesh_metric_airtime);
603293a2caeSAugustin Cavalier
604293a2caeSAugustin Cavalier}
605293a2caeSAugustin CavalierSYSINIT(wlan_mesh, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_mesh_init, NULL);
606293a2caeSAugustin Cavalier
607293a2caeSAugustin Cavaliervoid
608293a2caeSAugustin Cavalierieee80211_mesh_attach(struct ieee80211com *ic)
609293a2caeSAugustin Cavalier{
610293a2caeSAugustin Cavalier	ic->ic_vattach[IEEE80211_M_MBSS] = mesh_vattach;
611293a2caeSAugustin Cavalier}
612293a2caeSAugustin Cavalier
613293a2caeSAugustin Cavaliervoid
614293a2caeSAugustin Cavalierieee80211_mesh_detach(struct ieee80211com *ic)
615293a2caeSAugustin Cavalier{
616293a2caeSAugustin Cavalier}
617293a2caeSAugustin Cavalier
618293a2caeSAugustin Cavalierstatic void
619293a2caeSAugustin Cavaliermesh_vdetach_peers(void *arg, struct ieee80211_node *ni)
620293a2caeSAugustin Cavalier{
621293a2caeSAugustin Cavalier	struct ieee80211com *ic = ni->ni_ic;
622293a2caeSAugustin Cavalier	uint16_t args[3];
623293a2caeSAugustin Cavalier
624293a2caeSAugustin Cavalier	if (ni->ni_mlstate == IEEE80211_NODE_MESH_ESTABLISHED) {
625293a2caeSAugustin Cavalier		args[0] = ni->ni_mlpid;
626293a2caeSAugustin Cavalier		args[1] = ni->ni_mllid;
627293a2caeSAugustin Cavalier		args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
628293a2caeSAugustin Cavalier		ieee80211_send_action(ni,
629293a2caeSAugustin Cavalier		    IEEE80211_ACTION_CAT_SELF_PROT,
630293a2caeSAugustin Cavalier		    IEEE80211_ACTION_MESHPEERING_CLOSE,
631293a2caeSAugustin Cavalier		    args);
632293a2caeSAugustin Cavalier	}
633293a2caeSAugustin Cavalier	callout_drain(&ni->ni_mltimer);
634293a2caeSAugustin Cavalier	/* XXX belongs in hwmp */
635293a2caeSAugustin Cavalier	ieee80211_ageq_drain_node(&ic->ic_stageq,
636293a2caeSAugustin Cavalier	   (void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr));
637293a2caeSAugustin Cavalier}
638293a2caeSAugustin Cavalier
639293a2caeSAugustin Cavalierstatic void
640293a2caeSAugustin Cavaliermesh_vdetach(struct ieee80211vap *vap)
641293a2caeSAugustin Cavalier{
642293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
643293a2caeSAugustin Cavalier
644293a2caeSAugustin Cavalier	callout_drain(&ms->ms_cleantimer);
645293a2caeSAugustin Cavalier	ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers,
646293a2caeSAugustin Cavalier	    NULL);
647293a2caeSAugustin Cavalier	ieee80211_mesh_rt_flush(vap);
648293a2caeSAugustin Cavalier	MESH_RT_LOCK_DESTROY(ms);
649293a2caeSAugustin Cavalier	ms->ms_ppath->mpp_vdetach(vap);
650293a2caeSAugustin Cavalier	IEEE80211_FREE(vap->iv_mesh, M_80211_VAP);
651293a2caeSAugustin Cavalier	vap->iv_mesh = NULL;
652293a2caeSAugustin Cavalier}
653293a2caeSAugustin Cavalier
654293a2caeSAugustin Cavalierstatic void
655293a2caeSAugustin Cavaliermesh_vattach(struct ieee80211vap *vap)
656293a2caeSAugustin Cavalier{
657293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms;
658293a2caeSAugustin Cavalier	vap->iv_newstate = mesh_newstate;
659293a2caeSAugustin Cavalier	vap->iv_input = mesh_input;
660293a2caeSAugustin Cavalier	vap->iv_opdetach = mesh_vdetach;
661293a2caeSAugustin Cavalier	vap->iv_recv_mgmt = mesh_recv_mgmt;
662293a2caeSAugustin Cavalier	vap->iv_recv_ctl = mesh_recv_ctl;
663293a2caeSAugustin Cavalier	ms = IEEE80211_MALLOC(sizeof(struct ieee80211_mesh_state), M_80211_VAP,
664293a2caeSAugustin Cavalier	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
665293a2caeSAugustin Cavalier	if (ms == NULL) {
666293a2caeSAugustin Cavalier		printf("%s: couldn't alloc MBSS state\n", __func__);
667293a2caeSAugustin Cavalier		return;
668293a2caeSAugustin Cavalier	}
669293a2caeSAugustin Cavalier	vap->iv_mesh = ms;
670293a2caeSAugustin Cavalier	ms->ms_seq = 0;
671293a2caeSAugustin Cavalier	ms->ms_flags = (IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_FWD);
672293a2caeSAugustin Cavalier	ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL;
673293a2caeSAugustin Cavalier	TAILQ_INIT(&ms->ms_known_gates);
674293a2caeSAugustin Cavalier	TAILQ_INIT(&ms->ms_routes);
675293a2caeSAugustin Cavalier	MESH_RT_LOCK_INIT(ms, "MBSS");
676293a2caeSAugustin Cavalier	callout_init(&ms->ms_cleantimer, 1);
677293a2caeSAugustin Cavalier	callout_init(&ms->ms_gatetimer, 1);
678293a2caeSAugustin Cavalier	ms->ms_gateseq = 0;
679293a2caeSAugustin Cavalier	mesh_select_proto_metric(vap, "AIRTIME");
680293a2caeSAugustin Cavalier	KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
681293a2caeSAugustin Cavalier	mesh_select_proto_path(vap, "HWMP");
682293a2caeSAugustin Cavalier	KASSERT(ms->ms_ppath, ("ms_ppath == NULL"));
683293a2caeSAugustin Cavalier	ms->ms_ppath->mpp_vattach(vap);
684293a2caeSAugustin Cavalier}
685293a2caeSAugustin Cavalier
686293a2caeSAugustin Cavalier/*
687293a2caeSAugustin Cavalier * IEEE80211_M_MBSS vap state machine handler.
688293a2caeSAugustin Cavalier */
689293a2caeSAugustin Cavalierstatic int
690293a2caeSAugustin Cavaliermesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
691293a2caeSAugustin Cavalier{
692293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
693293a2caeSAugustin Cavalier	struct ieee80211com *ic = vap->iv_ic;
694293a2caeSAugustin Cavalier	struct ieee80211_node *ni;
695293a2caeSAugustin Cavalier	enum ieee80211_state ostate;
696293a2caeSAugustin Cavalier
697293a2caeSAugustin Cavalier	IEEE80211_LOCK_ASSERT(ic);
698293a2caeSAugustin Cavalier
699293a2caeSAugustin Cavalier	ostate = vap->iv_state;
700293a2caeSAugustin Cavalier	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
701293a2caeSAugustin Cavalier	    __func__, ieee80211_state_name[ostate],
702293a2caeSAugustin Cavalier	    ieee80211_state_name[nstate], arg);
703293a2caeSAugustin Cavalier	vap->iv_state = nstate;		/* state transition */
704293a2caeSAugustin Cavalier	if (ostate != IEEE80211_S_SCAN)
705293a2caeSAugustin Cavalier		ieee80211_cancel_scan(vap);	/* background scan */
706293a2caeSAugustin Cavalier	ni = vap->iv_bss;			/* NB: no reference held */
707293a2caeSAugustin Cavalier	if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) {
708293a2caeSAugustin Cavalier		callout_drain(&ms->ms_cleantimer);
709293a2caeSAugustin Cavalier		callout_drain(&ms->ms_gatetimer);
710293a2caeSAugustin Cavalier	}
711293a2caeSAugustin Cavalier	switch (nstate) {
712293a2caeSAugustin Cavalier	case IEEE80211_S_INIT:
713293a2caeSAugustin Cavalier		switch (ostate) {
714293a2caeSAugustin Cavalier		case IEEE80211_S_SCAN:
715293a2caeSAugustin Cavalier			ieee80211_cancel_scan(vap);
716293a2caeSAugustin Cavalier			break;
717293a2caeSAugustin Cavalier		case IEEE80211_S_CAC:
718293a2caeSAugustin Cavalier			ieee80211_dfs_cac_stop(vap);
719293a2caeSAugustin Cavalier			break;
720293a2caeSAugustin Cavalier		case IEEE80211_S_RUN:
721293a2caeSAugustin Cavalier			ieee80211_iterate_nodes(&ic->ic_sta,
722293a2caeSAugustin Cavalier			    mesh_vdetach_peers, NULL);
723293a2caeSAugustin Cavalier			break;
724293a2caeSAugustin Cavalier		default:
725293a2caeSAugustin Cavalier			break;
726293a2caeSAugustin Cavalier		}
727293a2caeSAugustin Cavalier		if (ostate != IEEE80211_S_INIT) {
728293a2caeSAugustin Cavalier			/* NB: optimize INIT -> INIT case */
729293a2caeSAugustin Cavalier			ieee80211_reset_bss(vap);
730293a2caeSAugustin Cavalier			ieee80211_mesh_rt_flush(vap);
731293a2caeSAugustin Cavalier		}
732293a2caeSAugustin Cavalier		break;
733293a2caeSAugustin Cavalier	case IEEE80211_S_SCAN:
734293a2caeSAugustin Cavalier		switch (ostate) {
735293a2caeSAugustin Cavalier		case IEEE80211_S_INIT:
736293a2caeSAugustin Cavalier			if (vap->iv_des_chan != IEEE80211_CHAN_ANYC &&
737293a2caeSAugustin Cavalier			    !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan) &&
738293a2caeSAugustin Cavalier			    ms->ms_idlen != 0) {
739293a2caeSAugustin Cavalier				/*
740293a2caeSAugustin Cavalier				 * Already have a channel and a mesh ID; bypass
741293a2caeSAugustin Cavalier				 * the scan and startup immediately.
742293a2caeSAugustin Cavalier				 */
743293a2caeSAugustin Cavalier				ieee80211_create_ibss(vap, vap->iv_des_chan);
744293a2caeSAugustin Cavalier				break;
745293a2caeSAugustin Cavalier			}
746293a2caeSAugustin Cavalier			/*
747293a2caeSAugustin Cavalier			 * Initiate a scan.  We can come here as a result
748293a2caeSAugustin Cavalier			 * of an IEEE80211_IOC_SCAN_REQ too in which case
749293a2caeSAugustin Cavalier			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
750293a2caeSAugustin Cavalier			 * and the scan request parameters will be present
751293a2caeSAugustin Cavalier			 * in iv_scanreq.  Otherwise we do the default.
752293a2caeSAugustin Cavalier			*/
753293a2caeSAugustin Cavalier			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
754293a2caeSAugustin Cavalier				ieee80211_check_scan(vap,
755293a2caeSAugustin Cavalier				    vap->iv_scanreq_flags,
756293a2caeSAugustin Cavalier				    vap->iv_scanreq_duration,
757293a2caeSAugustin Cavalier				    vap->iv_scanreq_mindwell,
758293a2caeSAugustin Cavalier				    vap->iv_scanreq_maxdwell,
759293a2caeSAugustin Cavalier				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
760293a2caeSAugustin Cavalier				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
761293a2caeSAugustin Cavalier			} else
762293a2caeSAugustin Cavalier				ieee80211_check_scan_current(vap);
763293a2caeSAugustin Cavalier			break;
764293a2caeSAugustin Cavalier		default:
765293a2caeSAugustin Cavalier			break;
766293a2caeSAugustin Cavalier		}
767293a2caeSAugustin Cavalier		break;
768293a2caeSAugustin Cavalier	case IEEE80211_S_CAC:
769293a2caeSAugustin Cavalier		/*
770293a2caeSAugustin Cavalier		 * Start CAC on a DFS channel.  We come here when starting
771293a2caeSAugustin Cavalier		 * a bss on a DFS channel (see ieee80211_create_ibss).
772293a2caeSAugustin Cavalier		 */
773293a2caeSAugustin Cavalier		ieee80211_dfs_cac_start(vap);
774293a2caeSAugustin Cavalier		break;
775293a2caeSAugustin Cavalier	case IEEE80211_S_RUN:
776293a2caeSAugustin Cavalier		switch (ostate) {
777293a2caeSAugustin Cavalier		case IEEE80211_S_INIT:
778293a2caeSAugustin Cavalier			/*
779293a2caeSAugustin Cavalier			 * Already have a channel; bypass the
780293a2caeSAugustin Cavalier			 * scan and startup immediately.
781293a2caeSAugustin Cavalier			 * Note that ieee80211_create_ibss will call
782293a2caeSAugustin Cavalier			 * back to do a RUN->RUN state change.
783293a2caeSAugustin Cavalier			 */
784293a2caeSAugustin Cavalier			ieee80211_create_ibss(vap,
785293a2caeSAugustin Cavalier			    ieee80211_ht_adjust_channel(ic,
786293a2caeSAugustin Cavalier				ic->ic_curchan, vap->iv_flags_ht));
787293a2caeSAugustin Cavalier			/* NB: iv_bss is changed on return */
788293a2caeSAugustin Cavalier			break;
789293a2caeSAugustin Cavalier		case IEEE80211_S_CAC:
790293a2caeSAugustin Cavalier			/*
791293a2caeSAugustin Cavalier			 * NB: This is the normal state change when CAC
792293a2caeSAugustin Cavalier			 * expires and no radar was detected; no need to
793293a2caeSAugustin Cavalier			 * clear the CAC timer as it's already expired.
794293a2caeSAugustin Cavalier			 */
795293a2caeSAugustin Cavalier			/* fall thru... */
796293a2caeSAugustin Cavalier		case IEEE80211_S_CSA:
797293a2caeSAugustin Cavalier#if 0
798293a2caeSAugustin Cavalier			/*
799293a2caeSAugustin Cavalier			 * Shorten inactivity timer of associated stations
800293a2caeSAugustin Cavalier			 * to weed out sta's that don't follow a CSA.
801293a2caeSAugustin Cavalier			 */
802293a2caeSAugustin Cavalier			ieee80211_iterate_nodes(&ic->ic_sta, sta_csa, vap);
803293a2caeSAugustin Cavalier#endif
804293a2caeSAugustin Cavalier			/*
805293a2caeSAugustin Cavalier			 * Update bss node channel to reflect where
806293a2caeSAugustin Cavalier			 * we landed after CSA.
807293a2caeSAugustin Cavalier			 */
808293a2caeSAugustin Cavalier			ieee80211_node_set_chan(ni,
809293a2caeSAugustin Cavalier			    ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
810293a2caeSAugustin Cavalier				ieee80211_htchanflags(ni->ni_chan)));
811293a2caeSAugustin Cavalier			/* XXX bypass debug msgs */
812293a2caeSAugustin Cavalier			break;
813293a2caeSAugustin Cavalier		case IEEE80211_S_SCAN:
814293a2caeSAugustin Cavalier		case IEEE80211_S_RUN:
815293a2caeSAugustin Cavalier#ifdef IEEE80211_DEBUG
816293a2caeSAugustin Cavalier			if (ieee80211_msg_debug(vap)) {
817293a2caeSAugustin Cavalier				ieee80211_note(vap,
818293a2caeSAugustin Cavalier				    "synchronized with %s meshid ",
819293a2caeSAugustin Cavalier				    ether_sprintf(ni->ni_meshid));
820293a2caeSAugustin Cavalier				ieee80211_print_essid(ni->ni_meshid,
821293a2caeSAugustin Cavalier				    ni->ni_meshidlen);
822293a2caeSAugustin Cavalier				/* XXX MCS/HT */
823293a2caeSAugustin Cavalier				printf(" channel %d\n",
824293a2caeSAugustin Cavalier				    ieee80211_chan2ieee(ic, ic->ic_curchan));
825293a2caeSAugustin Cavalier			}
826293a2caeSAugustin Cavalier#endif
827293a2caeSAugustin Cavalier			break;
828293a2caeSAugustin Cavalier		default:
829293a2caeSAugustin Cavalier			break;
830293a2caeSAugustin Cavalier		}
831293a2caeSAugustin Cavalier		ieee80211_node_authorize(ni);
832293a2caeSAugustin Cavalier		callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
833293a2caeSAugustin Cavalier                    mesh_rt_cleanup_cb, vap);
834293a2caeSAugustin Cavalier		mesh_gatemode_setup(vap);
835293a2caeSAugustin Cavalier		break;
836293a2caeSAugustin Cavalier	default:
837293a2caeSAugustin Cavalier		break;
838293a2caeSAugustin Cavalier	}
839293a2caeSAugustin Cavalier	/* NB: ostate not nstate */
840293a2caeSAugustin Cavalier	ms->ms_ppath->mpp_newstate(vap, ostate, arg);
841293a2caeSAugustin Cavalier	return 0;
842293a2caeSAugustin Cavalier}
843293a2caeSAugustin Cavalier
844293a2caeSAugustin Cavalierstatic void
845293a2caeSAugustin Cavaliermesh_rt_cleanup_cb(void *arg)
846293a2caeSAugustin Cavalier{
847293a2caeSAugustin Cavalier	struct ieee80211vap *vap = arg;
848293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
849293a2caeSAugustin Cavalier
850293a2caeSAugustin Cavalier	mesh_rt_flush_invalid(vap);
851293a2caeSAugustin Cavalier	callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
852293a2caeSAugustin Cavalier	    mesh_rt_cleanup_cb, vap);
853293a2caeSAugustin Cavalier}
854293a2caeSAugustin Cavalier
855293a2caeSAugustin Cavalier/*
856293a2caeSAugustin Cavalier * Mark a mesh STA as gate and return a pointer to it.
857293a2caeSAugustin Cavalier * If this is first time, we create a new gate route.
858293a2caeSAugustin Cavalier * Always update the path route to this mesh gate.
859293a2caeSAugustin Cavalier */
860293a2caeSAugustin Cavalierstruct ieee80211_mesh_gate_route *
861293a2caeSAugustin Cavalierieee80211_mesh_mark_gate(struct ieee80211vap *vap, const uint8_t *addr,
862293a2caeSAugustin Cavalier    struct ieee80211_mesh_route *rt)
863293a2caeSAugustin Cavalier{
864293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
865293a2caeSAugustin Cavalier	struct ieee80211_mesh_gate_route *gr = NULL, *next;
866293a2caeSAugustin Cavalier	int found = 0;
867293a2caeSAugustin Cavalier
868293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
869293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, next) {
870293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(gr->gr_addr, addr)) {
871293a2caeSAugustin Cavalier			found = 1;
872293a2caeSAugustin Cavalier			break;
873293a2caeSAugustin Cavalier		}
874293a2caeSAugustin Cavalier	}
875293a2caeSAugustin Cavalier
876293a2caeSAugustin Cavalier	if (!found) {
877293a2caeSAugustin Cavalier		/* New mesh gate add it to known table. */
878293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, addr,
879293a2caeSAugustin Cavalier		    "%s", "stored new gate information from pro-PREQ.");
880293a2caeSAugustin Cavalier		gr = IEEE80211_MALLOC(ALIGN(sizeof(struct ieee80211_mesh_gate_route)),
881293a2caeSAugustin Cavalier		    M_80211_MESH_GT_RT,
882293a2caeSAugustin Cavalier		    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
883293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(gr->gr_addr, addr);
884293a2caeSAugustin Cavalier		TAILQ_INSERT_TAIL(&ms->ms_known_gates, gr, gr_next);
885293a2caeSAugustin Cavalier	}
886293a2caeSAugustin Cavalier	gr->gr_route = rt;
887293a2caeSAugustin Cavalier	/* TODO: link from path route to gate route */
888293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
889293a2caeSAugustin Cavalier
890293a2caeSAugustin Cavalier	return gr;
891293a2caeSAugustin Cavalier}
892293a2caeSAugustin Cavalier
893293a2caeSAugustin Cavalier
894293a2caeSAugustin Cavalier/*
895293a2caeSAugustin Cavalier * Helper function to note the Mesh Peer Link FSM change.
896293a2caeSAugustin Cavalier */
897293a2caeSAugustin Cavalierstatic void
898293a2caeSAugustin Cavaliermesh_linkchange(struct ieee80211_node *ni, enum ieee80211_mesh_mlstate state)
899293a2caeSAugustin Cavalier{
900293a2caeSAugustin Cavalier	struct ieee80211vap *vap = ni->ni_vap;
901293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
902293a2caeSAugustin Cavalier#ifdef IEEE80211_DEBUG
903293a2caeSAugustin Cavalier	static const char *meshlinkstates[] = {
904293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_IDLE]		= "IDLE",
905293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_OPENSNT]		= "OPEN SENT",
906293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_OPENRCV]		= "OPEN RECEIVED",
907293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_CONFIRMRCV]	= "CONFIRM RECEIVED",
908293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_ESTABLISHED]	= "ESTABLISHED",
909293a2caeSAugustin Cavalier		[IEEE80211_NODE_MESH_HOLDING]		= "HOLDING"
910293a2caeSAugustin Cavalier	};
911293a2caeSAugustin Cavalier#endif
912293a2caeSAugustin Cavalier	IEEE80211_NOTE(vap, IEEE80211_MSG_MESH,
913293a2caeSAugustin Cavalier	    ni, "peer link: %s -> %s",
914293a2caeSAugustin Cavalier	    meshlinkstates[ni->ni_mlstate], meshlinkstates[state]);
915293a2caeSAugustin Cavalier
916293a2caeSAugustin Cavalier	/* track neighbor count */
917293a2caeSAugustin Cavalier	if (state == IEEE80211_NODE_MESH_ESTABLISHED &&
918293a2caeSAugustin Cavalier	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
919293a2caeSAugustin Cavalier		KASSERT(ms->ms_neighbors < 65535, ("neighbor count overflow"));
920293a2caeSAugustin Cavalier		ms->ms_neighbors++;
921293a2caeSAugustin Cavalier		ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
922293a2caeSAugustin Cavalier	} else if (ni->ni_mlstate == IEEE80211_NODE_MESH_ESTABLISHED &&
923293a2caeSAugustin Cavalier	    state != IEEE80211_NODE_MESH_ESTABLISHED) {
924293a2caeSAugustin Cavalier		KASSERT(ms->ms_neighbors > 0, ("neighbor count 0"));
925293a2caeSAugustin Cavalier		ms->ms_neighbors--;
926293a2caeSAugustin Cavalier		ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
927293a2caeSAugustin Cavalier	}
928293a2caeSAugustin Cavalier	ni->ni_mlstate = state;
929293a2caeSAugustin Cavalier	switch (state) {
930293a2caeSAugustin Cavalier	case IEEE80211_NODE_MESH_HOLDING:
931293a2caeSAugustin Cavalier		ms->ms_ppath->mpp_peerdown(ni);
932293a2caeSAugustin Cavalier		break;
933293a2caeSAugustin Cavalier	case IEEE80211_NODE_MESH_ESTABLISHED:
934293a2caeSAugustin Cavalier		ieee80211_mesh_discover(vap, ni->ni_macaddr, NULL);
935293a2caeSAugustin Cavalier		break;
936293a2caeSAugustin Cavalier	default:
937293a2caeSAugustin Cavalier		break;
938293a2caeSAugustin Cavalier	}
939293a2caeSAugustin Cavalier}
940293a2caeSAugustin Cavalier
941293a2caeSAugustin Cavalier/*
942293a2caeSAugustin Cavalier * Helper function to generate a unique local ID required for mesh
943293a2caeSAugustin Cavalier * peer establishment.
944293a2caeSAugustin Cavalier */
945293a2caeSAugustin Cavalierstatic void
946293a2caeSAugustin Cavaliermesh_checkid(void *arg, struct ieee80211_node *ni)
947293a2caeSAugustin Cavalier{
948293a2caeSAugustin Cavalier	uint16_t *r = arg;
9498244a9baSAugustin Cavalier
950293a2caeSAugustin Cavalier	if (*r == ni->ni_mllid)
951293a2caeSAugustin Cavalier		*(uint16_t *)arg = 0;
952293a2caeSAugustin Cavalier}
953293a2caeSAugustin Cavalier
954293a2caeSAugustin Cavalierstatic uint32_t
955293a2caeSAugustin Cavaliermesh_generateid(struct ieee80211vap *vap)
956293a2caeSAugustin Cavalier{
957293a2caeSAugustin Cavalier	int maxiter = 4;
958293a2caeSAugustin Cavalier	uint16_t r;
959293a2caeSAugustin Cavalier
960293a2caeSAugustin Cavalier	do {
961293a2caeSAugustin Cavalier		get_random_bytes(&r, 2);
962293a2caeSAugustin Cavalier		ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_checkid, &r);
963293a2caeSAugustin Cavalier		maxiter--;
964293a2caeSAugustin Cavalier	} while (r == 0 && maxiter > 0);
965293a2caeSAugustin Cavalier	return r;
966293a2caeSAugustin Cavalier}
967293a2caeSAugustin Cavalier
968293a2caeSAugustin Cavalier/*
969293a2caeSAugustin Cavalier * Verifies if we already received this packet by checking its
970293a2caeSAugustin Cavalier * sequence number.
971293a2caeSAugustin Cavalier * Returns 0 if the frame is to be accepted, 1 otherwise.
972293a2caeSAugustin Cavalier */
973293a2caeSAugustin Cavalierstatic int
974293a2caeSAugustin Cavaliermesh_checkpseq(struct ieee80211vap *vap,
975293a2caeSAugustin Cavalier    const uint8_t source[IEEE80211_ADDR_LEN], uint32_t seq)
976293a2caeSAugustin Cavalier{
977293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
978293a2caeSAugustin Cavalier
979293a2caeSAugustin Cavalier	rt = ieee80211_mesh_rt_find(vap, source);
980293a2caeSAugustin Cavalier	if (rt == NULL) {
981293a2caeSAugustin Cavalier		rt = ieee80211_mesh_rt_add(vap, source);
982293a2caeSAugustin Cavalier		if (rt == NULL) {
983293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
984293a2caeSAugustin Cavalier			    "%s", "add mcast route failed");
985293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_rtaddfailed++;
986293a2caeSAugustin Cavalier			return 1;
987293a2caeSAugustin Cavalier		}
988293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
989293a2caeSAugustin Cavalier		    "add mcast route, mesh seqno %d", seq);
990293a2caeSAugustin Cavalier		rt->rt_lastmseq = seq;
991293a2caeSAugustin Cavalier		return 0;
992293a2caeSAugustin Cavalier	}
993293a2caeSAugustin Cavalier	if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
994293a2caeSAugustin Cavalier		return 1;
995293a2caeSAugustin Cavalier	} else {
996293a2caeSAugustin Cavalier		rt->rt_lastmseq = seq;
997293a2caeSAugustin Cavalier		return 0;
998293a2caeSAugustin Cavalier	}
999293a2caeSAugustin Cavalier}
1000293a2caeSAugustin Cavalier
1001293a2caeSAugustin Cavalier/*
1002293a2caeSAugustin Cavalier * Iterate the routing table and locate the next hop.
1003293a2caeSAugustin Cavalier */
1004293a2caeSAugustin Cavalierstruct ieee80211_node *
1005293a2caeSAugustin Cavalierieee80211_mesh_find_txnode(struct ieee80211vap *vap,
1006293a2caeSAugustin Cavalier    const uint8_t dest[IEEE80211_ADDR_LEN])
1007293a2caeSAugustin Cavalier{
1008293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
1009293a2caeSAugustin Cavalier
1010293a2caeSAugustin Cavalier	rt = ieee80211_mesh_rt_find(vap, dest);
1011293a2caeSAugustin Cavalier	if (rt == NULL)
1012293a2caeSAugustin Cavalier		return NULL;
1013293a2caeSAugustin Cavalier	if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1014293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
1015293a2caeSAugustin Cavalier		    "%s: !valid, flags 0x%x", __func__, rt->rt_flags);
1016293a2caeSAugustin Cavalier		/* XXX stat */
1017293a2caeSAugustin Cavalier		return NULL;
1018293a2caeSAugustin Cavalier	}
1019293a2caeSAugustin Cavalier	if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1020293a2caeSAugustin Cavalier		rt = ieee80211_mesh_rt_find(vap, rt->rt_mesh_gate);
1021293a2caeSAugustin Cavalier		if (rt == NULL) return NULL;
1022293a2caeSAugustin Cavalier		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1023293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
1024293a2caeSAugustin Cavalier			    "%s: meshgate !valid, flags 0x%x", __func__,
1025293a2caeSAugustin Cavalier			    rt->rt_flags);
1026293a2caeSAugustin Cavalier			/* XXX stat */
1027293a2caeSAugustin Cavalier			return NULL;
1028293a2caeSAugustin Cavalier		}
1029293a2caeSAugustin Cavalier	}
1030293a2caeSAugustin Cavalier	return ieee80211_find_txnode(vap, rt->rt_nexthop);
1031293a2caeSAugustin Cavalier}
1032293a2caeSAugustin Cavalier
1033293a2caeSAugustin Cavalierstatic void
1034293a2caeSAugustin Cavaliermesh_transmit_to_gate(struct ieee80211vap *vap, struct mbuf *m,
1035293a2caeSAugustin Cavalier    struct ieee80211_mesh_route *rt_gate)
1036293a2caeSAugustin Cavalier{
1037293a2caeSAugustin Cavalier	struct ifnet *ifp = vap->iv_ifp;
1038293a2caeSAugustin Cavalier	struct ieee80211_node *ni;
1039293a2caeSAugustin Cavalier
1040293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
1041293a2caeSAugustin Cavalier
1042293a2caeSAugustin Cavalier	ni = ieee80211_mesh_find_txnode(vap, rt_gate->rt_dest);
1043293a2caeSAugustin Cavalier	if (ni == NULL) {
1044293a2caeSAugustin Cavalier		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1045293a2caeSAugustin Cavalier		m_freem(m);
1046293a2caeSAugustin Cavalier		return;
1047293a2caeSAugustin Cavalier	}
1048293a2caeSAugustin Cavalier
1049293a2caeSAugustin Cavalier	/*
1050293a2caeSAugustin Cavalier	 * Send through the VAP packet transmit path.
1051293a2caeSAugustin Cavalier	 * This consumes the node ref grabbed above and
1052293a2caeSAugustin Cavalier	 * the mbuf, regardless of whether there's a problem
1053293a2caeSAugustin Cavalier	 * or not.
1054293a2caeSAugustin Cavalier	 */
1055293a2caeSAugustin Cavalier	(void) ieee80211_vap_pkt_send_dest(vap, m, ni);
1056293a2caeSAugustin Cavalier}
1057293a2caeSAugustin Cavalier
1058293a2caeSAugustin Cavalier/*
1059293a2caeSAugustin Cavalier * Forward the queued frames to known valid mesh gates.
1060293a2caeSAugustin Cavalier * Assume destination to be outside the MBSS (i.e. proxy entry),
1061293a2caeSAugustin Cavalier * If no valid mesh gates are known silently discard queued frames.
1062293a2caeSAugustin Cavalier * After transmitting frames to all known valid mesh gates, this route
1063293a2caeSAugustin Cavalier * will be marked invalid, and a new path discovery will happen in the hopes
1064293a2caeSAugustin Cavalier * that (at least) one of the mesh gates have a new proxy entry for us to use.
1065293a2caeSAugustin Cavalier */
1066293a2caeSAugustin Cavaliervoid
1067293a2caeSAugustin Cavalierieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
1068293a2caeSAugustin Cavalier    struct ieee80211_mesh_route *rt_dest)
1069293a2caeSAugustin Cavalier{
1070293a2caeSAugustin Cavalier	struct ieee80211com *ic = vap->iv_ic;
1071293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1072293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt_gate;
1073293a2caeSAugustin Cavalier	struct ieee80211_mesh_gate_route *gr = NULL, *gr_next;
1074293a2caeSAugustin Cavalier	struct mbuf *m, *mcopy, *next;
1075293a2caeSAugustin Cavalier
1076293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(ic);
1077293a2caeSAugustin Cavalier
1078293a2caeSAugustin Cavalier	KASSERT( rt_dest->rt_flags == IEEE80211_MESHRT_FLAGS_DISCOVER,
1079293a2caeSAugustin Cavalier	    ("Route is not marked with IEEE80211_MESHRT_FLAGS_DISCOVER"));
1080293a2caeSAugustin Cavalier
1081293a2caeSAugustin Cavalier	/* XXX: send to more than one valid mash gate */
1082293a2caeSAugustin Cavalier	MESH_RT_LOCK(ms);
1083293a2caeSAugustin Cavalier
1084293a2caeSAugustin Cavalier	m = ieee80211_ageq_remove(&ic->ic_stageq,
1085293a2caeSAugustin Cavalier	    (struct ieee80211_node *)(uintptr_t)
1086293a2caeSAugustin Cavalier	    ieee80211_mac_hash(ic, rt_dest->rt_dest));
1087293a2caeSAugustin Cavalier
1088293a2caeSAugustin Cavalier	TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, gr_next) {
1089293a2caeSAugustin Cavalier		rt_gate = gr->gr_route;
1090293a2caeSAugustin Cavalier		if (rt_gate == NULL) {
1091293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
1092293a2caeSAugustin Cavalier				rt_dest->rt_dest,
1093293a2caeSAugustin Cavalier				"mesh gate with no path %6D",
1094293a2caeSAugustin Cavalier				gr->gr_addr, ":");
1095293a2caeSAugustin Cavalier			continue;
1096293a2caeSAugustin Cavalier		}
1097293a2caeSAugustin Cavalier		if ((rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
1098293a2caeSAugustin Cavalier			continue;
1099293a2caeSAugustin Cavalier		KASSERT(rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_GATE,
1100293a2caeSAugustin Cavalier		    ("route not marked as a mesh gate"));
1101293a2caeSAugustin Cavalier		KASSERT((rt_gate->rt_flags &
1102293a2caeSAugustin Cavalier			IEEE80211_MESHRT_FLAGS_PROXY) == 0,
1103293a2caeSAugustin Cavalier			("found mesh gate that is also marked porxy"));
1104293a2caeSAugustin Cavalier		/*
1105293a2caeSAugustin Cavalier		 * convert route to a proxy route gated by the current
1106293a2caeSAugustin Cavalier		 * mesh gate, this is needed so encap can built data
1107293a2caeSAugustin Cavalier		 * frame with correct address.
1108293a2caeSAugustin Cavalier		 */
1109293a2caeSAugustin Cavalier		rt_dest->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
1110293a2caeSAugustin Cavalier			IEEE80211_MESHRT_FLAGS_VALID;
1111293a2caeSAugustin Cavalier		rt_dest->rt_ext_seq = 1; /* random value */
1112293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(rt_dest->rt_mesh_gate, rt_gate->rt_dest);
1113293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(rt_dest->rt_nexthop, rt_gate->rt_nexthop);
1114293a2caeSAugustin Cavalier		rt_dest->rt_metric = rt_gate->rt_metric;
1115293a2caeSAugustin Cavalier		rt_dest->rt_nhops = rt_gate->rt_nhops;
1116293a2caeSAugustin Cavalier		ieee80211_mesh_rt_update(rt_dest, ms->ms_ppath->mpp_inact);
1117293a2caeSAugustin Cavalier		MESH_RT_UNLOCK(ms);
1118293a2caeSAugustin Cavalier		/* XXX: lock?? */
1119293a2caeSAugustin Cavalier		mcopy = m_dup(m, M_NOWAIT);
1120293a2caeSAugustin Cavalier		for (; mcopy != NULL; mcopy = next) {
1121293a2caeSAugustin Cavalier			next = mcopy->m_nextpkt;
1122293a2caeSAugustin Cavalier			mcopy->m_nextpkt = NULL;
1123293a2caeSAugustin Cavalier			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
1124293a2caeSAugustin Cavalier			    rt_dest->rt_dest,
1125293a2caeSAugustin Cavalier			    "flush queued frame %p len %d", mcopy,
1126293a2caeSAugustin Cavalier			    mcopy->m_pkthdr.len);
1127293a2caeSAugustin Cavalier			mesh_transmit_to_gate(vap, mcopy, rt_gate);
1128293a2caeSAugustin Cavalier		}
1129293a2caeSAugustin Cavalier		MESH_RT_LOCK(ms);
1130293a2caeSAugustin Cavalier	}
1131293a2caeSAugustin Cavalier	rt_dest->rt_flags = 0; /* Mark invalid */
1132293a2caeSAugustin Cavalier	m_freem(m);
1133293a2caeSAugustin Cavalier	MESH_RT_UNLOCK(ms);
1134293a2caeSAugustin Cavalier}
1135293a2caeSAugustin Cavalier
1136293a2caeSAugustin Cavalier/*
1137293a2caeSAugustin Cavalier * Forward the specified frame.
1138293a2caeSAugustin Cavalier * Decrement the TTL and set TA to our MAC address.
1139293a2caeSAugustin Cavalier */
1140293a2caeSAugustin Cavalierstatic void
1141293a2caeSAugustin Cavaliermesh_forward(struct ieee80211vap *vap, struct mbuf *m,
1142293a2caeSAugustin Cavalier    const struct ieee80211_meshcntl *mc)
1143293a2caeSAugustin Cavalier{
1144293a2caeSAugustin Cavalier	struct ieee80211com *ic = vap->iv_ic;
1145293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1146293a2caeSAugustin Cavalier	struct ifnet *ifp = vap->iv_ifp;
1147293a2caeSAugustin Cavalier	const struct ieee80211_frame *wh =
1148293a2caeSAugustin Cavalier	    mtod(m, const struct ieee80211_frame *);
1149293a2caeSAugustin Cavalier	struct mbuf *mcopy;
1150293a2caeSAugustin Cavalier	struct ieee80211_meshcntl *mccopy;
1151293a2caeSAugustin Cavalier	struct ieee80211_frame *whcopy;
1152293a2caeSAugustin Cavalier	struct ieee80211_node *ni;
1153293a2caeSAugustin Cavalier	int err;
1154293a2caeSAugustin Cavalier
1155293a2caeSAugustin Cavalier	/* This is called from the RX path - don't hold this lock */
1156293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(ic);
1157293a2caeSAugustin Cavalier
1158293a2caeSAugustin Cavalier	/*
1159293a2caeSAugustin Cavalier	 * mesh ttl of 1 means we are the last one receiving it,
1160293a2caeSAugustin Cavalier	 * according to amendment we decrement and then check if
1161293a2caeSAugustin Cavalier	 * 0, if so we dont forward.
1162293a2caeSAugustin Cavalier	 */
1163293a2caeSAugustin Cavalier	if (mc->mc_ttl < 1) {
1164293a2caeSAugustin Cavalier		IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
1165293a2caeSAugustin Cavalier		    "%s", "frame not fwd'd, ttl 1");
1166293a2caeSAugustin Cavalier		vap->iv_stats.is_mesh_fwd_ttl++;
1167293a2caeSAugustin Cavalier		return;
1168293a2caeSAugustin Cavalier	}
1169293a2caeSAugustin Cavalier	if (!(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1170293a2caeSAugustin Cavalier		IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
1171293a2caeSAugustin Cavalier		    "%s", "frame not fwd'd, fwding disabled");
1172293a2caeSAugustin Cavalier		vap->iv_stats.is_mesh_fwd_disabled++;
1173293a2caeSAugustin Cavalier		return;
1174293a2caeSAugustin Cavalier	}
1175293a2caeSAugustin Cavalier	mcopy = m_dup(m, M_NOWAIT);
1176293a2caeSAugustin Cavalier	if (mcopy == NULL) {
1177293a2caeSAugustin Cavalier		IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
1178293a2caeSAugustin Cavalier		    "%s", "frame not fwd'd, cannot dup");
1179293a2caeSAugustin Cavalier		vap->iv_stats.is_mesh_fwd_nobuf++;
1180293a2caeSAugustin Cavalier		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1181293a2caeSAugustin Cavalier		return;
1182293a2caeSAugustin Cavalier	}
1183293a2caeSAugustin Cavalier	mcopy = m_pullup(mcopy, ieee80211_hdrspace(ic, wh) +
1184293a2caeSAugustin Cavalier	    sizeof(struct ieee80211_meshcntl));
1185293a2caeSAugustin Cavalier	if (mcopy == NULL) {
1186293a2caeSAugustin Cavalier		IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
1187293a2caeSAugustin Cavalier		    "%s", "frame not fwd'd, too short");
1188293a2caeSAugustin Cavalier		vap->iv_stats.is_mesh_fwd_tooshort++;
1189293a2caeSAugustin Cavalier		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1190293a2caeSAugustin Cavalier		m_freem(mcopy);
1191293a2caeSAugustin Cavalier		return;
1192293a2caeSAugustin Cavalier	}
1193293a2caeSAugustin Cavalier	whcopy = mtod(mcopy, struct ieee80211_frame *);
1194293a2caeSAugustin Cavalier	mccopy = (struct ieee80211_meshcntl *)
1195293a2caeSAugustin Cavalier	    (mtod(mcopy, uint8_t *) + ieee80211_hdrspace(ic, wh));
1196293a2caeSAugustin Cavalier	/* XXX clear other bits? */
1197293a2caeSAugustin Cavalier	whcopy->i_fc[1] &= ~IEEE80211_FC1_RETRY;
1198293a2caeSAugustin Cavalier	IEEE80211_ADDR_COPY(whcopy->i_addr2, vap->iv_myaddr);
1199293a2caeSAugustin Cavalier	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1200293a2caeSAugustin Cavalier		ni = ieee80211_ref_node(vap->iv_bss);
1201293a2caeSAugustin Cavalier		mcopy->m_flags |= M_MCAST;
1202293a2caeSAugustin Cavalier	} else {
1203293a2caeSAugustin Cavalier		ni = ieee80211_mesh_find_txnode(vap, whcopy->i_addr3);
1204293a2caeSAugustin Cavalier		if (ni == NULL) {
1205293a2caeSAugustin Cavalier			/*
1206293a2caeSAugustin Cavalier			 * [Optional] any of the following three actions:
1207293a2caeSAugustin Cavalier			 * o silently discard
1208293a2caeSAugustin Cavalier			 * o trigger a path discovery
1209293a2caeSAugustin Cavalier			 * o inform TA that meshDA is unknown.
1210293a2caeSAugustin Cavalier			 */
1211293a2caeSAugustin Cavalier			IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
1212293a2caeSAugustin Cavalier			    "%s", "frame not fwd'd, no path");
1213293a2caeSAugustin Cavalier			ms->ms_ppath->mpp_senderror(vap, whcopy->i_addr3, NULL,
1214293a2caeSAugustin Cavalier			    IEEE80211_REASON_MESH_PERR_NO_FI);
1215293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_fwd_nopath++;
1216293a2caeSAugustin Cavalier			m_freem(mcopy);
1217293a2caeSAugustin Cavalier			return;
1218293a2caeSAugustin Cavalier		}
1219293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(whcopy->i_addr1, ni->ni_macaddr);
1220293a2caeSAugustin Cavalier	}
1221293a2caeSAugustin Cavalier	KASSERT(mccopy->mc_ttl > 0, ("%s called with wrong ttl", __func__));
1222293a2caeSAugustin Cavalier	mccopy->mc_ttl--;
1223293a2caeSAugustin Cavalier
1224293a2caeSAugustin Cavalier	/* XXX calculate priority so drivers can find the tx queue */
1225293a2caeSAugustin Cavalier	M_WME_SETAC(mcopy, WME_AC_BE);
1226293a2caeSAugustin Cavalier
1227293a2caeSAugustin Cavalier	/* XXX do we know m_nextpkt is NULL? */
1228293a2caeSAugustin Cavalier	mcopy->m_pkthdr.rcvif = (void *) ni;
1229293a2caeSAugustin Cavalier
1230293a2caeSAugustin Cavalier	/*
1231293a2caeSAugustin Cavalier	 * XXX this bypasses all of the VAP TX handling; it passes frames
1232293a2caeSAugustin Cavalier	 * directly to the parent interface.
1233293a2caeSAugustin Cavalier	 *
1234293a2caeSAugustin Cavalier	 * Because of this, there's no TX lock being held as there's no
1235293a2caeSAugustin Cavalier	 * encaps state being used.
1236293a2caeSAugustin Cavalier	 *
1237293a2caeSAugustin Cavalier	 * Doing a direct parent transmit may not be the correct thing
1238293a2caeSAugustin Cavalier	 * to do here; we'll have to re-think this soon.
1239293a2caeSAugustin Cavalier	 */
1240293a2caeSAugustin Cavalier	IEEE80211_TX_LOCK(ic);
1241293a2caeSAugustin Cavalier	err = ieee80211_parent_xmitpkt(ic, mcopy);
1242293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK(ic);
1243293a2caeSAugustin Cavalier	if (!err)
1244293a2caeSAugustin Cavalier		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1245293a2caeSAugustin Cavalier}
1246293a2caeSAugustin Cavalier
1247293a2caeSAugustin Cavalierstatic struct mbuf *
1248293a2caeSAugustin Cavaliermesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
1249293a2caeSAugustin Cavalier{
1250293a2caeSAugustin Cavalier#define	WHDIR(wh)	((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
1251293a2caeSAugustin Cavalier#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
1252293a2caeSAugustin Cavalier	uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
1253293a2caeSAugustin Cavalier		  sizeof(struct ieee80211_meshcntl_ae10)];
1254293a2caeSAugustin Cavalier	const struct ieee80211_qosframe_addr4 *wh;
1255293a2caeSAugustin Cavalier	const struct ieee80211_meshcntl_ae10 *mc;
1256293a2caeSAugustin Cavalier	struct ether_header *eh;
1257293a2caeSAugustin Cavalier	struct llc *llc;
1258293a2caeSAugustin Cavalier	int ae;
1259293a2caeSAugustin Cavalier
1260293a2caeSAugustin Cavalier	if (m->m_len < hdrlen + sizeof(*llc) &&
1261293a2caeSAugustin Cavalier	    (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
1262293a2caeSAugustin Cavalier		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
1263293a2caeSAugustin Cavalier		    "discard data frame: %s", "m_pullup failed");
1264293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_tooshort++;
1265293a2caeSAugustin Cavalier		return NULL;
1266293a2caeSAugustin Cavalier	}
1267293a2caeSAugustin Cavalier	memcpy(b, mtod(m, caddr_t), hdrlen);
1268293a2caeSAugustin Cavalier	wh = (const struct ieee80211_qosframe_addr4 *)&b[0];
1269293a2caeSAugustin Cavalier	mc = (const struct ieee80211_meshcntl_ae10 *)&b[hdrlen - meshdrlen];
1270293a2caeSAugustin Cavalier	KASSERT(WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS ||
1271293a2caeSAugustin Cavalier		WHDIR(wh) == IEEE80211_FC1_DIR_DSTODS,
1272293a2caeSAugustin Cavalier	    ("bogus dir, fc 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
1273293a2caeSAugustin Cavalier
1274293a2caeSAugustin Cavalier	llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
1275293a2caeSAugustin Cavalier	if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
1276293a2caeSAugustin Cavalier	    llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
1277293a2caeSAugustin Cavalier	    llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 &&
1278293a2caeSAugustin Cavalier	    /* NB: preserve AppleTalk frames that have a native SNAP hdr */
1279293a2caeSAugustin Cavalier	    !(llc->llc_snap.ether_type == htons(ETHERTYPE_AARP) ||
1280293a2caeSAugustin Cavalier	      llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) {
1281293a2caeSAugustin Cavalier		m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
1282293a2caeSAugustin Cavalier		llc = NULL;
1283293a2caeSAugustin Cavalier	} else {
1284293a2caeSAugustin Cavalier		m_adj(m, hdrlen - sizeof(*eh));
1285293a2caeSAugustin Cavalier	}
1286293a2caeSAugustin Cavalier	eh = mtod(m, struct ether_header *);
1287293a2caeSAugustin Cavalier	ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
1288293a2caeSAugustin Cavalier	if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
1289293a2caeSAugustin Cavalier		IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
1290293a2caeSAugustin Cavalier		if (ae == IEEE80211_MESH_AE_00) {
1291293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
1292293a2caeSAugustin Cavalier		} else if (ae == IEEE80211_MESH_AE_01) {
1293293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_shost,
1294293a2caeSAugustin Cavalier			    MC01(mc)->mc_addr4);
1295293a2caeSAugustin Cavalier		} else {
1296293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1297293a2caeSAugustin Cavalier			    (const struct ieee80211_frame *)wh, NULL,
1298293a2caeSAugustin Cavalier			    "bad AE %d", ae);
1299293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_badae++;
1300293a2caeSAugustin Cavalier			m_freem(m);
1301293a2caeSAugustin Cavalier			return NULL;
1302293a2caeSAugustin Cavalier		}
1303293a2caeSAugustin Cavalier	} else {
1304293a2caeSAugustin Cavalier		if (ae == IEEE80211_MESH_AE_00) {
1305293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
1306293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
1307293a2caeSAugustin Cavalier		} else if (ae == IEEE80211_MESH_AE_10) {
1308293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr5);
1309293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr6);
1310293a2caeSAugustin Cavalier		} else {
1311293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1312293a2caeSAugustin Cavalier			    (const struct ieee80211_frame *)wh, NULL,
1313293a2caeSAugustin Cavalier			    "bad AE %d", ae);
1314293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_badae++;
1315293a2caeSAugustin Cavalier			m_freem(m);
1316293a2caeSAugustin Cavalier			return NULL;
1317293a2caeSAugustin Cavalier		}
1318293a2caeSAugustin Cavalier	}
1319293a2caeSAugustin Cavalier#ifndef __NO_STRICT_ALIGNMENT
1320293a2caeSAugustin Cavalier	if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
1321293a2caeSAugustin Cavalier		m = ieee80211_realign(vap, m, sizeof(*eh));
1322293a2caeSAugustin Cavalier		if (m == NULL)
1323293a2caeSAugustin Cavalier			return NULL;
1324293a2caeSAugustin Cavalier	}
1325293a2caeSAugustin Cavalier#endif /* !__NO_STRICT_ALIGNMENT */
1326293a2caeSAugustin Cavalier	if (llc != NULL) {
1327293a2caeSAugustin Cavalier		eh = mtod(m, struct ether_header *);
1328293a2caeSAugustin Cavalier		eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
1329293a2caeSAugustin Cavalier	}
1330293a2caeSAugustin Cavalier	return m;
1331293a2caeSAugustin Cavalier#undef	WDIR
1332293a2caeSAugustin Cavalier#undef	MC01
1333293a2caeSAugustin Cavalier}
1334293a2caeSAugustin Cavalier
1335293a2caeSAugustin Cavalier/*
1336293a2caeSAugustin Cavalier * Return non-zero if the unicast mesh data frame should be processed
1337293a2caeSAugustin Cavalier * locally.  Frames that are not proxy'd have our address, otherwise
1338293a2caeSAugustin Cavalier * we need to consult the routing table to look for a proxy entry.
1339293a2caeSAugustin Cavalier */
1340293a2caeSAugustin Cavalierstatic __inline int
1341293a2caeSAugustin Cavaliermesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
1342293a2caeSAugustin Cavalier    const struct ieee80211_meshcntl *mc)
1343293a2caeSAugustin Cavalier{
1344293a2caeSAugustin Cavalier	int ae = mc->mc_flags & 3;
1345293a2caeSAugustin Cavalier
1346293a2caeSAugustin Cavalier	KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
1347293a2caeSAugustin Cavalier	    ("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
1348293a2caeSAugustin Cavalier	KASSERT(ae == IEEE80211_MESH_AE_00 || ae == IEEE80211_MESH_AE_10,
1349293a2caeSAugustin Cavalier	    ("bad AE %d", ae));
1350293a2caeSAugustin Cavalier	if (ae == IEEE80211_MESH_AE_10) {	/* ucast w/ proxy */
1351293a2caeSAugustin Cavalier		const struct ieee80211_meshcntl_ae10 *mc10 =
1352293a2caeSAugustin Cavalier		    (const struct ieee80211_meshcntl_ae10 *) mc;
1353293a2caeSAugustin Cavalier		struct ieee80211_mesh_route *rt =
1354293a2caeSAugustin Cavalier		    ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
1355293a2caeSAugustin Cavalier		/* check for proxy route to ourself */
1356293a2caeSAugustin Cavalier		return (rt != NULL &&
1357293a2caeSAugustin Cavalier		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
1358293a2caeSAugustin Cavalier	} else					/* ucast w/o proxy */
1359293a2caeSAugustin Cavalier		return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
1360293a2caeSAugustin Cavalier}
1361293a2caeSAugustin Cavalier
1362293a2caeSAugustin Cavalier/*
1363293a2caeSAugustin Cavalier * Verifies transmitter, updates lifetime, precursor list and forwards data.
1364293a2caeSAugustin Cavalier * > 0 means we have forwarded data and no need to process locally
1365293a2caeSAugustin Cavalier * == 0 means we want to process locally (and we may have forwarded data
1366293a2caeSAugustin Cavalier * < 0 means there was an error and data should be discarded
1367293a2caeSAugustin Cavalier */
1368293a2caeSAugustin Cavalierstatic int
1369293a2caeSAugustin Cavaliermesh_recv_indiv_data_to_fwrd(struct ieee80211vap *vap, struct mbuf *m,
1370293a2caeSAugustin Cavalier    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
1371293a2caeSAugustin Cavalier{
1372293a2caeSAugustin Cavalier	struct ieee80211_qosframe_addr4 *qwh;
1373293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1374293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt_meshda, *rt_meshsa;
1375293a2caeSAugustin Cavalier
1376293a2caeSAugustin Cavalier	/* This is called from the RX path - don't hold this lock */
1377293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
1378293a2caeSAugustin Cavalier
1379293a2caeSAugustin Cavalier	qwh = (struct ieee80211_qosframe_addr4 *)wh;
1380293a2caeSAugustin Cavalier
1381293a2caeSAugustin Cavalier	/*
1382293a2caeSAugustin Cavalier	 * TODO:
1383293a2caeSAugustin Cavalier	 * o verify addr2 is  a legitimate transmitter
1384293a2caeSAugustin Cavalier	 * o lifetime of precursor of addr3 (addr2) is max(init, curr)
1385293a2caeSAugustin Cavalier	 * o lifetime of precursor of addr4 (nexthop) is max(init, curr)
1386293a2caeSAugustin Cavalier	 */
1387293a2caeSAugustin Cavalier
1388293a2caeSAugustin Cavalier	/* set lifetime of addr3 (meshDA) to initial value */
1389293a2caeSAugustin Cavalier	rt_meshda = ieee80211_mesh_rt_find(vap, qwh->i_addr3);
1390293a2caeSAugustin Cavalier	if (rt_meshda == NULL) {
1391293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, qwh->i_addr2,
1392293a2caeSAugustin Cavalier		    "no route to meshDA(%6D)", qwh->i_addr3, ":");
1393293a2caeSAugustin Cavalier		/*
1394293a2caeSAugustin Cavalier		 * [Optional] any of the following three actions:
1395293a2caeSAugustin Cavalier		 * o silently discard 				[X]
1396293a2caeSAugustin Cavalier		 * o trigger a path discovery			[ ]
1397293a2caeSAugustin Cavalier		 * o inform TA that meshDA is unknown.		[ ]
1398293a2caeSAugustin Cavalier		 */
1399293a2caeSAugustin Cavalier		/* XXX: stats */
1400293a2caeSAugustin Cavalier		return (-1);
1401293a2caeSAugustin Cavalier	}
1402293a2caeSAugustin Cavalier
1403293a2caeSAugustin Cavalier	ieee80211_mesh_rt_update(rt_meshda, ticks_to_msecs(
1404293a2caeSAugustin Cavalier	    ms->ms_ppath->mpp_inact));
1405293a2caeSAugustin Cavalier
1406293a2caeSAugustin Cavalier	/* set lifetime of addr4 (meshSA) to initial value */
1407293a2caeSAugustin Cavalier	rt_meshsa = ieee80211_mesh_rt_find(vap, qwh->i_addr4);
1408293a2caeSAugustin Cavalier	KASSERT(rt_meshsa != NULL, ("no route"));
1409293a2caeSAugustin Cavalier	ieee80211_mesh_rt_update(rt_meshsa, ticks_to_msecs(
1410293a2caeSAugustin Cavalier	    ms->ms_ppath->mpp_inact));
1411293a2caeSAugustin Cavalier
1412293a2caeSAugustin Cavalier	mesh_forward(vap, m, mc);
1413293a2caeSAugustin Cavalier	return (1); /* dont process locally */
1414293a2caeSAugustin Cavalier}
1415293a2caeSAugustin Cavalier
1416293a2caeSAugustin Cavalier/*
1417293a2caeSAugustin Cavalier * Verifies transmitter, updates lifetime, precursor list and process data
1418293a2caeSAugustin Cavalier * locally, if data is proxy with AE = 10 it could mean data should go
1419293a2caeSAugustin Cavalier * on another mesh path or data should be forwarded to the DS.
1420293a2caeSAugustin Cavalier *
1421293a2caeSAugustin Cavalier * > 0 means we have forwarded data and no need to process locally
1422293a2caeSAugustin Cavalier * == 0 means we want to process locally (and we may have forwarded data
1423293a2caeSAugustin Cavalier * < 0 means there was an error and data should be discarded
1424293a2caeSAugustin Cavalier */
1425293a2caeSAugustin Cavalierstatic int
1426293a2caeSAugustin Cavaliermesh_recv_indiv_data_to_me(struct ieee80211vap *vap, struct mbuf *m,
1427293a2caeSAugustin Cavalier    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
1428293a2caeSAugustin Cavalier{
1429293a2caeSAugustin Cavalier	struct ieee80211_qosframe_addr4 *qwh;
1430293a2caeSAugustin Cavalier	const struct ieee80211_meshcntl_ae10 *mc10;
1431293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1432293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
1433293a2caeSAugustin Cavalier	int ae;
1434293a2caeSAugustin Cavalier
1435293a2caeSAugustin Cavalier	/* This is called from the RX path - don't hold this lock */
1436293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
1437293a2caeSAugustin Cavalier
1438293a2caeSAugustin Cavalier	qwh = (struct ieee80211_qosframe_addr4 *)wh;
1439293a2caeSAugustin Cavalier	mc10 = (const struct ieee80211_meshcntl_ae10 *)mc;
1440293a2caeSAugustin Cavalier
1441293a2caeSAugustin Cavalier	/*
1442293a2caeSAugustin Cavalier	 * TODO:
1443293a2caeSAugustin Cavalier	 * o verify addr2 is  a legitimate transmitter
1444293a2caeSAugustin Cavalier	 * o lifetime of precursor entry is max(init, curr)
1445293a2caeSAugustin Cavalier	 */
1446293a2caeSAugustin Cavalier
1447293a2caeSAugustin Cavalier	/* set lifetime of addr4 (meshSA) to initial value */
1448293a2caeSAugustin Cavalier	rt = ieee80211_mesh_rt_find(vap, qwh->i_addr4);
1449293a2caeSAugustin Cavalier	KASSERT(rt != NULL, ("no route"));
1450293a2caeSAugustin Cavalier	ieee80211_mesh_rt_update(rt, ticks_to_msecs(ms->ms_ppath->mpp_inact));
1451293a2caeSAugustin Cavalier	rt = NULL;
1452293a2caeSAugustin Cavalier
1453293a2caeSAugustin Cavalier	ae = mc10->mc_flags & IEEE80211_MESH_AE_MASK;
1454293a2caeSAugustin Cavalier	KASSERT(ae == IEEE80211_MESH_AE_00 ||
1455293a2caeSAugustin Cavalier	    ae == IEEE80211_MESH_AE_10, ("bad AE %d", ae));
1456293a2caeSAugustin Cavalier	if (ae == IEEE80211_MESH_AE_10) {
1457293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(mc10->mc_addr5, qwh->i_addr3)) {
1458293a2caeSAugustin Cavalier			return (0); /* process locally */
1459293a2caeSAugustin Cavalier		}
1460293a2caeSAugustin Cavalier
1461293a2caeSAugustin Cavalier		rt =  ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
1462293a2caeSAugustin Cavalier		if (rt != NULL &&
1463293a2caeSAugustin Cavalier		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
1464293a2caeSAugustin Cavalier		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) == 0) {
1465293a2caeSAugustin Cavalier			/*
1466293a2caeSAugustin Cavalier			 * Forward on another mesh-path, according to
1467293a2caeSAugustin Cavalier			 * amendment as specified in 9.32.4.1
1468293a2caeSAugustin Cavalier			 */
1469293a2caeSAugustin Cavalier			IEEE80211_ADDR_COPY(qwh->i_addr3, mc10->mc_addr5);
1470293a2caeSAugustin Cavalier			mesh_forward(vap, m,
1471293a2caeSAugustin Cavalier			    (const struct ieee80211_meshcntl *)mc10);
1472293a2caeSAugustin Cavalier			return (1); /* dont process locally */
1473293a2caeSAugustin Cavalier		}
1474293a2caeSAugustin Cavalier		/*
1475293a2caeSAugustin Cavalier		 * All other cases: forward of MSDUs from the MBSS to DS indiv.
1476293a2caeSAugustin Cavalier		 * addressed according to 13.11.3.2.
1477293a2caeSAugustin Cavalier		 */
1478293a2caeSAugustin Cavalier		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, qwh->i_addr2,
1479293a2caeSAugustin Cavalier		    "forward frame to DS, SA(%6D) DA(%6D)",
1480293a2caeSAugustin Cavalier		    mc10->mc_addr6, ":", mc10->mc_addr5, ":");
1481293a2caeSAugustin Cavalier	}
1482293a2caeSAugustin Cavalier	return (0); /* process locally */
1483293a2caeSAugustin Cavalier}
1484293a2caeSAugustin Cavalier
1485293a2caeSAugustin Cavalier/*
1486293a2caeSAugustin Cavalier * Try to forward the group addressed data on to other mesh STAs, and
1487293a2caeSAugustin Cavalier * also to the DS.
1488293a2caeSAugustin Cavalier *
1489293a2caeSAugustin Cavalier * > 0 means we have forwarded data and no need to process locally
1490293a2caeSAugustin Cavalier * == 0 means we want to process locally (and we may have forwarded data
1491293a2caeSAugustin Cavalier * < 0 means there was an error and data should be discarded
1492293a2caeSAugustin Cavalier */
1493293a2caeSAugustin Cavalierstatic int
1494293a2caeSAugustin Cavaliermesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
1495293a2caeSAugustin Cavalier    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
1496293a2caeSAugustin Cavalier{
1497293a2caeSAugustin Cavalier#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
1498293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1499293a2caeSAugustin Cavalier
1500293a2caeSAugustin Cavalier	/* This is called from the RX path - don't hold this lock */
1501293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
1502293a2caeSAugustin Cavalier
1503293a2caeSAugustin Cavalier	mesh_forward(vap, m, mc);
1504293a2caeSAugustin Cavalier
1505293a2caeSAugustin Cavalier	if(mc->mc_ttl > 0) {
1506293a2caeSAugustin Cavalier		if (mc->mc_flags & IEEE80211_MESH_AE_01) {
1507293a2caeSAugustin Cavalier			/*
1508293a2caeSAugustin Cavalier			 * Forward of MSDUs from the MBSS to DS group addressed
1509293a2caeSAugustin Cavalier			 * (according to 13.11.3.2)
1510293a2caeSAugustin Cavalier			 * This happens by delivering the packet, and a bridge
1511293a2caeSAugustin Cavalier			 * will sent it on another port member.
1512293a2caeSAugustin Cavalier			 */
1513293a2caeSAugustin Cavalier			if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE &&
1514293a2caeSAugustin Cavalier			    ms->ms_flags & IEEE80211_MESHFLAGS_FWD) {
1515293a2caeSAugustin Cavalier				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH,
1516293a2caeSAugustin Cavalier				    MC01(mc)->mc_addr4, "%s",
1517293a2caeSAugustin Cavalier				    "forward from MBSS to the DS");
1518293a2caeSAugustin Cavalier			}
1519293a2caeSAugustin Cavalier		}
1520293a2caeSAugustin Cavalier	}
1521293a2caeSAugustin Cavalier	return (0); /* process locally */
1522293a2caeSAugustin Cavalier#undef	MC01
1523293a2caeSAugustin Cavalier}
1524293a2caeSAugustin Cavalier
1525293a2caeSAugustin Cavalierstatic int
1526293a2caeSAugustin Cavaliermesh_input(struct ieee80211_node *ni, struct mbuf *m,
1527293a2caeSAugustin Cavalier    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
1528293a2caeSAugustin Cavalier{
1529293a2caeSAugustin Cavalier#define	HAS_SEQ(type)	((type & 0x4) == 0)
1530293a2caeSAugustin Cavalier#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
1531293a2caeSAugustin Cavalier	struct ieee80211vap *vap = ni->ni_vap;
1532293a2caeSAugustin Cavalier	struct ieee80211com *ic = ni->ni_ic;
1533293a2caeSAugustin Cavalier	struct ifnet *ifp = vap->iv_ifp;
1534293a2caeSAugustin Cavalier	struct ieee80211_frame *wh;
1535293a2caeSAugustin Cavalier	const struct ieee80211_meshcntl *mc;
1536293a2caeSAugustin Cavalier	int hdrspace, meshdrlen, need_tap, error;
1537293a2caeSAugustin Cavalier	uint8_t dir, type, subtype, ae;
1538293a2caeSAugustin Cavalier	uint32_t seq;
1539293a2caeSAugustin Cavalier	const uint8_t *addr;
1540293a2caeSAugustin Cavalier	uint8_t qos[2];
1541293a2caeSAugustin Cavalier
1542293a2caeSAugustin Cavalier	KASSERT(ni != NULL, ("null node"));
1543293a2caeSAugustin Cavalier	ni->ni_inact = ni->ni_inact_reload;
1544293a2caeSAugustin Cavalier
1545293a2caeSAugustin Cavalier	need_tap = 1;			/* mbuf need to be tapped. */
1546293a2caeSAugustin Cavalier	type = -1;			/* undefined */
1547293a2caeSAugustin Cavalier
1548293a2caeSAugustin Cavalier	/* This is called from the RX path - don't hold this lock */
1549293a2caeSAugustin Cavalier	IEEE80211_TX_UNLOCK_ASSERT(ic);
1550293a2caeSAugustin Cavalier
1551293a2caeSAugustin Cavalier	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
1552293a2caeSAugustin Cavalier		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1553293a2caeSAugustin Cavalier		    ni->ni_macaddr, NULL,
1554293a2caeSAugustin Cavalier		    "too short (1): len %u", m->m_pkthdr.len);
1555293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_tooshort++;
1556293a2caeSAugustin Cavalier		goto out;
1557293a2caeSAugustin Cavalier	}
1558293a2caeSAugustin Cavalier	/*
1559293a2caeSAugustin Cavalier	 * Bit of a cheat here, we use a pointer for a 3-address
1560293a2caeSAugustin Cavalier	 * frame format but don't reference fields past outside
1561293a2caeSAugustin Cavalier	 * ieee80211_frame_min w/o first validating the data is
1562293a2caeSAugustin Cavalier	 * present.
1563293a2caeSAugustin Cavalier	*/
1564293a2caeSAugustin Cavalier	wh = mtod(m, struct ieee80211_frame *);
1565293a2caeSAugustin Cavalier
1566293a2caeSAugustin Cavalier	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
1567293a2caeSAugustin Cavalier	    IEEE80211_FC0_VERSION_0) {
1568293a2caeSAugustin Cavalier		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1569293a2caeSAugustin Cavalier		    ni->ni_macaddr, NULL, "wrong version %x", wh->i_fc[0]);
1570293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_badversion++;
1571293a2caeSAugustin Cavalier		goto err;
1572293a2caeSAugustin Cavalier	}
1573293a2caeSAugustin Cavalier	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
1574293a2caeSAugustin Cavalier	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
1575293a2caeSAugustin Cavalier	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
1576293a2caeSAugustin Cavalier	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
1577293a2caeSAugustin Cavalier		IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
1578293a2caeSAugustin Cavalier		ni->ni_noise = nf;
1579293a2caeSAugustin Cavalier		if (HAS_SEQ(type)) {
1580293a2caeSAugustin Cavalier			uint8_t tid = ieee80211_gettid(wh);
1581293a2caeSAugustin Cavalier
1582293a2caeSAugustin Cavalier			if (IEEE80211_QOS_HAS_SEQ(wh) &&
1583293a2caeSAugustin Cavalier			    TID_TO_WME_AC(tid) >= WME_AC_VI)
1584293a2caeSAugustin Cavalier				ic->ic_wme.wme_hipri_traffic++;
15858244a9baSAugustin Cavalier			if (! ieee80211_check_rxseq(ni, wh, wh->i_addr1, rxs))
1586293a2caeSAugustin Cavalier				goto out;
1587293a2caeSAugustin Cavalier		}
1588293a2caeSAugustin Cavalier	}
1589293a2caeSAugustin Cavalier#ifdef IEEE80211_DEBUG
1590293a2caeSAugustin Cavalier	/*
1591293a2caeSAugustin Cavalier	 * It's easier, but too expensive, to simulate different mesh
1592293a2caeSAugustin Cavalier	 * topologies by consulting the ACL policy very early, so do this
1593293a2caeSAugustin Cavalier	 * only under DEBUG.
1594293a2caeSAugustin Cavalier	 *
1595293a2caeSAugustin Cavalier	 * NB: this check is also done upon peering link initiation.
1596293a2caeSAugustin Cavalier	 */
1597293a2caeSAugustin Cavalier	if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
1598293a2caeSAugustin Cavalier		IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
1599293a2caeSAugustin Cavalier		    wh, NULL, "%s", "disallowed by ACL");
1600293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_acl++;
1601293a2caeSAugustin Cavalier		goto out;
1602293a2caeSAugustin Cavalier	}
1603293a2caeSAugustin Cavalier#endif
1604293a2caeSAugustin Cavalier	switch (type) {
1605293a2caeSAugustin Cavalier	case IEEE80211_FC0_TYPE_DATA:
1606293a2caeSAugustin Cavalier		if (ni == vap->iv_bss)
1607293a2caeSAugustin Cavalier			goto out;
1608293a2caeSAugustin Cavalier		if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
1609293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
1610293a2caeSAugustin Cavalier			    ni->ni_macaddr, NULL,
1611293a2caeSAugustin Cavalier			    "peer link not yet established (%d)",
1612293a2caeSAugustin Cavalier			    ni->ni_mlstate);
1613293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_nolink++;
1614293a2caeSAugustin Cavalier			goto out;
1615293a2caeSAugustin Cavalier		}
1616293a2caeSAugustin Cavalier		if (dir != IEEE80211_FC1_DIR_FROMDS &&
1617293a2caeSAugustin Cavalier		    dir != IEEE80211_FC1_DIR_DSTODS) {
1618293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1619293a2caeSAugustin Cavalier			    wh, "data", "incorrect dir 0x%x", dir);
1620293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_wrongdir++;
1621293a2caeSAugustin Cavalier			goto err;
1622293a2caeSAugustin Cavalier		}
1623293a2caeSAugustin Cavalier
1624293a2caeSAugustin Cavalier		/* All Mesh data frames are QoS subtype */
1625293a2caeSAugustin Cavalier		if (!HAS_SEQ(type)) {
1626293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1627293a2caeSAugustin Cavalier			    wh, "data", "incorrect subtype 0x%x", subtype);
1628293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_badsubtype++;
1629293a2caeSAugustin Cavalier			goto err;
1630293a2caeSAugustin Cavalier		}
1631293a2caeSAugustin Cavalier
1632293a2caeSAugustin Cavalier		/*
1633293a2caeSAugustin Cavalier		 * Next up, any fragmentation.
1634293a2caeSAugustin Cavalier		 * XXX: we defrag before we even try to forward,
1635293a2caeSAugustin Cavalier		 * Mesh Control field is not present in sub-sequent
1636293a2caeSAugustin Cavalier		 * fragmented frames. This is in contrast to Draft 4.0.
1637293a2caeSAugustin Cavalier		 */
1638293a2caeSAugustin Cavalier		hdrspace = ieee80211_hdrspace(ic, wh);
1639293a2caeSAugustin Cavalier		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1640293a2caeSAugustin Cavalier			m = ieee80211_defrag(ni, m, hdrspace);
1641293a2caeSAugustin Cavalier			if (m == NULL) {
1642293a2caeSAugustin Cavalier				/* Fragment dropped or frame not complete yet */
1643293a2caeSAugustin Cavalier				goto out;
1644293a2caeSAugustin Cavalier			}
1645293a2caeSAugustin Cavalier		}
1646293a2caeSAugustin Cavalier		wh = mtod(m, struct ieee80211_frame *); /* NB: after defrag */
1647293a2caeSAugustin Cavalier
1648293a2caeSAugustin Cavalier		/*
1649293a2caeSAugustin Cavalier		 * Now we have a complete Mesh Data frame.
1650293a2caeSAugustin Cavalier		 */
1651293a2caeSAugustin Cavalier
1652293a2caeSAugustin Cavalier		/*
1653293a2caeSAugustin Cavalier		 * Only fromDStoDS data frames use 4 address qos frames
1654293a2caeSAugustin Cavalier		 * as specified in amendment. Otherwise addr4 is located
1655293a2caeSAugustin Cavalier		 * in the Mesh Control field and a 3 address qos frame
1656293a2caeSAugustin Cavalier		 * is used.
1657293a2caeSAugustin Cavalier		 */
1658293a2caeSAugustin Cavalier		if (IEEE80211_IS_DSTODS(wh))
1659293a2caeSAugustin Cavalier			*(uint16_t *)qos = *(uint16_t *)
1660293a2caeSAugustin Cavalier			    ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
1661293a2caeSAugustin Cavalier		else
1662293a2caeSAugustin Cavalier			*(uint16_t *)qos = *(uint16_t *)
1663293a2caeSAugustin Cavalier			    ((struct ieee80211_qosframe *)wh)->i_qos;
1664293a2caeSAugustin Cavalier
1665293a2caeSAugustin Cavalier		/*
1666293a2caeSAugustin Cavalier		 * NB: The mesh STA sets the Mesh Control Present
1667293a2caeSAugustin Cavalier		 * subfield to 1 in the Mesh Data frame containing
1668293a2caeSAugustin Cavalier		 * an unfragmented MSDU, an A-MSDU, or the first
1669293a2caeSAugustin Cavalier		 * fragment of an MSDU.
1670293a2caeSAugustin Cavalier		 * After defrag it should always be present.
1671293a2caeSAugustin Cavalier		 */
1672293a2caeSAugustin Cavalier		if (!(qos[1] & IEEE80211_QOS_MC)) {
1673293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
1674293a2caeSAugustin Cavalier			    ni->ni_macaddr, NULL,
1675293a2caeSAugustin Cavalier			    "%s", "Mesh control field not present");
1676293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_elem_missing++; /* XXX: kinda */
1677293a2caeSAugustin Cavalier			goto err;
1678293a2caeSAugustin Cavalier		}
1679293a2caeSAugustin Cavalier
1680293a2caeSAugustin Cavalier		/* pull up enough to get to the mesh control */
1681293a2caeSAugustin Cavalier		if (m->m_len < hdrspace + sizeof(struct ieee80211_meshcntl) &&
1682293a2caeSAugustin Cavalier		    (m = m_pullup(m, hdrspace +
1683293a2caeSAugustin Cavalier		        sizeof(struct ieee80211_meshcntl))) == NULL) {
1684293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1685293a2caeSAugustin Cavalier			    ni->ni_macaddr, NULL,
1686293a2caeSAugustin Cavalier			    "data too short: expecting %u", hdrspace);
1687293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_tooshort++;
1688293a2caeSAugustin Cavalier			goto out;		/* XXX */
1689293a2caeSAugustin Cavalier		}
1690293a2caeSAugustin Cavalier		/*
1691293a2caeSAugustin Cavalier		 * Now calculate the full extent of the headers. Note
1692293a2caeSAugustin Cavalier		 * mesh_decap will pull up anything we didn't get
1693293a2caeSAugustin Cavalier		 * above when it strips the 802.11 headers.
1694293a2caeSAugustin Cavalier		 */
1695293a2caeSAugustin Cavalier		mc = (const struct ieee80211_meshcntl *)
1696293a2caeSAugustin Cavalier		    (mtod(m, const uint8_t *) + hdrspace);
1697293a2caeSAugustin Cavalier		ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
1698293a2caeSAugustin Cavalier		meshdrlen = sizeof(struct ieee80211_meshcntl) +
1699293a2caeSAugustin Cavalier		    ae * IEEE80211_ADDR_LEN;
1700293a2caeSAugustin Cavalier		hdrspace += meshdrlen;
1701293a2caeSAugustin Cavalier
1702293a2caeSAugustin Cavalier		/* pull complete hdrspace = ieee80211_hdrspace + meshcontrol */
1703293a2caeSAugustin Cavalier		if ((meshdrlen > sizeof(struct ieee80211_meshcntl)) &&
1704293a2caeSAugustin Cavalier		    (m->m_len < hdrspace) &&
1705293a2caeSAugustin Cavalier		    ((m = m_pullup(m, hdrspace)) == NULL)) {
1706293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1707293a2caeSAugustin Cavalier			    ni->ni_macaddr, NULL,
1708293a2caeSAugustin Cavalier			    "data too short: expecting %u", hdrspace);
1709293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_tooshort++;
1710293a2caeSAugustin Cavalier			goto out;		/* XXX */
1711293a2caeSAugustin Cavalier		}
1712293a2caeSAugustin Cavalier		/* XXX: are we sure there is no reallocating after m_pullup? */
1713293a2caeSAugustin Cavalier
1714293a2caeSAugustin Cavalier		seq = le32dec(mc->mc_seq);
1715293a2caeSAugustin Cavalier		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1716293a2caeSAugustin Cavalier			addr = wh->i_addr3;
1717293a2caeSAugustin Cavalier		else if (ae == IEEE80211_MESH_AE_01)
1718293a2caeSAugustin Cavalier			addr = MC01(mc)->mc_addr4;
1719293a2caeSAugustin Cavalier		else
1720293a2caeSAugustin Cavalier			addr = ((struct ieee80211_qosframe_addr4 *)wh)->i_addr4;
1721293a2caeSAugustin Cavalier		if (IEEE80211_ADDR_EQ(vap->iv_myaddr, addr)) {
1722293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
1723293a2caeSAugustin Cavalier			    addr, "data", "%s", "not to me");
1724293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_wrongbss++;	/* XXX kinda */
1725293a2caeSAugustin Cavalier			goto out;
1726293a2caeSAugustin Cavalier		}
1727293a2caeSAugustin Cavalier		if (mesh_checkpseq(vap, addr, seq) != 0) {
1728293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_dup++;
1729293a2caeSAugustin Cavalier			goto out;
1730293a2caeSAugustin Cavalier		}
1731293a2caeSAugustin Cavalier
1732293a2caeSAugustin Cavalier		/* This code "routes" the frame to the right control path */
1733293a2caeSAugustin Cavalier		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1734293a2caeSAugustin Cavalier			if (IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr3))
1735293a2caeSAugustin Cavalier				error =
1736293a2caeSAugustin Cavalier				    mesh_recv_indiv_data_to_me(vap, m, wh, mc);
1737293a2caeSAugustin Cavalier			else if (IEEE80211_IS_MULTICAST(wh->i_addr3))
1738293a2caeSAugustin Cavalier				error = mesh_recv_group_data(vap, m, wh, mc);
1739293a2caeSAugustin Cavalier			else
1740293a2caeSAugustin Cavalier				error = mesh_recv_indiv_data_to_fwrd(vap, m,
1741293a2caeSAugustin Cavalier				    wh, mc);
1742293a2caeSAugustin Cavalier		} else
1743293a2caeSAugustin Cavalier			error = mesh_recv_group_data(vap, m, wh, mc);
1744293a2caeSAugustin Cavalier		if (error < 0)
1745293a2caeSAugustin Cavalier			goto err;
1746293a2caeSAugustin Cavalier		else if (error > 0)
1747293a2caeSAugustin Cavalier			goto out;
1748293a2caeSAugustin Cavalier
1749293a2caeSAugustin Cavalier		if (ieee80211_radiotap_active_vap(vap))
1750293a2caeSAugustin Cavalier			ieee80211_radiotap_rx(vap, m);
1751293a2caeSAugustin Cavalier		need_tap = 0;
1752293a2caeSAugustin Cavalier
1753293a2caeSAugustin Cavalier		/*
1754293a2caeSAugustin Cavalier		 * Finally, strip the 802.11 header.
1755293a2caeSAugustin Cavalier		 */
1756293a2caeSAugustin Cavalier		m = mesh_decap(vap, m, hdrspace, meshdrlen);
1757293a2caeSAugustin Cavalier		if (m == NULL) {
1758293a2caeSAugustin Cavalier			/* XXX mask bit to check for both */
1759293a2caeSAugustin Cavalier			/* don't count Null data frames as errors */
1760293a2caeSAugustin Cavalier			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
1761293a2caeSAugustin Cavalier			    subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
1762293a2caeSAugustin Cavalier				goto out;
1763293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
1764293a2caeSAugustin Cavalier			    ni->ni_macaddr, "data", "%s", "decap error");
1765293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_decap++;
1766293a2caeSAugustin Cavalier			IEEE80211_NODE_STAT(ni, rx_decap);
1767293a2caeSAugustin Cavalier			goto err;
1768293a2caeSAugustin Cavalier		}
1769293a2caeSAugustin Cavalier		if (qos[0] & IEEE80211_QOS_AMSDU) {
1770293a2caeSAugustin Cavalier			m = ieee80211_decap_amsdu(ni, m);
1771293a2caeSAugustin Cavalier			if (m == NULL)
1772293a2caeSAugustin Cavalier				return IEEE80211_FC0_TYPE_DATA;
1773293a2caeSAugustin Cavalier		}
1774293a2caeSAugustin Cavalier		ieee80211_deliver_data(vap, ni, m);
1775293a2caeSAugustin Cavalier		return type;
1776293a2caeSAugustin Cavalier	case IEEE80211_FC0_TYPE_MGT:
1777293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_mgmt++;
1778293a2caeSAugustin Cavalier		IEEE80211_NODE_STAT(ni, rx_mgmt);
1779293a2caeSAugustin Cavalier		if (dir != IEEE80211_FC1_DIR_NODS) {
1780293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1781293a2caeSAugustin Cavalier			    wh, "mgt", "incorrect dir 0x%x", dir);
1782293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_wrongdir++;
1783293a2caeSAugustin Cavalier			goto err;
1784293a2caeSAugustin Cavalier		}
1785293a2caeSAugustin Cavalier		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
1786293a2caeSAugustin Cavalier			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1787293a2caeSAugustin Cavalier			    ni->ni_macaddr, "mgt", "too short: len %u",
1788293a2caeSAugustin Cavalier			    m->m_pkthdr.len);
1789293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_tooshort++;
1790293a2caeSAugustin Cavalier			goto out;
1791293a2caeSAugustin Cavalier		}
1792293a2caeSAugustin Cavalier#ifdef IEEE80211_DEBUG
17938244a9baSAugustin Cavalier		if ((ieee80211_msg_debug(vap) &&
1794293a2caeSAugustin Cavalier		    (vap->iv_ic->ic_flags & IEEE80211_F_SCAN)) ||
1795293a2caeSAugustin Cavalier		    ieee80211_msg_dumppkts(vap)) {
1796293a2caeSAugustin Cavalier			if_printf(ifp, "received %s from %s rssi %d\n",
1797293a2caeSAugustin Cavalier			    ieee80211_mgt_subtype_name(subtype),
1798293a2caeSAugustin Cavalier			    ether_sprintf(wh->i_addr2), rssi);
1799293a2caeSAugustin Cavalier		}
1800293a2caeSAugustin Cavalier#endif
1801293a2caeSAugustin Cavalier		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1802293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1803293a2caeSAugustin Cavalier			    wh, NULL, "%s", "WEP set but not permitted");
1804293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
1805293a2caeSAugustin Cavalier			goto out;
1806293a2caeSAugustin Cavalier		}
1807293a2caeSAugustin Cavalier		vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
1808293a2caeSAugustin Cavalier		goto out;
1809293a2caeSAugustin Cavalier	case IEEE80211_FC0_TYPE_CTL:
1810293a2caeSAugustin Cavalier		vap->iv_stats.is_rx_ctl++;
1811293a2caeSAugustin Cavalier		IEEE80211_NODE_STAT(ni, rx_ctrl);
1812293a2caeSAugustin Cavalier		goto out;
1813293a2caeSAugustin Cavalier	default:
1814293a2caeSAugustin Cavalier		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1815293a2caeSAugustin Cavalier		    wh, "bad", "frame type 0x%x", type);
1816293a2caeSAugustin Cavalier		/* should not come here */
1817293a2caeSAugustin Cavalier		break;
1818293a2caeSAugustin Cavalier	}
1819293a2caeSAugustin Cavaliererr:
1820293a2caeSAugustin Cavalier	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1821293a2caeSAugustin Cavalierout:
1822293a2caeSAugustin Cavalier	if (m != NULL) {
1823293a2caeSAugustin Cavalier		if (need_tap && ieee80211_radiotap_active_vap(vap))
1824293a2caeSAugustin Cavalier			ieee80211_radiotap_rx(vap, m);
1825293a2caeSAugustin Cavalier		m_freem(m);
1826293a2caeSAugustin Cavalier	}
1827293a2caeSAugustin Cavalier	return type;
1828293a2caeSAugustin Cavalier#undef	HAS_SEQ
1829293a2caeSAugustin Cavalier#undef	MC01
1830293a2caeSAugustin Cavalier}
1831293a2caeSAugustin Cavalier
1832293a2caeSAugustin Cavalierstatic void
1833293a2caeSAugustin Cavaliermesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
1834293a2caeSAugustin Cavalier    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
1835293a2caeSAugustin Cavalier{
1836293a2caeSAugustin Cavalier	struct ieee80211vap *vap = ni->ni_vap;
1837293a2caeSAugustin Cavalier	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1838293a2caeSAugustin Cavalier	struct ieee80211com *ic = ni->ni_ic;
1839293a2caeSAugustin Cavalier	struct ieee80211_channel *rxchan = ic->ic_curchan;
1840293a2caeSAugustin Cavalier	struct ieee80211_frame *wh;
1841293a2caeSAugustin Cavalier	struct ieee80211_mesh_route *rt;
1842293a2caeSAugustin Cavalier	uint8_t *frm, *efrm;
1843293a2caeSAugustin Cavalier
1844293a2caeSAugustin Cavalier	wh = mtod(m0, struct ieee80211_frame *);
1845293a2caeSAugustin Cavalier	frm = (uint8_t *)&wh[1];
1846293a2caeSAugustin Cavalier	efrm = mtod(m0, uint8_t *) + m0->m_len;
1847293a2caeSAugustin Cavalier	switch (subtype) {
1848293a2caeSAugustin Cavalier	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1849293a2caeSAugustin Cavalier	case IEEE80211_FC0_SUBTYPE_BEACON:
1850293a2caeSAugustin Cavalier	{
1851293a2caeSAugustin Cavalier		struct ieee80211_scanparams scan;
1852293a2caeSAugustin Cavalier		struct ieee80211_channel *c;
1853293a2caeSAugustin Cavalier		/*
1854293a2caeSAugustin Cavalier		 * We process beacon/probe response
1855293a2caeSAugustin Cavalier		 * frames to discover neighbors.
1856293a2caeSAugustin Cavalier		 */
1857293a2caeSAugustin Cavalier		if (rxs != NULL) {
1858293a2caeSAugustin Cavalier			c = ieee80211_lookup_channel_rxstatus(vap, rxs);
1859293a2caeSAugustin Cavalier			if (c != NULL)
1860293a2caeSAugustin Cavalier				rxchan = c;
1861293a2caeSAugustin Cavalier		}
1862293a2caeSAugustin Cavalier		if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0)
1863293a2caeSAugustin Cavalier			return;
1864293a2caeSAugustin Cavalier		/*
1865293a2caeSAugustin Cavalier		 * Count frame now that we know it's to be processed.
1866293a2caeSAugustin Cavalier		 */
1867293a2caeSAugustin Cavalier		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
1868293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_beacon++;	/* XXX remove */
1869293a2caeSAugustin Cavalier			IEEE80211_NODE_STAT(ni, rx_beacons);
1870293a2caeSAugustin Cavalier		} else
1871293a2caeSAugustin Cavalier			IEEE80211_NODE_STAT(ni, rx_proberesp);
1872293a2caeSAugustin Cavalier		/*
1873293a2caeSAugustin Cavalier		 * If scanning, just pass information to the scan module.
1874293a2caeSAugustin Cavalier		 */
1875293a2caeSAugustin Cavalier		if (ic->ic_flags & IEEE80211_F_SCAN) {
1876293a2caeSAugustin Cavalier			if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
1877293a2caeSAugustin Cavalier				/*
1878293a2caeSAugustin Cavalier				 * Actively scanning a channel marked passive;
1879293a2caeSAugustin Cavalier				 * send a probe request now that we know there
1880293a2caeSAugustin Cavalier				 * is 802.11 traffic present.
1881293a2caeSAugustin Cavalier				 *
1882293a2caeSAugustin Cavalier				 * XXX check if the beacon we recv'd gives
1883293a2caeSAugustin Cavalier				 * us what we need and suppress the probe req
1884293a2caeSAugustin Cavalier				 */
1885293a2caeSAugustin Cavalier				ieee80211_probe_curchan(vap, 1);
1886293a2caeSAugustin Cavalier				ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
1887293a2caeSAugustin Cavalier			}
1888293a2caeSAugustin Cavalier			ieee80211_add_scan(vap, rxchan, &scan, wh,
1889293a2caeSAugustin Cavalier			    subtype, rssi, nf);
1890293a2caeSAugustin Cavalier			return;
1891293a2caeSAugustin Cavalier		}
1892293a2caeSAugustin Cavalier
1893293a2caeSAugustin Cavalier		/* The rest of this code assumes we are running */
1894293a2caeSAugustin Cavalier		if (vap->iv_state != IEEE80211_S_RUN)
1895293a2caeSAugustin Cavalier			return;
1896293a2caeSAugustin Cavalier		/*
1897293a2caeSAugustin Cavalier		 * Ignore non-mesh STAs.
1898293a2caeSAugustin Cavalier		 */
1899293a2caeSAugustin Cavalier		if ((scan.capinfo &
1900293a2caeSAugustin Cavalier		     (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) ||
1901293a2caeSAugustin Cavalier		    scan.meshid == NULL || scan.meshconf == NULL) {
1902293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1903293a2caeSAugustin Cavalier			    wh, "beacon", "%s", "not a mesh sta");
1904293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_wrongmesh++;
1905293a2caeSAugustin Cavalier			return;
1906293a2caeSAugustin Cavalier		}
1907293a2caeSAugustin Cavalier		/*
1908293a2caeSAugustin Cavalier		 * Ignore STAs for other mesh networks.
1909293a2caeSAugustin Cavalier		 */
1910293a2caeSAugustin Cavalier		if (memcmp(scan.meshid+2, ms->ms_id, ms->ms_idlen) != 0 ||
1911293a2caeSAugustin Cavalier		    mesh_verify_meshconf(vap, scan.meshconf)) {
1912293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1913293a2caeSAugustin Cavalier			    wh, "beacon", "%s", "not for our mesh");
1914293a2caeSAugustin Cavalier			vap->iv_stats.is_mesh_wrongmesh++;
1915293a2caeSAugustin Cavalier			return;
1916293a2caeSAugustin Cavalier		}
1917293a2caeSAugustin Cavalier		/*
1918293a2caeSAugustin Cavalier		 * Peer only based on the current ACL policy.
1919293a2caeSAugustin Cavalier		 */
1920293a2caeSAugustin Cavalier		if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
1921293a2caeSAugustin Cavalier			IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
1922293a2caeSAugustin Cavalier			    wh, NULL, "%s", "disallowed by ACL");
1923293a2caeSAugustin Cavalier			vap->iv_stats.is_rx_acl++;
1924293a2caeSAugustin Cavalier			return;
1925293a2caeSAugustin Cavalier		}
1926293a2caeSAugustin Cavalier		/*
1927293a2caeSAugustin Cavalier		 * Do neighbor discovery.
1928293a2caeSAugustin Cavalier		 */
1929293a2caeSAugustin Cavalier		if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
1930293a2caeSAugustin Cavalier			/*
1931293a2caeSAugustin Cavalier			 * Create a new entry in the neighbor table.
1932293a2caeSAugustin Cavalier			 */
1933293a2caeSAugustin Cavalier			ni = ieee80211_add_neighbor(vap, wh, &scan);
1934293a2caeSAugustin Cavalier		}
1935293a2caeSAugustin Cavalier		/*
1936293a2caeSAugustin Cavalier		 * Automatically peer with discovered nodes if possible.
1937293a2caeSAugustin Cavalier		 */
1938293a2caeSAugustin Cavalier		if (ni != vap->iv_bss &&
1939293a2caeSAugustin Cavalier		    (ms->ms_flags & IEEE80211_MESHFLAGS_AP)) {
1940293a2caeSAugustin Cavalier			switch (ni->ni_mlstate) {
1941293a2caeSAugustin Cavalier			case IEEE80211_NODE_MESH_IDLE:
1942293a2caeSAugustin Cavalier			{
1943293a2caeSAugustin Cavalier				uint16_t args[1];
1944293a2caeSAugustin Cavalier
1945293a2caeSAugustin Cavalier				/* Wait for backoff callout to reset counter */
1946293a2caeSAugustin Cavalier				if (ni->ni_mlhcnt >= ieee80211_mesh_maxholding)
1947293a2caeSAugustin Cavalier					return;
1948293a2caeSAugustin Cavalier
1949293a2caeSAugustin Cavalier				ni->ni_mlpid = mesh_generateid(vap);
1950293a2caeSAugustin Cavalier				if (ni->ni_mlpid == 0)
1951293a2caeSAugustin Cavalier					return;
1952293a2caeSAugustin Cavalier				mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENSNT);
1953293a2caeSAugustin Cavalier				args[0] = ni->ni_mlpid;
1954293a2caeSAugustin Cavalier				ieee80211_send_action(ni,
1955293a2caeSAugustin Cavalier				IEEE80211_ACTION_CAT_SELF_PROT,
1956293a2caeSAugustin Cavalier				IEEE80211_ACTION_MESHPEERING_OPEN, args);
1957293a2caeSAugustin Cavalier				ni->ni_mlrcnt = 0;
1958293a2caeSAugustin Cavalier