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