kernel: Remove some unused variables.
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_mesh.c
1 /*- 
2  * Copyright (c) 2009 The FreeBSD Foundation 
3  * All rights reserved. 
4  * 
5  * This software was developed by Rui Paulo under sponsorship from the
6  * FreeBSD Foundation. 
7  *  
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions 
10  * are met: 
11  * 1. Redistributions of source code must retain the above copyright 
12  *    notice, this list of conditions and the following disclaimer. 
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
27  * SUCH DAMAGE. 
28  *
29  * $FreeBSD: head/sys/net80211/ieee80211_mesh.c 203423 2010-02-03 10:12:49Z rpaulo $
30  */ 
31
32 /*
33  * IEEE 802.11s Mesh Point (MBSS) support.
34  *
35  * Based on March 2009, D3.0 802.11s draft spec.
36  */
37 #include "opt_inet.h"
38 #include "opt_wlan.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h> 
42 #include <sys/mbuf.h>   
43 #include <sys/malloc.h>
44 #include <sys/kernel.h>
45
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/endian.h>
49 #include <sys/errno.h>
50 #include <sys/proc.h>
51 #include <sys/sysctl.h>
52
53 #include <net/if.h>
54 #include <net/if_media.h>
55 #include <net/if_llc.h>
56 #include <net/ethernet.h>
57 #include <net/route.h>
58
59 #include <netproto/802_11/ieee80211_var.h>
60 #include <netproto/802_11/ieee80211_action.h>
61 #include <netproto/802_11/ieee80211_input.h>
62 #include <netproto/802_11/ieee80211_mesh.h>
63
64 static void     mesh_rt_flush_invalid(struct ieee80211vap *);
65 static int      mesh_select_proto_path(struct ieee80211vap *, const char *);
66 static int      mesh_select_proto_metric(struct ieee80211vap *, const char *);
67 static void     mesh_vattach(struct ieee80211vap *);
68 static int      mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
69 static void     mesh_rt_cleanup_callout(void *);
70 static void     mesh_linkchange(struct ieee80211_node *,
71                     enum ieee80211_mesh_mlstate);
72 static void     mesh_checkid(void *, struct ieee80211_node *);
73 static uint32_t mesh_generateid(struct ieee80211vap *);
74 static int      mesh_checkpseq(struct ieee80211vap *,
75                     const uint8_t [IEEE80211_ADDR_LEN], uint32_t);
76 static struct ieee80211_node *
77                 mesh_find_txnode(struct ieee80211vap *,
78                     const uint8_t [IEEE80211_ADDR_LEN]);
79 static void     mesh_forward(struct ieee80211vap *, struct mbuf *,
80                     const struct ieee80211_meshcntl *);
81 static int      mesh_input(struct ieee80211_node *, struct mbuf *, int, int);
82 static void     mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
83                     int, int);
84 static void     mesh_peer_timeout_setup(struct ieee80211_node *);
85 static void     mesh_peer_timeout_backoff(struct ieee80211_node *);
86 static void     mesh_peer_timeout_callout(void *);
87 static __inline void
88                 mesh_peer_timeout_stop(struct ieee80211_node *);
89 static int      mesh_verify_meshid(struct ieee80211vap *, const uint8_t *);
90 static int      mesh_verify_meshconf(struct ieee80211vap *, const uint8_t *);
91 static int      mesh_verify_meshpeer(struct ieee80211vap *, uint8_t,
92                     const uint8_t *);
93 uint32_t        mesh_airtime_calc(struct ieee80211_node *);
94
95 /*
96  * Timeout values come from the specification and are in milliseconds.
97  */
98 SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0,
99     "IEEE 802.11s parameters");
100 static int ieee80211_mesh_retrytimeout = -1;
101 SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, retrytimeout, CTLTYPE_INT | CTLFLAG_RW,
102     &ieee80211_mesh_retrytimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
103     "Retry timeout (msec)");
104 static int ieee80211_mesh_holdingtimeout = -1;
105 SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, holdingtimeout, CTLTYPE_INT | CTLFLAG_RW,
106     &ieee80211_mesh_holdingtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
107     "Holding state timeout (msec)");
108 static int ieee80211_mesh_confirmtimeout = -1;
109 SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, confirmtimeout, CTLTYPE_INT | CTLFLAG_RW,
110     &ieee80211_mesh_confirmtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
111     "Confirm state timeout (msec)");
112 static int ieee80211_mesh_maxretries = 2;
113 SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLTYPE_INT | CTLFLAG_RW,
114     &ieee80211_mesh_maxretries, 0,
115     "Maximum retries during peer link establishment");
116
117 static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
118         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
119
120 static  ieee80211_recv_action_func mesh_recv_action_meshpeering_open;
121 static  ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm;
122 static  ieee80211_recv_action_func mesh_recv_action_meshpeering_close;
123 static  ieee80211_recv_action_func mesh_recv_action_meshlmetric_req;
124 static  ieee80211_recv_action_func mesh_recv_action_meshlmetric_rep;
125
126 static  ieee80211_send_action_func mesh_send_action_meshpeering_open;
127 static  ieee80211_send_action_func mesh_send_action_meshpeering_confirm;
128 static  ieee80211_send_action_func mesh_send_action_meshpeering_close;
129 static  ieee80211_send_action_func mesh_send_action_meshlink_request;
130 static  ieee80211_send_action_func mesh_send_action_meshlink_reply;
131
132 static const struct ieee80211_mesh_proto_metric mesh_metric_airtime = {
133         .mpm_descr      = "AIRTIME",
134         .mpm_ie         = IEEE80211_MESHCONF_METRIC_AIRTIME,
135         .mpm_metric     = mesh_airtime_calc,
136 };
137
138 static struct ieee80211_mesh_proto_path         mesh_proto_paths[4];
139 static struct ieee80211_mesh_proto_metric       mesh_proto_metrics[4];
140
141 MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
142
143 /*
144  * Helper functions to manipulate the Mesh routing table.
145  */
146
147 static struct ieee80211_mesh_route *
148 mesh_rt_find_locked(struct ieee80211_mesh_state *ms,
149     const uint8_t dest[IEEE80211_ADDR_LEN])
150 {
151         struct ieee80211_mesh_route *rt;
152
153         TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
154                 if (IEEE80211_ADDR_EQ(dest, rt->rt_dest))
155                         return rt;
156         }
157         return NULL;
158 }
159
160 static struct ieee80211_mesh_route *
161 mesh_rt_add_locked(struct ieee80211_mesh_state *ms,
162     const uint8_t dest[IEEE80211_ADDR_LEN])
163 {
164         struct ieee80211_mesh_route *rt;
165
166         KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
167             ("%s: adding broadcast to the routing table", __func__));
168
169         rt = kmalloc(ALIGN(sizeof(struct ieee80211_mesh_route)) +
170             ms->ms_ppath->mpp_privlen, M_80211_MESH_RT, M_INTWAIT | M_ZERO);
171         if (rt != NULL) {
172                 IEEE80211_ADDR_COPY(rt->rt_dest, dest);
173                 rt->rt_priv = (void *)ALIGN(&rt[1]);
174                 rt->rt_crtime = ticks;
175                 TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
176         }
177         return rt;
178 }
179
180 struct ieee80211_mesh_route *
181 ieee80211_mesh_rt_find(struct ieee80211vap *vap,
182     const uint8_t dest[IEEE80211_ADDR_LEN])
183 {
184         struct ieee80211_mesh_state *ms = vap->iv_mesh;
185         struct ieee80211_mesh_route *rt;
186
187         rt = mesh_rt_find_locked(ms, dest);
188         return rt;
189 }
190
191 struct ieee80211_mesh_route *
192 ieee80211_mesh_rt_add(struct ieee80211vap *vap,
193     const uint8_t dest[IEEE80211_ADDR_LEN])
194 {
195         struct ieee80211_mesh_state *ms = vap->iv_mesh;
196         struct ieee80211_mesh_route *rt;
197
198         KASSERT(ieee80211_mesh_rt_find(vap, dest) == NULL,
199             ("%s: duplicate entry in the routing table", __func__));
200         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
201             ("%s: adding self to the routing table", __func__));
202
203         rt = mesh_rt_add_locked(ms, dest);
204         return rt;
205 }
206
207 /*
208  * Add a proxy route (as needed) for the specified destination.
209  */
210 void
211 ieee80211_mesh_proxy_check(struct ieee80211vap *vap,
212     const uint8_t dest[IEEE80211_ADDR_LEN])
213 {
214         struct ieee80211_mesh_state *ms = vap->iv_mesh;
215         struct ieee80211_mesh_route *rt;
216
217         rt = mesh_rt_find_locked(ms, dest);
218         if (rt == NULL) {
219                 rt = mesh_rt_add_locked(ms, dest);
220                 if (rt == NULL) {
221                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
222                             "%s", "unable to add proxy entry");
223                         vap->iv_stats.is_mesh_rtaddfailed++;
224                 } else {
225                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
226                             "%s", "add proxy entry");
227                         IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
228                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
229                                      |  IEEE80211_MESHRT_FLAGS_PROXY;
230                 }
231         /* XXX assert PROXY? */
232         } else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
233                 struct ieee80211com *ic = vap->iv_ic;
234                 /*
235                  * Fix existing entry created by received frames from
236                  * stations that have some memory of dest.  We also
237                  * flush any frames held on the staging queue; delivering
238                  * them is too much trouble right now.
239                  */
240                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
241                     "%s", "fix proxy entry");
242                 IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
243                 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
244                              |  IEEE80211_MESHRT_FLAGS_PROXY;
245                 /* XXX belongs in hwmp */
246                 ieee80211_ageq_drain_node(&ic->ic_stageq,
247                    (void *)(uintptr_t) ieee80211_mac_hash(ic, dest));
248                 /* XXX stat? */
249         }
250 }
251
252 static __inline void
253 mesh_rt_del(struct ieee80211_mesh_state *ms, struct ieee80211_mesh_route *rt)
254 {
255         TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
256         kfree(rt, M_80211_MESH_RT);
257 }
258
259 void
260 ieee80211_mesh_rt_del(struct ieee80211vap *vap,
261     const uint8_t dest[IEEE80211_ADDR_LEN])
262 {
263         struct ieee80211_mesh_state *ms = vap->iv_mesh;
264         struct ieee80211_mesh_route *rt, *next;
265
266         TAILQ_FOREACH_MUTABLE(rt, &ms->ms_routes, rt_next, next) {
267                 if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) {
268                         mesh_rt_del(ms, rt);
269                         return;
270                 }
271         }
272 }
273
274 void
275 ieee80211_mesh_rt_flush(struct ieee80211vap *vap)
276 {
277         struct ieee80211_mesh_state *ms = vap->iv_mesh;
278         struct ieee80211_mesh_route *rt, *next;
279
280         if (ms == NULL)
281                 return;
282         TAILQ_FOREACH_MUTABLE(rt, &ms->ms_routes, rt_next, next)
283                 mesh_rt_del(ms, rt);
284 }
285
286 void
287 ieee80211_mesh_rt_flush_peer(struct ieee80211vap *vap,
288     const uint8_t peer[IEEE80211_ADDR_LEN])
289 {
290         struct ieee80211_mesh_state *ms = vap->iv_mesh;
291         struct ieee80211_mesh_route *rt, *next;
292
293         TAILQ_FOREACH_MUTABLE(rt, &ms->ms_routes, rt_next, next) {
294                 if (IEEE80211_ADDR_EQ(rt->rt_nexthop, peer))
295                         mesh_rt_del(ms, rt);
296         }
297 }
298
299 /*
300  * Flush expired routing entries, i.e. those in invalid state for
301  * some time.
302  */
303 static void
304 mesh_rt_flush_invalid(struct ieee80211vap *vap)
305 {
306         struct ieee80211_mesh_state *ms = vap->iv_mesh;
307         struct ieee80211_mesh_route *rt, *next;
308
309         if (ms == NULL)
310                 return;
311         TAILQ_FOREACH_MUTABLE(rt, &ms->ms_routes, rt_next, next) {
312                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 &&
313                     ticks - rt->rt_crtime >= ms->ms_ppath->mpp_inact)
314                         mesh_rt_del(ms, rt);
315         }
316 }
317
318 int
319 ieee80211_mesh_register_proto_path(const struct ieee80211_mesh_proto_path *mpp)
320 {
321         int i, firstempty = -1;
322
323         for (i = 0; i < NELEM(mesh_proto_paths); i++) {
324                 if (strncmp(mpp->mpp_descr, mesh_proto_paths[i].mpp_descr,
325                     IEEE80211_MESH_PROTO_DSZ) == 0)
326                         return EEXIST;
327                 if (!mesh_proto_paths[i].mpp_active && firstempty == -1)
328                         firstempty = i;
329         }
330         if (firstempty < 0)
331                 return ENOSPC;
332         memcpy(&mesh_proto_paths[firstempty], mpp, sizeof(*mpp));
333         mesh_proto_paths[firstempty].mpp_active = 1;
334         return 0;
335 }
336
337 int
338 ieee80211_mesh_register_proto_metric(const struct
339     ieee80211_mesh_proto_metric *mpm)
340 {
341         int i, firstempty = -1;
342
343         for (i = 0; i < NELEM(mesh_proto_metrics); i++) {
344                 if (strncmp(mpm->mpm_descr, mesh_proto_metrics[i].mpm_descr,
345                     IEEE80211_MESH_PROTO_DSZ) == 0)
346                         return EEXIST;
347                 if (!mesh_proto_metrics[i].mpm_active && firstempty == -1)
348                         firstempty = i;
349         }
350         if (firstempty < 0)
351                 return ENOSPC;
352         memcpy(&mesh_proto_metrics[firstempty], mpm, sizeof(*mpm));
353         mesh_proto_metrics[firstempty].mpm_active = 1;
354         return 0;
355 }
356
357 static int
358 mesh_select_proto_path(struct ieee80211vap *vap, const char *name)
359 {
360         struct ieee80211_mesh_state *ms = vap->iv_mesh;
361         int i;
362
363         for (i = 0; i < NELEM(mesh_proto_paths); i++) {
364                 if (strcasecmp(mesh_proto_paths[i].mpp_descr, name) == 0) {
365                         ms->ms_ppath = &mesh_proto_paths[i];
366                         return 0;
367                 }
368         }
369         return ENOENT;
370 }
371
372 static int
373 mesh_select_proto_metric(struct ieee80211vap *vap, const char *name)
374 {
375         struct ieee80211_mesh_state *ms = vap->iv_mesh;
376         int i;
377
378         for (i = 0; i < NELEM(mesh_proto_metrics); i++) {
379                 if (strcasecmp(mesh_proto_metrics[i].mpm_descr, name) == 0) {
380                         ms->ms_pmetric = &mesh_proto_metrics[i];
381                         return 0;
382                 }
383         }
384         return ENOENT;
385 }
386
387 static void
388 ieee80211_mesh_init(void)
389 {
390
391         memset(mesh_proto_paths, 0, sizeof(mesh_proto_paths));
392         memset(mesh_proto_metrics, 0, sizeof(mesh_proto_metrics));
393
394         /*
395          * Setup mesh parameters that depends on the clock frequency.
396          */
397         ieee80211_mesh_retrytimeout = msecs_to_ticks(40);
398         ieee80211_mesh_holdingtimeout = msecs_to_ticks(40);
399         ieee80211_mesh_confirmtimeout = msecs_to_ticks(40);
400
401         /*
402          * Register action frame handlers.
403          */
404         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
405             IEEE80211_ACTION_MESHPEERING_OPEN,
406             mesh_recv_action_meshpeering_open);
407         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
408             IEEE80211_ACTION_MESHPEERING_CONFIRM,
409             mesh_recv_action_meshpeering_confirm);
410         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
411             IEEE80211_ACTION_MESHPEERING_CLOSE,
412             mesh_recv_action_meshpeering_close);
413         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
414             IEEE80211_ACTION_MESHLMETRIC_REQ, mesh_recv_action_meshlmetric_req);
415         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
416             IEEE80211_ACTION_MESHLMETRIC_REP, mesh_recv_action_meshlmetric_rep);
417
418         ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING, 
419             IEEE80211_ACTION_MESHPEERING_OPEN,
420             mesh_send_action_meshpeering_open);
421         ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING, 
422             IEEE80211_ACTION_MESHPEERING_CONFIRM,
423             mesh_send_action_meshpeering_confirm);
424         ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING, 
425             IEEE80211_ACTION_MESHPEERING_CLOSE,
426             mesh_send_action_meshpeering_close);
427         ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC, 
428             IEEE80211_ACTION_MESHLMETRIC_REQ,
429             mesh_send_action_meshlink_request);
430         ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC, 
431             IEEE80211_ACTION_MESHLMETRIC_REP,
432             mesh_send_action_meshlink_reply);
433
434         /*
435          * Register Airtime Link Metric.
436          */
437         ieee80211_mesh_register_proto_metric(&mesh_metric_airtime);
438
439 }
440 SYSINIT(wlan_mesh, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_mesh_init, NULL);
441
442 void
443 ieee80211_mesh_attach(struct ieee80211com *ic)
444 {
445         ic->ic_vattach[IEEE80211_M_MBSS] = mesh_vattach;
446 }
447
448 void
449 ieee80211_mesh_detach(struct ieee80211com *ic)
450 {
451 }
452
453 static void
454 mesh_vdetach_peers(void *arg, struct ieee80211_node *ni)
455 {
456         struct ieee80211com *ic = ni->ni_ic;
457         uint16_t args[3];
458
459         if (ni->ni_mlstate == IEEE80211_NODE_MESH_ESTABLISHED) {
460                 args[0] = ni->ni_mlpid;
461                 args[1] = ni->ni_mllid;
462                 args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
463                 ieee80211_send_action(ni,
464                     IEEE80211_ACTION_CAT_MESHPEERING,
465                     IEEE80211_ACTION_MESHPEERING_CLOSE,
466                     args);
467         }
468         callout_stop(&ni->ni_mltimer);
469         /* XXX belongs in hwmp */
470         ieee80211_ageq_drain_node(&ic->ic_stageq,
471            (void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr));
472 }
473
474 static void
475 mesh_vdetach(struct ieee80211vap *vap)
476 {
477         struct ieee80211_mesh_state *ms = vap->iv_mesh;
478
479         callout_stop(&ms->ms_cleantimer);
480         ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers,
481             NULL);
482         ieee80211_mesh_rt_flush(vap);
483         ms->ms_ppath->mpp_vdetach(vap);
484         kfree(vap->iv_mesh, M_80211_VAP);
485         vap->iv_mesh = NULL;
486 }
487
488 static void
489 mesh_vattach(struct ieee80211vap *vap)
490 {
491         struct ieee80211_mesh_state *ms;
492         vap->iv_newstate = mesh_newstate;
493         vap->iv_input = mesh_input;
494         vap->iv_opdetach = mesh_vdetach;
495         vap->iv_recv_mgmt = mesh_recv_mgmt;
496         ms = kmalloc(sizeof(struct ieee80211_mesh_state), M_80211_VAP,
497             M_INTWAIT | M_ZERO);
498         if (ms == NULL) {
499                 kprintf("%s: couldn't alloc MBSS state\n", __func__);
500                 return;
501         }
502         vap->iv_mesh = ms;
503         ms->ms_seq = 0;
504         ms->ms_flags = (IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_FWD);
505         ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL;
506         TAILQ_INIT(&ms->ms_routes);
507         callout_init_mp(&ms->ms_cleantimer);
508         mesh_select_proto_metric(vap, "AIRTIME");
509         KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
510         mesh_select_proto_path(vap, "HWMP");
511         KASSERT(ms->ms_ppath, ("ms_ppath == NULL"));
512         ms->ms_ppath->mpp_vattach(vap);
513 }
514
515 /*
516  * IEEE80211_M_MBSS vap state machine handler.
517  */
518 static int
519 mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
520 {
521         struct ieee80211_mesh_state *ms = vap->iv_mesh;
522         struct ieee80211com *ic = vap->iv_ic;
523         struct ieee80211_node *ni;
524         enum ieee80211_state ostate;
525
526         ostate = vap->iv_state;
527         IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
528             __func__, ieee80211_state_name[ostate],
529             ieee80211_state_name[nstate], arg);
530         vap->iv_state = nstate;         /* state transition */
531         if (ostate != IEEE80211_S_SCAN)
532                 ieee80211_cancel_scan(vap);     /* background scan */
533         ni = vap->iv_bss;                       /* NB: no reference held */
534         if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
535                 callout_stop(&ms->ms_cleantimer);
536         switch (nstate) {
537         case IEEE80211_S_INIT:
538                 switch (ostate) {
539                 case IEEE80211_S_SCAN:
540                         ieee80211_cancel_scan(vap);
541                         break;
542                 case IEEE80211_S_CAC:
543                         ieee80211_dfs_cac_stop(vap);
544                         break;
545                 case IEEE80211_S_RUN:
546                         ieee80211_iterate_nodes(&ic->ic_sta,
547                             mesh_vdetach_peers, NULL);
548                         break;
549                 default:
550                         break;
551                 }
552                 if (ostate != IEEE80211_S_INIT) {
553                         /* NB: optimize INIT -> INIT case */
554                         ieee80211_reset_bss(vap);
555                         ieee80211_mesh_rt_flush(vap);
556                 }
557                 break;
558         case IEEE80211_S_SCAN:
559                 switch (ostate) {
560                 case IEEE80211_S_INIT:
561                         if (vap->iv_des_chan != IEEE80211_CHAN_ANYC &&
562                             !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan) &&
563                             ms->ms_idlen != 0) {
564                                 /*
565                                  * Already have a channel and a mesh ID; bypass
566                                  * the scan and startup immediately.
567                                  */
568                                 ieee80211_create_ibss(vap, vap->iv_des_chan);
569                                 break;
570                         }
571                         /*
572                          * Initiate a scan.  We can come here as a result
573                          * of an IEEE80211_IOC_SCAN_REQ too in which case
574                          * the vap will be marked with IEEE80211_FEXT_SCANREQ
575                          * and the scan request parameters will be present
576                          * in iv_scanreq.  Otherwise we do the default.
577                         */
578                         if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
579                                 ieee80211_check_scan(vap,
580                                     vap->iv_scanreq_flags,
581                                     vap->iv_scanreq_duration,
582                                     vap->iv_scanreq_mindwell,
583                                     vap->iv_scanreq_maxdwell,
584                                     vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
585                                 vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
586                         } else
587                                 ieee80211_check_scan_current(vap);
588                         break;
589                 default:
590                         break;
591                 }
592                 break;
593         case IEEE80211_S_CAC:
594                 /*
595                  * Start CAC on a DFS channel.  We come here when starting
596                  * a bss on a DFS channel (see ieee80211_create_ibss).
597                  */
598                 ieee80211_dfs_cac_start(vap);
599                 break;
600         case IEEE80211_S_RUN:
601                 switch (ostate) {
602                 case IEEE80211_S_INIT:
603                         /*
604                          * Already have a channel; bypass the
605                          * scan and startup immediately.
606                          * Note that ieee80211_create_ibss will call
607                          * back to do a RUN->RUN state change.
608                          */
609                         ieee80211_create_ibss(vap,
610                             ieee80211_ht_adjust_channel(ic,
611                                 ic->ic_curchan, vap->iv_flags_ht));
612                         /* NB: iv_bss is changed on return */
613                         break;
614                 case IEEE80211_S_CAC:
615                         /*
616                          * NB: This is the normal state change when CAC
617                          * expires and no radar was detected; no need to
618                          * clear the CAC timer as it's already expired.
619                          */
620                         /* fall thru... */
621                 case IEEE80211_S_CSA:
622 #if 0
623                         /*
624                          * Shorten inactivity timer of associated stations
625                          * to weed out sta's that don't follow a CSA.
626                          */
627                         ieee80211_iterate_nodes(&ic->ic_sta, sta_csa, vap);
628 #endif
629                         /*
630                          * Update bss node channel to reflect where
631                          * we landed after CSA.
632                          */
633                         ieee80211_node_set_chan(vap->iv_bss,
634                             ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
635                                 ieee80211_htchanflags(vap->iv_bss->ni_chan)));
636                         /* XXX bypass debug msgs */
637                         break;
638                 case IEEE80211_S_SCAN:
639                 case IEEE80211_S_RUN:
640 #ifdef IEEE80211_DEBUG
641                         if (ieee80211_msg_debug(vap)) {
642                                 struct ieee80211_node *ni = vap->iv_bss;
643                                 ieee80211_note(vap,
644                                     "synchronized with %6D meshid ",
645                                     ni->ni_meshid, ":");
646                                 ieee80211_print_essid(ni->ni_meshid,
647                                     ni->ni_meshidlen);
648                                 /* XXX MCS/HT */
649                                 kprintf(" channel %d\n",
650                                     ieee80211_chan2ieee(ic, ic->ic_curchan));
651                         }
652 #endif
653                         break;
654                 default:
655                         break;
656                 }
657                 ieee80211_node_authorize(vap->iv_bss);
658                 callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
659                     mesh_rt_cleanup_callout, vap);
660                 break;
661         default:
662                 break;
663         }
664         /* NB: ostate not nstate */
665         ms->ms_ppath->mpp_newstate(vap, ostate, arg);
666         return 0;
667 }
668
669 static void
670 mesh_rt_cleanup_callout(void *arg)
671 {
672         struct ieee80211vap *vap = arg;
673         struct ieee80211_mesh_state *ms = vap->iv_mesh;
674
675         wlan_serialize_enter();
676         mesh_rt_flush_invalid(vap);
677         callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
678                       mesh_rt_cleanup_callout, vap);
679         wlan_serialize_exit();
680 }
681
682
683 /*
684  * Helper function to note the Mesh Peer Link FSM change.
685  */
686 static void
687 mesh_linkchange(struct ieee80211_node *ni, enum ieee80211_mesh_mlstate state)
688 {
689         struct ieee80211vap *vap = ni->ni_vap;
690         struct ieee80211_mesh_state *ms = vap->iv_mesh;
691 #ifdef IEEE80211_DEBUG
692         static const char *meshlinkstates[] = {
693                 [IEEE80211_NODE_MESH_IDLE]              = "IDLE",
694                 [IEEE80211_NODE_MESH_OPENSNT]           = "OPEN SENT",
695                 [IEEE80211_NODE_MESH_OPENRCV]           = "OPEN RECEIVED",
696                 [IEEE80211_NODE_MESH_CONFIRMRCV]        = "CONFIRM RECEIVED",
697                 [IEEE80211_NODE_MESH_ESTABLISHED]       = "ESTABLISHED",
698                 [IEEE80211_NODE_MESH_HOLDING]           = "HOLDING"
699         };
700 #endif
701         IEEE80211_NOTE(vap, IEEE80211_MSG_MESH,
702             ni, "peer link: %s -> %s",
703             meshlinkstates[ni->ni_mlstate], meshlinkstates[state]);
704
705         /* track neighbor count */
706         if (state == IEEE80211_NODE_MESH_ESTABLISHED &&
707             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
708                 KASSERT(ms->ms_neighbors < 65535, ("neighbor count overflow"));
709                 ms->ms_neighbors++;
710                 ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
711         } else if (ni->ni_mlstate == IEEE80211_NODE_MESH_ESTABLISHED &&
712             state != IEEE80211_NODE_MESH_ESTABLISHED) {
713                 KASSERT(ms->ms_neighbors > 0, ("neighbor count 0"));
714                 ms->ms_neighbors--;
715                 ieee80211_beacon_notify(vap, IEEE80211_BEACON_MESHCONF);
716         }
717         ni->ni_mlstate = state;
718         switch (state) {
719         case IEEE80211_NODE_MESH_HOLDING:
720                 ms->ms_ppath->mpp_peerdown(ni);
721                 break;
722         case IEEE80211_NODE_MESH_ESTABLISHED:
723                 ieee80211_mesh_discover(vap, ni->ni_macaddr, NULL);
724                 break;
725         default:
726                 break;
727         }
728 }
729
730 /*
731  * Helper function to generate a unique local ID required for mesh
732  * peer establishment.
733  */
734 static void
735 mesh_checkid(void *arg, struct ieee80211_node *ni)
736 {
737         uint16_t *r = arg;
738         
739         if (*r == ni->ni_mllid)
740                 *(uint16_t *)arg = 0;
741 }
742
743 static uint32_t
744 mesh_generateid(struct ieee80211vap *vap)
745 {
746         int maxiter = 4;
747         uint16_t r;
748
749         do {
750                 get_random_bytes(&r, 2);
751                 ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_checkid, &r);
752                 maxiter--;
753         } while (r == 0 && maxiter > 0);
754         return r;
755 }
756
757 /*
758  * Verifies if we already received this packet by checking its
759  * sequence number.
760  * Returns 0 if the frame is to be accepted, 1 otherwise.
761  */
762 static int
763 mesh_checkpseq(struct ieee80211vap *vap,
764     const uint8_t source[IEEE80211_ADDR_LEN], uint32_t seq)
765 {
766         struct ieee80211_mesh_route *rt;
767
768         rt = ieee80211_mesh_rt_find(vap, source);
769         if (rt == NULL) {
770                 rt = ieee80211_mesh_rt_add(vap, source);
771                 if (rt == NULL) {
772                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
773                             "%s", "add mcast route failed");
774                         vap->iv_stats.is_mesh_rtaddfailed++;
775                         return 1;
776                 }
777                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
778                     "add mcast route, mesh seqno %d", seq);
779                 rt->rt_lastmseq = seq;
780                 return 0;
781         }
782         if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
783                 return 1;
784         } else {
785                 rt->rt_lastmseq = seq;
786                 return 0;
787         }
788 }
789
790 /*
791  * Iterate the routing table and locate the next hop.
792  */
793 static struct ieee80211_node *
794 mesh_find_txnode(struct ieee80211vap *vap,
795     const uint8_t dest[IEEE80211_ADDR_LEN])
796 {
797         struct ieee80211_mesh_route *rt;
798
799         rt = ieee80211_mesh_rt_find(vap, dest);
800         if (rt == NULL)
801                 return NULL;
802         if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
803             (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
804                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
805                     "%s: !valid or proxy, flags 0x%x", __func__, rt->rt_flags);
806                 /* XXX stat */
807                 return NULL;
808         }
809         return ieee80211_find_txnode(vap, rt->rt_nexthop);
810 }
811
812 /*
813  * Forward the specified frame.
814  * Decrement the TTL and set TA to our MAC address.
815  */
816 static void
817 mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
818     const struct ieee80211_meshcntl *mc)
819 {
820         struct ieee80211com *ic = vap->iv_ic;
821         struct ieee80211_mesh_state *ms = vap->iv_mesh;
822         struct ifnet *ifp = vap->iv_ifp;
823         struct ifnet *parent = ic->ic_ifp;
824         const struct ieee80211_frame *wh =
825             mtod(m, const struct ieee80211_frame *);
826         struct mbuf *mcopy;
827         struct ieee80211_meshcntl *mccopy;
828         struct ieee80211_frame *whcopy;
829         struct ieee80211_node *ni;
830         int err;
831
832         if (mc->mc_ttl == 0) {
833                 IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
834                     "%s", "frame not fwd'd, ttl 0");
835                 vap->iv_stats.is_mesh_fwd_ttl++;
836                 return;
837         }
838         if (!(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
839                 IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
840                     "%s", "frame not fwd'd, fwding disabled");
841                 vap->iv_stats.is_mesh_fwd_disabled++;
842                 return;
843         }
844         mcopy = m_dup(m, MB_DONTWAIT);
845         if (mcopy == NULL) {
846                 IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
847                     "%s", "frame not fwd'd, cannot dup");
848                 vap->iv_stats.is_mesh_fwd_nobuf++;
849                 ifp->if_oerrors++;
850                 return;
851         }
852         mcopy = m_pullup(mcopy, ieee80211_hdrspace(ic, wh) +
853             sizeof(struct ieee80211_meshcntl));
854         if (mcopy == NULL) {
855                 IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
856                     "%s", "frame not fwd'd, too short");
857                 vap->iv_stats.is_mesh_fwd_tooshort++;
858                 ifp->if_oerrors++;
859                 m_freem(mcopy);
860                 return;
861         }
862         whcopy = mtod(mcopy, struct ieee80211_frame *);
863         mccopy = (struct ieee80211_meshcntl *)
864             (mtod(mcopy, uint8_t *) + ieee80211_hdrspace(ic, wh));
865         /* XXX clear other bits? */
866         whcopy->i_fc[1] &= ~IEEE80211_FC1_RETRY;
867         IEEE80211_ADDR_COPY(whcopy->i_addr2, vap->iv_myaddr);
868         if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
869                 ni = ieee80211_ref_node(vap->iv_bss);
870                 mcopy->m_flags |= M_MCAST;
871         } else {
872                 ni = mesh_find_txnode(vap, whcopy->i_addr3);
873                 if (ni == NULL) {
874                         IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
875                             "%s", "frame not fwd'd, no path");
876                         vap->iv_stats.is_mesh_fwd_nopath++;
877                         m_freem(mcopy);
878                         return;
879                 }
880                 IEEE80211_ADDR_COPY(whcopy->i_addr1, ni->ni_macaddr);
881         }
882         KASSERT(mccopy->mc_ttl > 0, ("%s called with wrong ttl", __func__));
883         mccopy->mc_ttl--;
884
885         /* XXX calculate priority so drivers can find the tx queue */
886         M_WME_SETAC(mcopy, WME_AC_BE);
887
888         /* XXX do we know m_nextpkt is NULL? */
889         mcopy->m_pkthdr.rcvif = (void *) ni;
890         err = ieee80211_handoff(parent, mcopy);
891         if (err != 0) {
892                 /* NB: IFQ_HANDOFF reclaims mbuf */
893                 ieee80211_free_node(ni);
894         } else {
895                 ifp->if_opackets++;
896         }
897 }
898
899 static struct mbuf *
900 mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
901 {
902 #define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
903         uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
904                   sizeof(struct ieee80211_meshcntl_ae11)];
905         const struct ieee80211_qosframe_addr4 *wh;
906         const struct ieee80211_meshcntl_ae10 *mc;
907         struct ether_header *eh;
908         struct llc *llc;
909         int ae;
910
911         if (m->m_len < hdrlen + sizeof(*llc) &&
912             (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
913                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
914                     "discard data frame: %s", "m_pullup failed");
915                 vap->iv_stats.is_rx_tooshort++;
916                 return NULL;
917         }
918         memcpy(b, mtod(m, caddr_t), hdrlen);
919         wh = (const struct ieee80211_qosframe_addr4 *)&b[0];
920         mc = (const struct ieee80211_meshcntl_ae10 *)&b[hdrlen - meshdrlen];
921         KASSERT(WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS ||
922                 WHDIR(wh) == IEEE80211_FC1_DIR_DSTODS,
923             ("bogus dir, fc 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
924
925         llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
926         if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
927             llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
928             llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 &&
929             !(llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) {
930                 m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
931                 llc = NULL;
932         } else {
933                 m_adj(m, hdrlen - sizeof(*eh));
934         }
935         eh = mtod(m, struct ether_header *);
936         ae = mc->mc_flags & 3;
937         if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
938                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
939                 if (ae == 0) {
940                         IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
941                 } else if (ae == 1) {
942                         IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
943                 } else {
944                         IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
945                             (const struct ieee80211_frame *)wh, NULL,
946                             "bad AE %d", ae);
947                         vap->iv_stats.is_mesh_badae++;
948                         m_freem(m);
949                         return NULL;
950                 }
951         } else {
952                 if (ae == 0) {
953                         IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
954                         IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
955                 } else if (ae == 2) {
956                         IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
957                         IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
958                 } else {
959                         IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
960                             (const struct ieee80211_frame *)wh, NULL,
961                             "bad AE %d", ae);
962                         vap->iv_stats.is_mesh_badae++;
963                         m_freem(m);
964                         return NULL;
965                 }
966         }
967 #ifdef ALIGNED_POINTER
968         if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
969                 m = ieee80211_realign(vap, m, sizeof(*eh));
970                 if (m == NULL)
971                         return NULL;
972         }
973 #endif /* ALIGNED_POINTER */
974         if (llc != NULL) {
975                 eh = mtod(m, struct ether_header *);
976                 eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
977         }
978         return m;
979 #undef WDIR
980 }
981
982 /*
983  * Return non-zero if the unicast mesh data frame should be processed
984  * locally.  Frames that are not proxy'd have our address, otherwise
985  * we need to consult the routing table to look for a proxy entry.
986  */
987 static __inline int
988 mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
989     const struct ieee80211_meshcntl *mc)
990 {
991         int ae = mc->mc_flags & 3;
992
993         KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
994             ("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
995         KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
996         if (ae == 2) {                          /* ucast w/ proxy */
997                 const struct ieee80211_meshcntl_ae10 *mc10 =
998                     (const struct ieee80211_meshcntl_ae10 *) mc;
999                 struct ieee80211_mesh_route *rt =
1000                     ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
1001                 /* check for proxy route to ourself */
1002                 return (rt != NULL &&
1003                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
1004         } else                                  /* ucast w/o proxy */
1005                 return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
1006 }
1007
1008 static int
1009 mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
1010 {
1011 #define SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
1012 #define HAS_SEQ(type)   ((type & 0x4) == 0)
1013         struct ieee80211vap *vap = ni->ni_vap;
1014         struct ieee80211com *ic = ni->ni_ic;
1015         struct ifnet *ifp = vap->iv_ifp;
1016         struct ieee80211_frame *wh;
1017         const struct ieee80211_meshcntl *mc;
1018         int hdrspace, meshdrlen, need_tap;
1019         uint8_t dir, type, subtype, qos;
1020         uint32_t seq;
1021         uint8_t *addr;
1022         ieee80211_seq rxseq;
1023
1024         KASSERT(ni != NULL, ("null node"));
1025         ni->ni_inact = ni->ni_inact_reload;
1026
1027         need_tap = 1;                   /* mbuf need to be tapped. */
1028         type = -1;                      /* undefined */
1029
1030         if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
1031                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1032                     ni->ni_macaddr, NULL,
1033                     "too short (1): len %u", m->m_pkthdr.len);
1034                 vap->iv_stats.is_rx_tooshort++;
1035                 goto out;
1036         }
1037         /*
1038          * Bit of a cheat here, we use a pointer for a 3-address
1039          * frame format but don't reference fields past outside
1040          * ieee80211_frame_min w/o first validating the data is
1041          * present.
1042         */
1043         wh = mtod(m, struct ieee80211_frame *);
1044
1045         if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
1046             IEEE80211_FC0_VERSION_0) {
1047                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1048                     ni->ni_macaddr, NULL, "wrong version %x", wh->i_fc[0]);
1049                 vap->iv_stats.is_rx_badversion++;
1050                 goto err;
1051         }
1052         dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
1053         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
1054         subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
1055         if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
1056                 IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
1057                 ni->ni_noise = nf;
1058                 if (HAS_SEQ(type)) {
1059                         uint8_t tid = ieee80211_gettid(wh);
1060
1061                         if (IEEE80211_QOS_HAS_SEQ(wh) &&
1062                             TID_TO_WME_AC(tid) >= WME_AC_VI)
1063                                 ic->ic_wme.wme_hipri_traffic++;
1064                         rxseq = le16toh(*(uint16_t *)wh->i_seq);
1065                         if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
1066                             (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
1067                             SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
1068                                 /* duplicate, discard */
1069                                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
1070                                     wh->i_addr1, "duplicate",
1071                                     "seqno <%u,%u> fragno <%u,%u> tid %u",
1072                                     rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
1073                                     ni->ni_rxseqs[tid] >>
1074                                     IEEE80211_SEQ_SEQ_SHIFT,
1075                                     rxseq & IEEE80211_SEQ_FRAG_MASK,
1076                                     ni->ni_rxseqs[tid] &
1077                                     IEEE80211_SEQ_FRAG_MASK,
1078                                     tid);
1079                                 vap->iv_stats.is_rx_dup++;
1080                                 IEEE80211_NODE_STAT(ni, rx_dup);
1081                                 goto out;
1082                         }
1083                         ni->ni_rxseqs[tid] = rxseq;
1084                 }
1085         }
1086 #ifdef IEEE80211_DEBUG
1087         /*
1088          * It's easier, but too expensive, to simulate different mesh
1089          * topologies by consulting the ACL policy very early, so do this
1090          * only under DEBUG.
1091          *
1092          * NB: this check is also done upon peering link initiation.
1093          */
1094         if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh->i_addr2)) {
1095                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
1096                     wh, NULL, "%s", "disallowed by ACL");
1097                 vap->iv_stats.is_rx_acl++;
1098                 goto out;
1099         }
1100 #endif
1101         switch (type) {
1102         case IEEE80211_FC0_TYPE_DATA:
1103                 if (ni == vap->iv_bss)
1104                         goto out;
1105                 if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
1106                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
1107                             ni->ni_macaddr, NULL,
1108                             "peer link not yet established (%d)",
1109                             ni->ni_mlstate);
1110                         vap->iv_stats.is_mesh_nolink++;
1111                         goto out;
1112                 }       
1113                 if (dir != IEEE80211_FC1_DIR_FROMDS &&
1114                     dir != IEEE80211_FC1_DIR_DSTODS) {
1115                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1116                             wh, "data", "incorrect dir 0x%x", dir);
1117                         vap->iv_stats.is_rx_wrongdir++;
1118                         goto err;
1119                 }
1120                 /* pull up enough to get to the mesh control */
1121                 hdrspace = ieee80211_hdrspace(ic, wh);
1122                 if (m->m_len < hdrspace + sizeof(struct ieee80211_meshcntl) &&
1123                     (m = m_pullup(m, hdrspace +
1124                         sizeof(struct ieee80211_meshcntl))) == NULL) {
1125                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1126                             ni->ni_macaddr, NULL,
1127                             "data too short: expecting %u", hdrspace);
1128                         vap->iv_stats.is_rx_tooshort++;
1129                         goto out;               /* XXX */
1130                 }
1131                 /*
1132                  * Now calculate the full extent of the headers. Note
1133                  * mesh_decap will pull up anything we didn't get
1134                  * above when it strips the 802.11 headers.
1135                  */
1136                 mc = (const struct ieee80211_meshcntl *)
1137                     (mtod(m, const uint8_t *) + hdrspace);
1138                 meshdrlen = sizeof(struct ieee80211_meshcntl) +
1139                     (mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
1140                 hdrspace += meshdrlen;
1141                 seq = LE_READ_4(mc->mc_seq);
1142                 if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1143                         addr = wh->i_addr3;
1144                 else
1145                         addr = ((struct ieee80211_qosframe_addr4 *)wh)->i_addr4;
1146                 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, addr)) {
1147                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
1148                             addr, "data", "%s", "not to me");
1149                         vap->iv_stats.is_rx_wrongbss++; /* XXX kinda */
1150                         goto out;
1151                 }
1152                 if (mesh_checkpseq(vap, addr, seq) != 0) {
1153                         vap->iv_stats.is_rx_dup++;
1154                         goto out;
1155                 }
1156
1157                 /*
1158                  * Potentially forward packet.  See table s36 (p140)
1159                  * for the rules.  XXX tap fwd'd packets not for us?
1160                  */
1161                 if (dir == IEEE80211_FC1_DIR_FROMDS ||
1162                     !mesh_isucastforme(vap, wh, mc)) {
1163                         mesh_forward(vap, m, mc);
1164                         if (dir == IEEE80211_FC1_DIR_DSTODS)
1165                                 goto out;
1166                         /* NB: fall thru to deliver mcast frames locally */
1167                 }
1168
1169                 /*
1170                  * Save QoS bits for use below--before we strip the header.
1171                  */
1172                 if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
1173                         qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
1174                             ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
1175                             ((struct ieee80211_qosframe *)wh)->i_qos[0];
1176                 } else
1177                         qos = 0;
1178                 /*
1179                  * Next up, any fragmentation.
1180                  */
1181                 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1182                         m = ieee80211_defrag(ni, m, hdrspace);
1183                         if (m == NULL) {
1184                                 /* Fragment dropped or frame not complete yet */
1185                                 goto out;
1186                         }
1187                 }
1188                 wh = NULL;              /* no longer valid, catch any uses */
1189
1190                 if (ieee80211_radiotap_active_vap(vap))
1191                         ieee80211_radiotap_rx(vap, m);
1192                 need_tap = 0;
1193
1194                 /*
1195                  * Finally, strip the 802.11 header.
1196                  */
1197                 m = mesh_decap(vap, m, hdrspace, meshdrlen);
1198                 if (m == NULL) {
1199                         /* XXX mask bit to check for both */
1200                         /* don't count Null data frames as errors */
1201                         if (subtype == IEEE80211_FC0_SUBTYPE_NODATA ||
1202                             subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)
1203                                 goto out;
1204                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
1205                             ni->ni_macaddr, "data", "%s", "decap error");
1206                         vap->iv_stats.is_rx_decap++;
1207                         IEEE80211_NODE_STAT(ni, rx_decap);
1208                         goto err;
1209                 }
1210                 if (qos & IEEE80211_QOS_AMSDU) {
1211                         m = ieee80211_decap_amsdu(ni, m);
1212                         if (m == NULL)
1213                                 return IEEE80211_FC0_TYPE_DATA;
1214                 }
1215                 ieee80211_deliver_data(vap, ni, m);
1216                 return type;
1217         case IEEE80211_FC0_TYPE_MGT:
1218                 vap->iv_stats.is_rx_mgmt++;
1219                 IEEE80211_NODE_STAT(ni, rx_mgmt);
1220                 if (dir != IEEE80211_FC1_DIR_NODS) {
1221                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1222                             wh, "mgt", "incorrect dir 0x%x", dir);
1223                         vap->iv_stats.is_rx_wrongdir++;
1224                         goto err;
1225                 }
1226                 if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
1227                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
1228                             ni->ni_macaddr, "mgt", "too short: len %u",
1229                             m->m_pkthdr.len);
1230                         vap->iv_stats.is_rx_tooshort++;
1231                         goto out;
1232                 }
1233 #ifdef IEEE80211_DEBUG
1234                 if ((ieee80211_msg_debug(vap) && 
1235                     (vap->iv_ic->ic_flags & IEEE80211_F_SCAN)) ||
1236                     ieee80211_msg_dumppkts(vap)) {
1237                         if_printf(ifp, "received %s from %6D rssi %d\n",
1238                             ieee80211_mgt_subtype_name[subtype >>
1239                             IEEE80211_FC0_SUBTYPE_SHIFT],
1240                             wh->i_addr2, ":", rssi);
1241                 }
1242 #endif
1243                 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1244                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1245                             wh, NULL, "%s", "WEP set but not permitted");
1246                         vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
1247                         goto out;
1248                 }
1249                 vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
1250                 goto out;
1251         case IEEE80211_FC0_TYPE_CTL:
1252                 vap->iv_stats.is_rx_ctl++;
1253                 IEEE80211_NODE_STAT(ni, rx_ctrl);
1254                 goto out;
1255         default:
1256                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1257                     wh, "bad", "frame type 0x%x", type);
1258                 /* should not come here */
1259                 break;
1260         }
1261 err:
1262         ifp->if_ierrors++;
1263 out:
1264         if (m != NULL) {
1265                 if (need_tap && ieee80211_radiotap_active_vap(vap))
1266                         ieee80211_radiotap_rx(vap, m);
1267                 m_freem(m);
1268         }
1269         return type;
1270 }
1271
1272 static void
1273 mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
1274     int rssi, int nf)
1275 {
1276         struct ieee80211vap *vap = ni->ni_vap;
1277         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1278         struct ieee80211com *ic = ni->ni_ic;
1279         struct ieee80211_frame *wh;
1280         uint8_t *frm, *efrm;
1281
1282         wh = mtod(m0, struct ieee80211_frame *);
1283         frm = (uint8_t *)&wh[1];
1284         efrm = mtod(m0, uint8_t *) + m0->m_len;
1285         switch (subtype) {
1286         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1287         case IEEE80211_FC0_SUBTYPE_BEACON:
1288         {
1289                 struct ieee80211_scanparams scan;
1290                 /*
1291                  * We process beacon/probe response
1292                  * frames to discover neighbors.
1293                  */
1294                 if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
1295                         return;
1296                 /*
1297                  * Count frame now that we know it's to be processed.
1298                  */
1299                 if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
1300                         vap->iv_stats.is_rx_beacon++;   /* XXX remove */
1301                         IEEE80211_NODE_STAT(ni, rx_beacons);
1302                 } else
1303                         IEEE80211_NODE_STAT(ni, rx_proberesp);
1304                 /*
1305                  * If scanning, just pass information to the scan module.
1306                  */
1307                 if (ic->ic_flags & IEEE80211_F_SCAN) {
1308                         if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) {
1309                                 /*
1310                                  * Actively scanning a channel marked passive;
1311                                  * send a probe request now that we know there
1312                                  * is 802.11 traffic present.
1313                                  *
1314                                  * XXX check if the beacon we recv'd gives
1315                                  * us what we need and suppress the probe req
1316                                  */
1317                                 ieee80211_probe_curchan(vap, 1);
1318                                 ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
1319                         }
1320                         ieee80211_add_scan(vap, &scan, wh,
1321                             subtype, rssi, nf);
1322                         return;
1323                 }
1324
1325                 /* The rest of this code assumes we are running */
1326                 if (vap->iv_state != IEEE80211_S_RUN)
1327                         return;
1328                 /*
1329                  * Ignore non-mesh STAs.
1330                  */
1331                 if ((scan.capinfo &
1332                      (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) ||
1333                     scan.meshid == NULL || scan.meshconf == NULL) {
1334                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1335                             wh, "beacon", "%s", "not a mesh sta");
1336                         vap->iv_stats.is_mesh_wrongmesh++;
1337                         return;
1338                 }
1339                 /*
1340                  * Ignore STAs for other mesh networks.
1341                  */
1342                 if (memcmp(scan.meshid+2, ms->ms_id, ms->ms_idlen) != 0 ||
1343                     mesh_verify_meshconf(vap, scan.meshconf)) {
1344                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1345                             wh, "beacon", "%s", "not for our mesh");
1346                         vap->iv_stats.is_mesh_wrongmesh++;
1347                         return;
1348                 }
1349                 /*
1350                  * Peer only based on the current ACL policy.
1351                  */
1352                 if (vap->iv_acl != NULL &&
1353                     !vap->iv_acl->iac_check(vap, wh->i_addr2)) {
1354                         IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
1355                             wh, NULL, "%s", "disallowed by ACL");
1356                         vap->iv_stats.is_rx_acl++;
1357                         return;
1358                 }
1359                 /*
1360                  * Do neighbor discovery.
1361                  */
1362                 if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
1363                         /*
1364                          * Create a new entry in the neighbor table.
1365                          */
1366                         ni = ieee80211_add_neighbor(vap, wh, &scan);
1367                 }
1368                 /*
1369                  * Automatically peer with discovered nodes if possible.
1370                  * XXX backoff on repeated failure
1371                  */
1372                 if (ni != vap->iv_bss &&
1373                     (ms->ms_flags & IEEE80211_MESHFLAGS_AP) &&
1374                     ni->ni_mlstate == IEEE80211_NODE_MESH_IDLE) {
1375                         uint16_t args[1];
1376
1377                         ni->ni_mlpid = mesh_generateid(vap);
1378                         if (ni->ni_mlpid == 0)
1379                                 return;
1380                         mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENSNT);
1381                         args[0] = ni->ni_mlpid;
1382                         ieee80211_send_action(ni,
1383                             IEEE80211_ACTION_CAT_MESHPEERING,
1384                             IEEE80211_ACTION_MESHPEERING_OPEN, args);
1385                         ni->ni_mlrcnt = 0;
1386                         mesh_peer_timeout_setup(ni);
1387                 }
1388                 break;
1389         }
1390         case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
1391         {
1392                 uint8_t *ssid, *meshid, *rates, *xrates;
1393
1394                 if (vap->iv_state != IEEE80211_S_RUN) {
1395                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1396                             wh, NULL, "wrong state %s",
1397                             ieee80211_state_name[vap->iv_state]);
1398                         vap->iv_stats.is_rx_mgtdiscard++;
1399                         return;
1400                 }
1401                 if (IEEE80211_IS_MULTICAST(wh->i_addr2)) {
1402                         /* frame must be directed */
1403                         IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1404                             wh, NULL, "%s", "not unicast");
1405                         vap->iv_stats.is_rx_mgtdiscard++;       /* XXX stat */
1406                         return;
1407                 }
1408                 /*
1409                  * prreq frame format
1410                  *      [tlv] ssid
1411                  *      [tlv] supported rates
1412                  *      [tlv] extended supported rates
1413                  *      [tlv] mesh id
1414                  */
1415                 ssid = meshid = rates = xrates = NULL;
1416                 while (efrm - frm > 1) {
1417                         IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
1418                         switch (*frm) {
1419                         case IEEE80211_ELEMID_SSID:
1420                                 ssid = frm;
1421                                 break;
1422                         case IEEE80211_ELEMID_RATES:
1423                                 rates = frm;
1424                                 break;
1425                         case IEEE80211_ELEMID_XRATES:
1426                                 xrates = frm;
1427                                 break;
1428                         case IEEE80211_ELEMID_MESHID:
1429                                 meshid = frm;
1430                                 break;
1431                         }
1432                         frm += frm[2] + 2;
1433                 }
1434                 IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return);
1435                 IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return);
1436                 if (xrates != NULL)
1437                         IEEE80211_VERIFY_ELEMENT(xrates,
1438                             IEEE80211_RATE_MAXSIZE - rates[1], return);
1439                 if (meshid != NULL) {
1440                         IEEE80211_VERIFY_ELEMENT(meshid,
1441                             IEEE80211_MESHID_LEN, return);
1442                         /* NB: meshid, not ssid */
1443                         IEEE80211_VERIFY_SSID(vap->iv_bss, meshid, return);
1444                 }
1445
1446                 /* XXX find a better class or define it's own */
1447                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2,
1448                     "%s", "recv probe req");
1449                 /*
1450                  * Some legacy 11b clients cannot hack a complete
1451                  * probe response frame.  When the request includes
1452                  * only a bare-bones rate set, communicate this to
1453                  * the transmit side.
1454                  */
1455                 ieee80211_send_proberesp(vap, wh->i_addr2, 0);
1456                 break;
1457         }
1458         case IEEE80211_FC0_SUBTYPE_ACTION:
1459                 if (vap->iv_state != IEEE80211_S_RUN) {
1460                         vap->iv_stats.is_rx_mgtdiscard++;
1461                         break;
1462                 }
1463                 /*
1464                  * We received an action for an unknown neighbor.
1465                  * XXX: wait for it to beacon or create ieee80211_node?
1466                  */
1467                 if (ni == vap->iv_bss) {
1468                         IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH,
1469                             wh, NULL, "%s", "unknown node");
1470                         vap->iv_stats.is_rx_mgtdiscard++;
1471                         break;
1472                 }
1473                 /*
1474                  * Discard if not for us.
1475                  */
1476                 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) &&
1477                     !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1478                         IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH,
1479                             wh, NULL, "%s", "not for me");
1480                         vap->iv_stats.is_rx_mgtdiscard++;
1481                         break;
1482                 }
1483                 /* XXX parse_action is a bit useless now */
1484                 if (ieee80211_parse_action(ni, m0) == 0)
1485                         ic->ic_recv_action(ni, wh, frm, efrm);
1486                 break;
1487         case IEEE80211_FC0_SUBTYPE_AUTH:
1488         case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
1489         case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
1490         case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1491         case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
1492         case IEEE80211_FC0_SUBTYPE_DEAUTH:
1493         case IEEE80211_FC0_SUBTYPE_DISASSOC:
1494                 IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
1495                     wh, NULL, "%s", "not handled");
1496                 vap->iv_stats.is_rx_mgtdiscard++;
1497                 return;
1498         default:
1499                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
1500                     wh, "mgt", "subtype 0x%x not handled", subtype);
1501                 vap->iv_stats.is_rx_badsubtype++;
1502                 break;
1503         }
1504 }
1505
1506 /*
1507  * Parse meshpeering action ie's for open+confirm frames; the
1508  * important bits are returned in the supplied structure.
1509  */
1510 static const struct ieee80211_meshpeer_ie *
1511 mesh_parse_meshpeering_action(struct ieee80211_node *ni,
1512         const struct ieee80211_frame *wh,       /* XXX for VERIFY_LENGTH */
1513         const uint8_t *frm, const uint8_t *efrm,
1514         struct ieee80211_meshpeer_ie *mp, uint8_t subtype)
1515 {
1516         struct ieee80211vap *vap = ni->ni_vap;
1517         const struct ieee80211_meshpeer_ie *mpie;
1518         const uint8_t *meshid, *meshconf, *meshpeer;
1519
1520         meshid = meshconf = meshpeer = NULL;
1521         while (efrm - frm > 1) {
1522                 IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return NULL);
1523                 switch (*frm) {
1524                 case IEEE80211_ELEMID_MESHID:
1525                         meshid = frm;
1526                         break;
1527                 case IEEE80211_ELEMID_MESHCONF:
1528                         meshconf = frm;
1529                         break;
1530                 case IEEE80211_ELEMID_MESHPEER:
1531                         meshpeer = frm;
1532                         mpie = (const struct ieee80211_meshpeer_ie *) frm;
1533                         memset(mp, 0, sizeof(*mp));
1534                         mp->peer_llinkid = LE_READ_2(&mpie->peer_llinkid);
1535                         /* NB: peer link ID is optional on these frames */
1536                         if (subtype == IEEE80211_MESH_PEER_LINK_CLOSE &&
1537                             mpie->peer_len == 8) {
1538                                 mp->peer_linkid = 0;
1539                                 mp->peer_rcode = LE_READ_2(&mpie->peer_linkid);
1540                         } else {
1541                                 mp->peer_linkid = LE_READ_2(&mpie->peer_linkid);
1542                                 mp->peer_rcode = LE_READ_2(&mpie->peer_rcode);
1543                         }
1544                         break;
1545                 }
1546                 frm += frm[1] + 2;
1547         }
1548
1549         /*
1550          * Verify the contents of the frame. Action frames with
1551          * close subtype don't have a Mesh Configuration IE.
1552          * If if fails validation, close the peer link.
1553          */
1554         KASSERT(meshpeer != NULL &&
1555             subtype != IEEE80211_ACTION_MESHPEERING_CLOSE,
1556             ("parsing close action"));
1557
1558         if (mesh_verify_meshid(vap, meshid) ||
1559             mesh_verify_meshpeer(vap, subtype, meshpeer) ||
1560             mesh_verify_meshconf(vap, meshconf)) {
1561                 uint16_t args[3];
1562
1563                 IEEE80211_DISCARD(vap,
1564                     IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
1565                     wh, NULL, "%s", "not for our mesh");
1566                 vap->iv_stats.is_rx_mgtdiscard++;
1567                 switch (ni->ni_mlstate) {
1568                 case IEEE80211_NODE_MESH_IDLE:
1569                 case IEEE80211_NODE_MESH_ESTABLISHED:
1570                 case IEEE80211_NODE_MESH_HOLDING:
1571                         /* ignore */
1572                         break;
1573                 case IEEE80211_NODE_MESH_OPENSNT:
1574                 case IEEE80211_NODE_MESH_OPENRCV:
1575                 case IEEE80211_NODE_MESH_CONFIRMRCV:
1576                         args[0] = ni->ni_mlpid;
1577                         args[1] = ni->ni_mllid;
1578                         args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
1579                         ieee80211_send_action(ni,
1580                             IEEE80211_ACTION_CAT_MESHPEERING,
1581                             IEEE80211_ACTION_MESHPEERING_CLOSE,
1582                             args);
1583                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
1584                         mesh_peer_timeout_setup(ni);
1585                         break;
1586                 }
1587                 return NULL;
1588         }
1589         return (const struct ieee80211_meshpeer_ie *) mp;
1590 }
1591
1592 static int
1593 mesh_recv_action_meshpeering_open(struct ieee80211_node *ni,
1594         const struct ieee80211_frame *wh,
1595         const uint8_t *frm, const uint8_t *efrm)
1596 {
1597         struct ieee80211vap *vap = ni->ni_vap;
1598         struct ieee80211_meshpeer_ie ie;
1599         const struct ieee80211_meshpeer_ie *meshpeer;
1600         uint16_t args[3];
1601
1602         /* +2+2 for action + code + capabilites */
1603         meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2, efrm, &ie,
1604             IEEE80211_ACTION_MESHPEERING_OPEN);
1605         if (meshpeer == NULL) {
1606                 return 0;
1607         }
1608
1609         /* XXX move up */
1610         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
1611             "recv PEER OPEN, lid 0x%x", meshpeer->peer_llinkid);
1612
1613         switch (ni->ni_mlstate) {
1614         case IEEE80211_NODE_MESH_IDLE:
1615                 mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENRCV);
1616                 ni->ni_mllid = meshpeer->peer_llinkid;
1617                 ni->ni_mlpid = mesh_generateid(vap);
1618                 if (ni->ni_mlpid == 0)
1619                         return 0;               /* XXX */
1620                 args[0] = ni->ni_mlpid;
1621                 /* Announce we're open too... */
1622                 ieee80211_send_action(ni,
1623                     IEEE80211_ACTION_CAT_MESHPEERING,
1624                     IEEE80211_ACTION_MESHPEERING_OPEN, args);
1625                 /* ...and confirm the link. */
1626                 args[0] = ni->ni_mlpid;
1627                 args[1] = ni->ni_mllid;
1628                 ieee80211_send_action(ni,
1629                     IEEE80211_ACTION_CAT_MESHPEERING,
1630                     IEEE80211_ACTION_MESHPEERING_CONFIRM,
1631                     args);
1632                 mesh_peer_timeout_setup(ni);
1633                 break;
1634         case IEEE80211_NODE_MESH_OPENRCV:
1635                 /* Wrong Link ID */
1636                 if (ni->ni_mllid != meshpeer->peer_llinkid) {
1637                         args[0] = ni->ni_mllid;
1638                         args[1] = ni->ni_mlpid;
1639                         args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
1640                         ieee80211_send_action(ni,
1641                             IEEE80211_ACTION_CAT_MESHPEERING,
1642                             IEEE80211_ACTION_MESHPEERING_CLOSE,
1643                             args);
1644                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
1645                         mesh_peer_timeout_setup(ni);
1646                         break;
1647                 }
1648                 /* Duplicate open, confirm again. */
1649                 args[0] = ni->ni_mlpid;
1650                 args[1] = ni->ni_mllid;
1651                 ieee80211_send_action(ni,
1652                     IEEE80211_ACTION_CAT_MESHPEERING,
1653                     IEEE80211_ACTION_MESHPEERING_CONFIRM,
1654                     args);
1655                 break;
1656         case IEEE80211_NODE_MESH_OPENSNT:
1657                 ni->ni_mllid = meshpeer->peer_llinkid;
1658                 mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENRCV);
1659                 args[0] = ni->ni_mlpid;
1660                 args[1] = ni->ni_mllid;
1661                 ieee80211_send_action(ni,
1662                     IEEE80211_ACTION_CAT_MESHPEERING,
1663                     IEEE80211_ACTION_MESHPEERING_CONFIRM,
1664                     args);
1665                 /* NB: don't setup/clear any timeout */
1666                 break;
1667         case IEEE80211_NODE_MESH_CONFIRMRCV:
1668                 if (ni->ni_mlpid != meshpeer->peer_linkid ||
1669                     ni->ni_mllid != meshpeer->peer_llinkid) {
1670                         args[0] = ni->ni_mlpid;
1671                         args[1] = ni->ni_mllid;
1672                         args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
1673                         ieee80211_send_action(ni,
1674                             IEEE80211_ACTION_CAT_MESHPEERING,
1675                             IEEE80211_ACTION_MESHPEERING_CLOSE,
1676                             args);
1677                         mesh_linkchange(ni,
1678                             IEEE80211_NODE_MESH_HOLDING);
1679                         mesh_peer_timeout_setup(ni);
1680                         break;
1681                 }
1682                 mesh_linkchange(ni, IEEE80211_NODE_MESH_ESTABLISHED);
1683                 ni->ni_mllid = meshpeer->peer_llinkid;
1684                 args[0] = ni->ni_mlpid;
1685                 args[1] = ni->ni_mllid;
1686                 ieee80211_send_action(ni,
1687                     IEEE80211_ACTION_CAT_MESHPEERING,
1688                     IEEE80211_ACTION_MESHPEERING_CONFIRM,
1689                     args);
1690                 mesh_peer_timeout_stop(ni);
1691                 break;
1692         case IEEE80211_NODE_MESH_ESTABLISHED:
1693                 if (ni->ni_mllid != meshpeer->peer_llinkid) {
1694                         args[0] = ni->ni_mllid;
1695                         args[1] = ni->ni_mlpid;
1696                         args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
1697                         ieee80211_send_action(ni,
1698                             IEEE80211_ACTION_CAT_MESHPEERING,
1699                             IEEE80211_ACTION_MESHPEERING_CLOSE,
1700                             args);
1701                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
1702                         mesh_peer_timeout_setup(ni);
1703                         break;
1704                 }
1705                 args[0] = ni->ni_mlpid;
1706                 args[1] = ni->ni_mllid;
1707                 ieee80211_send_action(ni,
1708                     IEEE80211_ACTION_CAT_MESHPEERING,
1709                     IEEE80211_ACTION_MESHPEERING_CONFIRM,
1710                     args);
1711                 break;
1712         case IEEE80211_NODE_MESH_HOLDING:
1713                 args[0] = ni->ni_mlpid;
1714                 args[1] = meshpeer->peer_llinkid;
1715                 args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
1716                 ieee80211_send_action(ni,
1717                     IEEE80211_ACTION_CAT_MESHPEERING,
1718                     IEEE80211_ACTION_MESHPEERING_CLOSE,
1719                     args);
1720                 break;
1721         }
1722         return 0;
1723 }
1724
1725 static int
1726 mesh_recv_action_meshpeering_confirm(struct ieee80211_node *ni,
1727         const struct ieee80211_frame *wh,
1728         const uint8_t *frm, const uint8_t *efrm)
1729 {
1730         struct ieee80211vap *vap = ni->ni_vap;
1731         struct ieee80211_meshpeer_ie ie;
1732         const struct ieee80211_meshpeer_ie *meshpeer;
1733         uint16_t args[3];
1734
1735         /* +2+2+2+2 for action + code + capabilites + status code + AID */
1736         meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2+2+2, efrm, &ie,
1737             IEEE80211_ACTION_MESHPEERING_CONFIRM);
1738         if (meshpeer == NULL) {
1739                 return 0;
1740         }
1741
1742         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
1743             "recv PEER CONFIRM, local id 0x%x, peer id 0x%x",
1744             meshpeer->peer_llinkid, meshpeer->peer_linkid);
1745
1746         switch (ni->ni_mlstate) {
1747         case IEEE80211_NODE_MESH_OPENRCV:
1748                 mesh_linkchange(ni, IEEE80211_NODE_MESH_ESTABLISHED);
1749                 mesh_peer_timeout_stop(ni);
1750                 break;
1751         case IEEE80211_NODE_MESH_OPENSNT:
1752                 mesh_linkchange(ni, IEEE80211_NODE_MESH_CONFIRMRCV);
1753                 break;
1754         case IEEE80211_NODE_MESH_HOLDING:
1755                 args[0] = ni->ni_mlpid;
1756                 args[1] = meshpeer->peer_llinkid;
1757                 args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
1758                 ieee80211_send_action(ni,
1759                     IEEE80211_ACTION_CAT_MESHPEERING,
1760                     IEEE80211_ACTION_MESHPEERING_CLOSE,
1761                     args);
1762                 break;
1763         case IEEE80211_NODE_MESH_CONFIRMRCV:
1764                 if (ni->ni_mllid != meshpeer->peer_llinkid) {
1765                         args[0] = ni->ni_mlpid;
1766                         args[1] = ni->ni_mllid;
1767                         args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
1768                         ieee80211_send_action(ni,
1769                             IEEE80211_ACTION_CAT_MESHPEERING,
1770                             IEEE80211_ACTION_MESHPEERING_CLOSE,
1771                             args);
1772                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
1773                         mesh_peer_timeout_setup(ni);
1774                 }
1775                 break;
1776         default:
1777                 IEEE80211_DISCARD(vap,
1778                     IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
1779                     wh, NULL, "received confirm in invalid state %d",
1780                     ni->ni_mlstate);
1781                 vap->iv_stats.is_rx_mgtdiscard++;
1782                 break;
1783         }
1784         return 0;
1785 }
1786
1787 static int
1788 mesh_recv_action_meshpeering_close(struct ieee80211_node *ni,
1789         const struct ieee80211_frame *wh,
1790         const uint8_t *frm, const uint8_t *efrm)
1791 {
1792         uint16_t args[3];
1793
1794         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
1795             ni, "%s", "recv PEER CLOSE");
1796
1797         switch (ni->ni_mlstate) {
1798         case IEEE80211_NODE_MESH_IDLE:
1799                 /* ignore */
1800                 break;
1801         case IEEE80211_NODE_MESH_OPENRCV:
1802         case IEEE80211_NODE_MESH_OPENSNT:
1803         case IEEE80211_NODE_MESH_CONFIRMRCV:
1804         case IEEE80211_NODE_MESH_ESTABLISHED:
1805                 args[0] = ni->ni_mlpid;
1806                 args[1] = ni->ni_mllid;
1807                 args[2] = IEEE80211_REASON_MESH_CLOSE_RCVD;
1808                 ieee80211_send_action(ni,
1809                     IEEE80211_ACTION_CAT_MESHPEERING,
1810                     IEEE80211_ACTION_MESHPEERING_CLOSE,
1811                     args);
1812                 mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
1813                 mesh_peer_timeout_setup(ni);
1814                 break;
1815         case IEEE80211_NODE_MESH_HOLDING:
1816                 mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE);
1817                 mesh_peer_timeout_setup(ni);
1818                 break;
1819         }
1820         return 0;
1821 }
1822
1823 /*
1824  * Link Metric handling.
1825  */
1826 static int
1827 mesh_recv_action_meshlmetric_req(struct ieee80211_node *ni,
1828         const struct ieee80211_frame *wh,
1829         const uint8_t *frm, const uint8_t *efrm)
1830 {
1831         uint32_t metric;
1832
1833         metric = mesh_airtime_calc(ni);
1834         ieee80211_send_action(ni,
1835             IEEE80211_ACTION_CAT_MESHLMETRIC,
1836             IEEE80211_ACTION_MESHLMETRIC_REP,
1837             &metric);
1838         return 0;
1839 }
1840
1841 static int
1842 mesh_recv_action_meshlmetric_rep(struct ieee80211_node *ni,
1843         const struct ieee80211_frame *wh,
1844         const uint8_t *frm, const uint8_t *efrm)
1845 {
1846         return 0;
1847 }
1848
1849 static int
1850 mesh_send_action(struct ieee80211_node *ni, struct mbuf *m)
1851 {
1852         struct ieee80211_bpf_params params;
1853
1854         memset(&params, 0, sizeof(params));
1855         params.ibp_pri = WME_AC_VO;
1856         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
1857         /* XXX ucast/mcast */
1858         params.ibp_try0 = ni->ni_txparms->maxretry;
1859         params.ibp_power = ni->ni_txpower;
1860         return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
1861              &params);
1862 }
1863
1864 #define ADDSHORT(frm, v) do {                   \
1865         frm[0] = (v) & 0xff;                    \
1866         frm[1] = (v) >> 8;                      \
1867         frm += 2;                               \
1868 } while (0)
1869 #define ADDWORD(frm, v) do {                    \
1870         frm[0] = (v) & 0xff;                    \
1871         frm[1] = ((v) >> 8) & 0xff;             \
1872         frm[2] = ((v) >> 16) & 0xff;            \
1873         frm[3] = ((v) >> 24) & 0xff;            \
1874         frm += 4;                               \
1875 } while (0)
1876
1877 static int
1878 mesh_send_action_meshpeering_open(struct ieee80211_node *ni,
1879         int category, int action, void *args0)
1880 {
1881         struct ieee80211vap *vap = ni->ni_vap;
1882         struct ieee80211com *ic = ni->ni_ic;
1883         uint16_t *args = args0;
1884         const struct ieee80211_rateset *rs;
1885         struct mbuf *m;
1886         uint8_t *frm;
1887
1888         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
1889             "send PEER OPEN action: localid 0x%x", args[0]);
1890
1891         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1892             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__, __LINE__,
1893             ni, ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)+1);
1894         ieee80211_ref_node(ni);
1895
1896         m = ieee80211_getmgtframe(&frm,
1897             ic->ic_headroom + sizeof(struct ieee80211_frame),
1898             sizeof(uint16_t)    /* action+category */
1899             + sizeof(uint16_t)  /* capabilites */
1900             + 2 + IEEE80211_RATE_SIZE    
1901             + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)         
1902             + 2 + IEEE80211_MESHID_LEN
1903             + sizeof(struct ieee80211_meshconf_ie)       
1904             + sizeof(struct ieee80211_meshpeer_ie)
1905         );
1906         if (m != NULL) {
1907                 /*
1908                  * mesh peer open action frame format:
1909                  *   [1] category
1910                  *   [1] action
1911                  *   [2] capabilities
1912                  *   [tlv] rates
1913                  *   [tlv] xrates
1914                  *   [tlv] mesh id
1915                  *   [tlv] mesh conf
1916                  *   [tlv] mesh peer link mgmt
1917                  */
1918                 *frm++ = category;
1919                 *frm++ = action;
1920                 ADDSHORT(frm, ieee80211_getcapinfo(vap, ni->ni_chan));
1921                 rs = ieee80211_get_suprates(ic, ic->ic_curchan);
1922                 frm = ieee80211_add_rates(frm, rs);
1923                 frm = ieee80211_add_xrates(frm, rs);
1924                 frm = ieee80211_add_meshid(frm, vap);
1925                 frm = ieee80211_add_meshconf(frm, vap);
1926                 frm = ieee80211_add_meshpeer(frm, IEEE80211_MESH_PEER_LINK_OPEN,
1927                     args[0], 0, 0);
1928                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1929                 return mesh_send_action(ni, m);
1930         } else {
1931                 vap->iv_stats.is_tx_nobuf++;
1932                 ieee80211_free_node(ni);
1933                 return ENOMEM;
1934         }
1935 }
1936
1937 static int
1938 mesh_send_action_meshpeering_confirm(struct ieee80211_node *ni,
1939         int category, int action, void *args0)
1940 {
1941         struct ieee80211vap *vap = ni->ni_vap;
1942         struct ieee80211com *ic = ni->ni_ic;
1943         uint16_t *args = args0;
1944         const struct ieee80211_rateset *rs;
1945         struct mbuf *m;
1946         uint8_t *frm;
1947
1948         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
1949             "send PEER CONFIRM action: localid 0x%x, peerid 0x%x",
1950             args[0], args[1]);
1951
1952         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1953             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__, __LINE__,
1954             ni, ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)+1);
1955         ieee80211_ref_node(ni);
1956
1957         m = ieee80211_getmgtframe(&frm,
1958             ic->ic_headroom + sizeof(struct ieee80211_frame),
1959             sizeof(uint16_t)    /* action+category */
1960             + sizeof(uint16_t)  /* capabilites */
1961             + sizeof(uint16_t)  /* status code */
1962             + sizeof(uint16_t)  /* AID */
1963             + 2 + IEEE80211_RATE_SIZE    
1964             + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)         
1965             + 2 + IEEE80211_MESHID_LEN
1966             + sizeof(struct ieee80211_meshconf_ie)       
1967             + sizeof(struct ieee80211_meshpeer_ie)
1968         );
1969         if (m != NULL) {
1970                 /*
1971                  * mesh peer confirm action frame format:
1972                  *   [1] category
1973                  *   [1] action
1974                  *   [2] capabilities
1975                  *   [2] status code
1976                  *   [2] association id (peer ID)
1977                  *   [tlv] rates
1978                  *   [tlv] xrates
1979                  *   [tlv] mesh id
1980                  *   [tlv] mesh conf
1981                  *   [tlv] mesh peer link mgmt
1982                  */
1983                 *frm++ = category;
1984                 *frm++ = action;
1985                 ADDSHORT(frm, ieee80211_getcapinfo(vap, ni->ni_chan));
1986                 ADDSHORT(frm, 0);               /* status code */
1987                 ADDSHORT(frm, args[1]);         /* AID */
1988                 rs = ieee80211_get_suprates(ic, ic->ic_curchan);
1989                 frm = ieee80211_add_rates(frm, rs);
1990                 frm = ieee80211_add_xrates(frm, rs);
1991                 frm = ieee80211_add_meshid(frm, vap);
1992                 frm = ieee80211_add_meshconf(frm, vap);
1993                 frm = ieee80211_add_meshpeer(frm,
1994                     IEEE80211_MESH_PEER_LINK_CONFIRM,
1995                     args[0], args[1], 0);
1996                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1997                 return mesh_send_action(ni, m);
1998         } else {
1999                 vap->iv_stats.is_tx_nobuf++;
2000                 ieee80211_free_node(ni);
2001                 return ENOMEM;
2002         }
2003 }
2004
2005 static int
2006 mesh_send_action_meshpeering_close(struct ieee80211_node *ni,
2007         int category, int action, void *args0)
2008 {
2009         struct ieee80211vap *vap = ni->ni_vap;
2010         struct ieee80211com *ic = ni->ni_ic;
2011         uint16_t *args = args0;
2012         struct mbuf *m;
2013         uint8_t *frm;
2014
2015         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
2016             "send PEER CLOSE action: localid 0x%x, peerid 0x%x reason %d",
2017             args[0], args[1], args[2]);
2018
2019         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2020             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__, __LINE__,
2021             ni, ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)+1);
2022         ieee80211_ref_node(ni);
2023
2024         m = ieee80211_getmgtframe(&frm,
2025             ic->ic_headroom + sizeof(struct ieee80211_frame),
2026             sizeof(uint16_t)    /* action+category */
2027             + sizeof(uint16_t)  /* reason code */
2028             + 2 + IEEE80211_MESHID_LEN
2029             + sizeof(struct ieee80211_meshpeer_ie) 
2030         );
2031         if (m != NULL) {
2032                 /*
2033                  * mesh peer close action frame format:
2034                  *   [1] category
2035                  *   [1] action
2036                  *   [2] reason code
2037                  *   [tlv] mesh id
2038                  *   [tlv] mesh peer link mgmt
2039                  */
2040                 *frm++ = category;
2041                 *frm++ = action;
2042                 ADDSHORT(frm, args[2]);         /* reason code */
2043                 frm = ieee80211_add_meshid(frm, vap);
2044                 frm = ieee80211_add_meshpeer(frm,
2045                     IEEE80211_MESH_PEER_LINK_CLOSE,
2046                     args[0], args[1], args[2]);
2047                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2048                 return mesh_send_action(ni, m);
2049         } else {
2050                 vap->iv_stats.is_tx_nobuf++;
2051                 ieee80211_free_node(ni);
2052                 return ENOMEM;
2053         }
2054 }
2055
2056 static int
2057 mesh_send_action_meshlink_request(struct ieee80211_node *ni,
2058         int category, int action, void *arg0)
2059 {
2060         struct ieee80211vap *vap = ni->ni_vap;
2061         struct ieee80211com *ic = ni->ni_ic;
2062         struct mbuf *m;
2063         uint8_t *frm;
2064
2065         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
2066             "%s", "send LINK METRIC REQUEST action");
2067
2068         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2069             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__, __LINE__,
2070             ni, ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)+1);
2071         ieee80211_ref_node(ni);
2072
2073         m = ieee80211_getmgtframe(&frm,
2074             ic->ic_headroom + sizeof(struct ieee80211_frame),
2075             sizeof(uint16_t)    /* action+category */
2076         );
2077         if (m != NULL) {
2078                 /*
2079                  * mesh link metric request
2080                  *   [1] category
2081                  *   [1] action
2082                  */
2083                 *frm++ = category;
2084                 *frm++ = action;
2085                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2086                 return mesh_send_action(ni, m);
2087         } else {
2088                 vap->iv_stats.is_tx_nobuf++;
2089                 ieee80211_free_node(ni);
2090                 return ENOMEM;
2091         }
2092 }
2093
2094 static int
2095 mesh_send_action_meshlink_reply(struct ieee80211_node *ni,
2096         int category, int action, void *args0)
2097 {
2098         struct ieee80211vap *vap = ni->ni_vap;
2099         struct ieee80211com *ic = ni->ni_ic;
2100         uint32_t *metric = args0;
2101         struct mbuf *m;
2102         uint8_t *frm;
2103
2104         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
2105             "send LINK METRIC REPLY action: metric 0x%x", *metric);
2106
2107         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2108             "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", __func__, __LINE__,
2109             ni, ni->ni_macaddr, ":", ieee80211_node_refcnt(ni)+1);
2110         ieee80211_ref_node(ni);
2111
2112         m = ieee80211_getmgtframe(&frm,
2113             ic->ic_headroom + sizeof(struct ieee80211_frame),
2114             sizeof(uint16_t)    /* action+category */
2115             + sizeof(struct ieee80211_meshlmetric_ie)
2116         );
2117         if (m != NULL) {
2118                 /*
2119                  * mesh link metric reply
2120                  *   [1] category
2121                  *   [1] action
2122                  *   [tlv] mesh link metric
2123                  */
2124                 *frm++ = category;
2125                 *frm++ = action;
2126                 frm = ieee80211_add_meshlmetric(frm, *metric);
2127                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2128                 return mesh_send_action(ni, m);
2129         } else {
2130                 vap->iv_stats.is_tx_nobuf++;
2131                 ieee80211_free_node(ni);
2132                 return ENOMEM;
2133         }
2134 }
2135
2136 static void
2137 mesh_peer_timeout_setup(struct ieee80211_node *ni)
2138 {
2139         switch (ni->ni_mlstate) {
2140         case IEEE80211_NODE_MESH_HOLDING:
2141                 ni->ni_mltval = ieee80211_mesh_holdingtimeout;
2142                 break;
2143         case IEEE80211_NODE_MESH_CONFIRMRCV:
2144                 ni->ni_mltval = ieee80211_mesh_confirmtimeout;
2145                 break;
2146         case IEEE80211_NODE_MESH_IDLE:
2147                 ni->ni_mltval = 0;
2148                 break;
2149         default:
2150                 ni->ni_mltval = ieee80211_mesh_retrytimeout;
2151                 break;
2152         }
2153         if (ni->ni_mltval) {
2154                 callout_reset(&ni->ni_mltimer, ni->ni_mltval,
2155                               mesh_peer_timeout_callout, ni);
2156         }
2157 }
2158
2159 /*
2160  * Same as above but backoffs timer statisically 50%.
2161  */
2162 static void
2163 mesh_peer_timeout_backoff(struct ieee80211_node *ni)
2164 {
2165         uint32_t r;
2166         
2167         r = karc4random();
2168         ni->ni_mltval += r % ni->ni_mltval;
2169         callout_reset(&ni->ni_mltimer, ni->ni_mltval,
2170                       mesh_peer_timeout_callout, ni);
2171 }
2172
2173 static __inline void
2174 mesh_peer_timeout_stop(struct ieee80211_node *ni)
2175 {
2176         callout_stop(&ni->ni_mltimer);
2177 }
2178
2179 /*
2180  * Mesh Peer Link Management FSM timeout handling.
2181  */
2182 static void
2183 mesh_peer_timeout_callout(void *arg)
2184 {
2185         struct ieee80211_node *ni = (struct ieee80211_node *)arg;
2186         uint16_t args[3];
2187
2188         wlan_serialize_enter();
2189         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_MESH,
2190             ni, "mesh link timeout, state %d, retry counter %d",
2191             ni->ni_mlstate, ni->ni_mlrcnt);
2192         
2193         switch (ni->ni_mlstate) {
2194         case IEEE80211_NODE_MESH_IDLE:
2195         case IEEE80211_NODE_MESH_ESTABLISHED:
2196                 break;
2197         case IEEE80211_NODE_MESH_OPENSNT:
2198         case IEEE80211_NODE_MESH_OPENRCV:
2199                 if (ni->ni_mlrcnt == ieee80211_mesh_maxretries) {
2200                         args[0] = ni->ni_mlpid;
2201                         args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
2202                         ieee80211_send_action(ni,
2203                             IEEE80211_ACTION_CAT_MESHPEERING,
2204                             IEEE80211_ACTION_MESHPEERING_CLOSE, args);
2205                         ni->ni_mlrcnt = 0;
2206                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
2207                         mesh_peer_timeout_setup(ni);
2208                 } else {
2209                         args[0] = ni->ni_mlpid;
2210                         ieee80211_send_action(ni,
2211                             IEEE80211_ACTION_CAT_MESHPEERING,
2212                             IEEE80211_ACTION_MESHPEERING_OPEN, args);
2213                         ni->ni_mlrcnt++;
2214                         mesh_peer_timeout_backoff(ni);
2215                 }
2216                 break;
2217         case IEEE80211_NODE_MESH_CONFIRMRCV:
2218                 if (ni->ni_mlrcnt == ieee80211_mesh_maxretries) {
2219                         args[0] = ni->ni_mlpid;
2220                         args[2] = IEEE80211_REASON_MESH_CONFIRM_TIMEOUT;
2221                         ieee80211_send_action(ni,
2222                             IEEE80211_ACTION_CAT_MESHPEERING,
2223                             IEEE80211_ACTION_MESHPEERING_CLOSE, args);
2224                         ni->ni_mlrcnt = 0;
2225                         mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
2226                         mesh_peer_timeout_setup(ni);
2227                 } else {
2228                         ni->ni_mlrcnt++;
2229                         mesh_peer_timeout_setup(ni);
2230                 }
2231                 break;
2232         case IEEE80211_NODE_MESH_HOLDING:
2233                 mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE);
2234                 break;
2235         }
2236         wlan_serialize_exit();
2237 }
2238
2239 static int
2240 mesh_verify_meshid(struct ieee80211vap *vap, const uint8_t *ie)
2241 {
2242         struct ieee80211_mesh_state *ms = vap->iv_mesh;
2243
2244         if (ie == NULL || ie[1] != ms->ms_idlen)
2245                 return 1;
2246         return memcmp(ms->ms_id, ie + 2, ms->ms_idlen);
2247 }
2248
2249 /*
2250  * Check if we are using the same algorithms for this mesh.
2251  */
2252 static int
2253 mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie)
2254 {
2255         const struct ieee80211_meshconf_ie *meshconf =
2256             (const struct ieee80211_meshconf_ie *) ie;
2257         const struct ieee80211_mesh_state *ms = vap->iv_mesh;
2258         uint16_t cap;
2259
2260         if (meshconf == NULL)
2261                 return 1;
2262         if (meshconf->conf_pselid != ms->ms_ppath->mpp_ie) {
2263                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2264                     "unknown path selection algorithm: 0x%x\n",
2265                     meshconf->conf_pselid);
2266                 return 1;
2267         }
2268         if (meshconf->conf_pmetid != ms->ms_pmetric->mpm_ie) {
2269                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2270                     "unknown path metric algorithm: 0x%x\n",
2271                     meshconf->conf_pmetid);
2272                 return 1;
2273         }
2274         if (meshconf->conf_ccid != 0) {
2275                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2276                     "unknown congestion control algorithm: 0x%x\n",
2277                     meshconf->conf_ccid);
2278                 return 1;
2279         }
2280         if (meshconf->conf_syncid != IEEE80211_MESHCONF_SYNC_NEIGHOFF) {
2281                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2282                     "unknown sync algorithm: 0x%x\n",
2283                     meshconf->conf_syncid);
2284                 return 1;
2285         }
2286         if (meshconf->conf_authid != 0) {
2287                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2288                     "unknown auth algorithm: 0x%x\n",
2289                     meshconf->conf_pselid);
2290                 return 1;
2291         }
2292         /* NB: conf_cap is only read correctly here */
2293         cap = LE_READ_2(&meshconf->conf_cap);
2294         /* Not accepting peers */
2295         if (!(cap & IEEE80211_MESHCONF_CAP_AP)) {
2296                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
2297                     "not accepting peers: 0x%x\n", meshconf->conf_cap);
2298                 return 1;
2299         }
2300         return 0;
2301 }
2302
2303 static int
2304 mesh_verify_meshpeer(struct ieee80211vap *vap, uint8_t subtype,
2305     const uint8_t *ie)
2306 {
2307         const struct ieee80211_meshpeer_ie *meshpeer =
2308             (const struct ieee80211_meshpeer_ie *) ie;
2309
2310         if (meshpeer == NULL || meshpeer->peer_len < 6 ||
2311             meshpeer->peer_len > 10)
2312                 return 1;
2313         switch (subtype) {
2314         case IEEE80211_MESH_PEER_LINK_OPEN:
2315                 if (meshpeer->peer_len != 6)
2316                         return 1;
2317                 break;
2318         case IEEE80211_MESH_PEER_LINK_CONFIRM:
2319                 if (meshpeer->peer_len != 8)
2320                         return 1;
2321                 break;
2322         case IEEE80211_MESH_PEER_LINK_CLOSE:
2323                 if (meshpeer->peer_len < 8)
2324                         return 1;
2325                 if (meshpeer->peer_len == 8 && meshpeer->peer_linkid != 0)
2326                         return 1;
2327                 if (meshpeer->peer_rcode == 0)
2328                         return 1;
2329                 break;
2330         }
2331         return 0;
2332 }
2333
2334 /*
2335  * Add a Mesh ID IE to a frame.
2336  */
2337 uint8_t *
2338 ieee80211_add_meshid(uint8_t *frm, struct ieee80211vap *vap)
2339 {
2340         struct ieee80211_mesh_state *ms = vap->iv_mesh;
2341
2342         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a mbss vap"));
2343
2344         *frm++ = IEEE80211_ELEMID_MESHID;
2345         *frm++ = ms->ms_idlen;
2346         memcpy(frm, ms->ms_id, ms->ms_idlen);
2347         return frm + ms->ms_idlen;
2348 }
2349
2350 /*
2351  * Add a Mesh Configuration IE to a frame.
2352  * For now just use HWMP routing, Airtime link metric, Null Congestion
2353  * Signaling, Null Sync Protocol and Null Authentication.
2354  */
2355 uint8_t *
2356 ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap)
2357 {
2358         const struct ieee80211_mesh_state *ms = vap->iv_mesh;
2359         uint16_t caps;
2360
2361         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap"));
2362
2363         *frm++ = IEEE80211_ELEMID_MESHCONF;
2364         *frm++ = sizeof(struct ieee80211_meshconf_ie) - 2;
2365         *frm++ = ms->ms_ppath->mpp_ie;          /* path selection */
2366         *frm++ = ms->ms_pmetric->mpm_ie;        /* link metric */
2367         *frm++ = IEEE80211_MESHCONF_CC_DISABLED;
2368         *frm++ = IEEE80211_MESHCONF_SYNC_NEIGHOFF;
2369         *frm++ = IEEE80211_MESHCONF_AUTH_DISABLED;
2370         /* NB: set the number of neighbors before the rest */
2371         *frm = (ms->ms_neighbors > 15 ? 15 : ms->ms_neighbors) << 1;
2372         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
2373                 *frm |= IEEE80211_MESHCONF_FORM_MP;
2374         frm += 1;
2375         caps = 0;
2376         if (ms->ms_flags & IEEE80211_MESHFLAGS_AP)
2377                 caps |= IEEE80211_MESHCONF_CAP_AP;
2378         if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)
2379                 caps |= IEEE80211_MESHCONF_CAP_FWRD;
2380         ADDSHORT(frm, caps);
2381         return frm;
2382 }
2383
2384 /*
2385  * Add a Mesh Peer Management IE to a frame.
2386  */
2387 uint8_t *
2388 ieee80211_add_meshpeer(uint8_t *frm, uint8_t subtype, uint16_t localid,
2389     uint16_t peerid, uint16_t reason)
2390 {
2391         /* XXX change for AH */
2392         static const uint8_t meshpeerproto[4] = IEEE80211_MESH_PEER_PROTO;
2393
2394         KASSERT(localid != 0, ("localid == 0"));
2395
2396         *frm++ = IEEE80211_ELEMID_MESHPEER;
2397         switch (subtype) {
2398         case IEEE80211_MESH_PEER_LINK_OPEN:
2399                 *frm++ = 6;             /* length */
2400                 memcpy(frm, meshpeerproto, 4);
2401                 frm += 4;
2402                 ADDSHORT(frm, localid); /* local ID */
2403                 break;
2404         case IEEE80211_MESH_PEER_LINK_CONFIRM:
2405                 KASSERT(peerid != 0, ("sending peer confirm without peer id"));
2406                 *frm++ = 8;             /* length */
2407                 memcpy(frm, meshpeerproto, 4);
2408                 frm += 4;
2409                 ADDSHORT(frm, localid); /* local ID */
2410                 ADDSHORT(frm, peerid);  /* peer ID */
2411                 break;
2412         case IEEE80211_MESH_PEER_LINK_CLOSE:
2413                 if (peerid)
2414                         *frm++ = 10;    /* length */
2415                 else
2416                         *frm++ = 8;     /* length */
2417                 memcpy(frm, meshpeerproto, 4);
2418                 frm += 4;
2419                 ADDSHORT(frm, localid); /* local ID */
2420                 if (peerid)
2421                         ADDSHORT(frm, peerid);  /* peer ID */
2422                 ADDSHORT(frm, reason);
2423                 break;
2424         }
2425         return frm;
2426 }
2427
2428 /*
2429  * Compute an Airtime Link Metric for the link with this node.
2430  *
2431  * Based on Draft 3.0 spec (11B.10, p.149).
2432  */
2433 /*
2434  * Max 802.11s overhead.
2435  */
2436 #define IEEE80211_MESH_MAXOVERHEAD \
2437         (sizeof(struct ieee80211_qosframe_addr4) \
2438          + sizeof(struct ieee80211_meshcntl_ae11) \
2439         + sizeof(struct llc) \
2440         + IEEE80211_ADDR_LEN \
2441         + IEEE80211_WEP_IVLEN \
2442         + IEEE80211_WEP_KIDLEN \
2443         + IEEE80211_WEP_CRCLEN \
2444         + IEEE80211_WEP_MICLEN \
2445         + IEEE80211_CRC_LEN)
2446 uint32_t
2447 mesh_airtime_calc(struct ieee80211_node *ni)
2448 {
2449 #define M_BITS 8
2450 #define S_FACTOR (2 * M_BITS)
2451         struct ieee80211com *ic = ni->ni_ic;
2452         struct ifnet *ifp = ni->ni_vap->iv_ifp;
2453         static const int nbits = 8192 << M_BITS;
2454         uint32_t overhead, rate, errrate;
2455         uint64_t res;
2456
2457         /* Time to transmit a frame */
2458         rate = ni->ni_txrate;
2459         overhead = ieee80211_compute_duration(ic->ic_rt,
2460             ifp->if_mtu + IEEE80211_MESH_MAXOVERHEAD, rate, 0) << M_BITS;
2461         /* Error rate in percentage */
2462         /* XXX assuming small failures are ok */
2463         errrate = (((ifp->if_oerrors +
2464             ifp->if_ierrors) / 100) << M_BITS) / 100;
2465         res = (overhead + (nbits / rate)) *
2466             ((1 << S_FACTOR) / ((1 << M_BITS) - errrate));
2467
2468         return (uint32_t)(res >> S_FACTOR);
2469 #undef M_BITS
2470 #undef S_FACTOR
2471 }
2472
2473 /*
2474  * Add a Mesh Link Metric report IE to a frame.
2475  */
2476 uint8_t *
2477 ieee80211_add_meshlmetric(uint8_t *frm, uint32_t metric)
2478 {
2479         *frm++ = IEEE80211_ELEMID_MESHLINK;
2480         *frm++ = 4;
2481         ADDWORD(frm, metric);
2482         return frm;
2483 }
2484 #undef ADDSHORT
2485 #undef ADDWORD
2486
2487 /*
2488  * Initialize any mesh-specific node state.
2489  */
2490 void
2491 ieee80211_mesh_node_init(struct ieee80211vap *vap, struct ieee80211_node *ni)
2492 {
2493         ni->ni_flags |= IEEE80211_NODE_QOS;
2494         callout_init_mp(&ni->ni_mltimer);
2495 }
2496
2497 /*
2498  * Cleanup any mesh-specific node state.
2499  */
2500 void
2501 ieee80211_mesh_node_cleanup(struct ieee80211_node *ni)
2502 {
2503         struct ieee80211vap *vap = ni->ni_vap;
2504         struct ieee80211_mesh_state *ms = vap->iv_mesh;
2505
2506         callout_stop(&ni->ni_mltimer);
2507         /* NB: short-circuit callbacks after mesh_vdetach */
2508         if (vap->iv_mesh != NULL)
2509                 ms->ms_ppath->mpp_peerdown(ni);
2510 }
2511
2512 void
2513 ieee80211_parse_meshid(struct ieee80211_node *ni, const uint8_t *ie)
2514 {
2515         ni->ni_meshidlen = ie[1];
2516         memcpy(ni->ni_meshid, ie + 2, ie[1]);
2517 }
2518
2519 /*
2520  * Setup mesh-specific node state on neighbor discovery.
2521  */
2522 void
2523 ieee80211_mesh_init_neighbor(struct ieee80211_node *ni,
2524         const struct ieee80211_frame *wh,
2525         const struct ieee80211_scanparams *sp)
2526 {
2527         ieee80211_parse_meshid(ni, sp->meshid);
2528 }
2529
2530 void
2531 ieee80211_mesh_update_beacon(struct ieee80211vap *vap,
2532         struct ieee80211_beacon_offsets *bo)
2533 {
2534         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap"));
2535
2536         if (isset(bo->bo_flags, IEEE80211_BEACON_MESHCONF)) {
2537                 (void)ieee80211_add_meshconf(bo->bo_meshconf, vap);
2538                 clrbit(bo->bo_flags, IEEE80211_BEACON_MESHCONF);
2539         }
2540 }
2541
2542 static int
2543 mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
2544 {
2545         struct ieee80211_mesh_state *ms = vap->iv_mesh;
2546         uint8_t tmpmeshid[IEEE80211_NWID_LEN];
2547         struct ieee80211_mesh_route *rt;
2548         struct ieee80211req_mesh_route *imr;
2549         size_t len, off;
2550         uint8_t *p;
2551         int error;
2552
2553         if (vap->iv_opmode != IEEE80211_M_MBSS)
2554                 return ENOSYS;
2555
2556         error = 0;
2557         switch (ireq->i_type) {
2558         case IEEE80211_IOC_MESH_ID:
2559                 ireq->i_len = ms->ms_idlen;
2560                 memcpy(tmpmeshid, ms->ms_id, ireq->i_len);
2561                 error = copyout(tmpmeshid, ireq->i_data, ireq->i_len);
2562                 break;
2563         case IEEE80211_IOC_MESH_AP:
2564                 ireq->i_val = (ms->ms_flags & IEEE80211_MESHFLAGS_AP) != 0;
2565                 break;
2566         case IEEE80211_IOC_MESH_FWRD:
2567                 ireq->i_val = (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) != 0;
2568                 break;
2569         case IEEE80211_IOC_MESH_TTL:
2570                 ireq->i_val = ms->ms_ttl;
2571                 break;
2572         case IEEE80211_IOC_MESH_RTCMD:
2573                 switch (ireq->i_val) {
2574                 case IEEE80211_MESH_RTCMD_LIST:
2575                         len = 0;
2576                         TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
2577                                 len += sizeof(*imr);
2578                         }
2579                         if (len > ireq->i_len || ireq->i_len < sizeof(*imr)) {
2580                                 ireq->i_len = len;
2581                                 return ENOMEM;
2582                         }
2583                         ireq->i_len = len;
2584                         /* XXX M_WAIT? */
2585                         p = kmalloc(len, M_TEMP, M_INTWAIT | M_ZERO);
2586                         if (p == NULL)
2587                                 return ENOMEM;
2588                         off = 0;
2589                         TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
2590                                 if (off >= len)
2591                                         break;
2592                                 imr = (struct ieee80211req_mesh_route *)
2593                                     (p + off);
2594                                 imr->imr_flags = rt->rt_flags;
2595                                 IEEE80211_ADDR_COPY(imr->imr_dest,
2596                                     rt->rt_dest);
2597                                 IEEE80211_ADDR_COPY(imr->imr_nexthop,
2598                                     rt->rt_nexthop);
2599                                 imr->imr_metric = rt->rt_metric;
2600                                 imr->imr_nhops = rt->rt_nhops;
2601                                 imr->imr_lifetime = rt->rt_lifetime;
2602                                 imr->imr_lastmseq = rt->rt_lastmseq;
2603                                 off += sizeof(*imr);
2604                         }
2605                         error = copyout(p, (uint8_t *)ireq->i_data,
2606                             ireq->i_len);
2607                         kfree(p, M_TEMP);
2608                         break;
2609                 case IEEE80211_MESH_RTCMD_FLUSH:
2610                 case IEEE80211_MESH_RTCMD_ADD:
2611                 case IEEE80211_MESH_RTCMD_DELETE:
2612                         return EINVAL;
2613                 default:
2614                         return ENOSYS;
2615                 }
2616                 break;
2617         case IEEE80211_IOC_MESH_PR_METRIC:
2618                 len = strlen(ms->ms_pmetric->mpm_descr);
2619                 if (ireq->i_len < len)
2620                         return EINVAL;
2621                 ireq->i_len = len;
2622                 error = copyout(ms->ms_pmetric->mpm_descr,
2623                     (uint8_t *)ireq->i_data, len);
2624                 break;
2625         case IEEE80211_IOC_MESH_PR_PATH:
2626                 len = strlen(ms->ms_ppath->mpp_descr);
2627                 if (ireq->i_len < len)
2628                         return EINVAL;
2629                 ireq->i_len = len;
2630                 error = copyout(ms->ms_ppath->mpp_descr,
2631                     (uint8_t *)ireq->i_data, len);
2632                 break;
2633         default:
2634                 return ENOSYS;
2635         }
2636
2637         return error;
2638 }
2639 IEEE80211_IOCTL_GET(mesh, mesh_ioctl_get80211);
2640
2641 static int
2642 mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
2643 {
2644         struct ieee80211_mesh_state *ms = vap->iv_mesh;
2645         uint8_t tmpmeshid[IEEE80211_NWID_LEN];
2646         uint8_t tmpaddr[IEEE80211_ADDR_LEN];
2647         char tmpproto[IEEE80211_MESH_PROTO_DSZ];
2648         int error;
2649
2650         if (vap->iv_opmode != IEEE80211_M_MBSS)
2651                 return ENOSYS;
2652
2653         error = 0;
2654         switch (ireq->i_type) {
2655         case IEEE80211_IOC_MESH_ID:
2656                 if (ireq->i_val != 0 || ireq->i_len > IEEE80211_MESHID_LEN)
2657                         return EINVAL;
2658                 error = copyin(ireq->i_data, tmpmeshid, ireq->i_len);
2659                 if (error != 0)
2660                         break;
2661                 memset(ms->ms_id, 0, IEEE80211_NWID_LEN);
2662                 ms->ms_idlen = ireq->i_len;
2663                 memcpy(ms->ms_id, tmpmeshid, ireq->i_len);
2664                 error = ENETRESET;
2665                 break;
2666         case IEEE80211_IOC_MESH_AP:
2667                 if (ireq->i_val)
2668                         ms->ms_flags |= IEEE80211_MESHFLAGS_AP;
2669                 else
2670                         ms->ms_flags &= ~IEEE80211_MESHFLAGS_AP;
2671                 error = ENETRESET;
2672                 break;
2673         case IEEE80211_IOC_MESH_FWRD:
2674                 if (ireq->i_val)
2675                         ms->ms_flags |= IEEE80211_MESHFLAGS_FWD;
2676                 else
2677                         ms->ms_flags &= ~IEEE80211_MESHFLAGS_FWD;
2678                 break;
2679         case IEEE80211_IOC_MESH_TTL:
2680                 ms->ms_ttl = (uint8_t) ireq->i_val;
2681                 break;
2682         case IEEE80211_IOC_MESH_RTCMD:
2683                 switch (ireq->i_val) {
2684                 case IEEE80211_MESH_RTCMD_LIST:
2685                         return EINVAL;
2686                 case IEEE80211_MESH_RTCMD_FLUSH:
2687                         ieee80211_mesh_rt_flush(vap);
2688                         break;
2689                 case IEEE80211_MESH_RTCMD_ADD:
2690                         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, ireq->i_data) ||
2691                             IEEE80211_ADDR_EQ(broadcastaddr, ireq->i_data))
2692                                 return EINVAL;
2693                         error = copyin(ireq->i_data, &tmpaddr,
2694                             IEEE80211_ADDR_LEN);
2695                         if (error == 0)
2696                                 ieee80211_mesh_discover(vap, tmpaddr, NULL);
2697                         break;
2698                 case IEEE80211_MESH_RTCMD_DELETE:
2699                         ieee80211_mesh_rt_del(vap, ireq->i_data);
2700                         break;
2701                 default:
2702                         return ENOSYS;
2703                 }
2704                 break;
2705         case IEEE80211_IOC_MESH_PR_METRIC:
2706                 error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto));
2707                 if (error == 0) {
2708                         error = mesh_select_proto_metric(vap, tmpproto);
2709                         if (error == 0)
2710                                 error = ENETRESET;
2711                 }
2712                 break;
2713         case IEEE80211_IOC_MESH_PR_PATH:
2714                 error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto));
2715                 if (error == 0) {
2716                         error = mesh_select_proto_path(vap, tmpproto);
2717                         if (error == 0)
2718                                 error = ENETRESET;
2719                 }
2720                 break;
2721         default:
2722                 return ENOSYS;
2723         }
2724         return error;
2725 }
2726 IEEE80211_IOCTL_SET(mesh, mesh_ioctl_set80211);