]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/net80211/ieee80211_hwmp.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / net80211 / ieee80211_hwmp.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 #include <sys/cdefs.h>
30 #ifdef __FreeBSD__
31 __FBSDID("$FreeBSD$");
32 #endif
33
34 /*
35  * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
36  * 
37  * Based on March 2009, D3.0 802.11s draft spec.
38  */
39 #include "opt_inet.h"
40 #include "opt_wlan.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h> 
44 #include <sys/mbuf.h>   
45 #include <sys/malloc.h>
46 #include <sys/kernel.h>
47
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/endian.h>
51 #include <sys/errno.h>
52 #include <sys/proc.h>
53 #include <sys/sysctl.h>
54
55 #include <net/if.h>
56 #include <net/if_media.h>
57 #include <net/if_llc.h>
58 #include <net/ethernet.h>
59
60 #include <net/bpf.h>
61
62 #include <net80211/ieee80211_var.h>
63 #include <net80211/ieee80211_action.h>
64 #include <net80211/ieee80211_input.h>
65 #include <net80211/ieee80211_mesh.h>
66
67 static void     hwmp_vattach(struct ieee80211vap *);
68 static void     hwmp_vdetach(struct ieee80211vap *);
69 static int      hwmp_newstate(struct ieee80211vap *,
70                     enum ieee80211_state, int);
71 static int      hwmp_send_action(struct ieee80211_node *,
72                     const uint8_t [IEEE80211_ADDR_LEN],
73                     const uint8_t [IEEE80211_ADDR_LEN],
74                     uint8_t *, size_t);
75 static uint8_t * hwmp_add_meshpreq(uint8_t *,
76                     const struct ieee80211_meshpreq_ie *);
77 static uint8_t * hwmp_add_meshprep(uint8_t *,
78                     const struct ieee80211_meshprep_ie *);
79 static uint8_t * hwmp_add_meshperr(uint8_t *,
80                     const struct ieee80211_meshperr_ie *);
81 static uint8_t * hwmp_add_meshrann(uint8_t *,
82                     const struct ieee80211_meshrann_ie *);
83 static void     hwmp_rootmode_setup(struct ieee80211vap *);
84 static void     hwmp_rootmode_cb(void *);
85 static void     hwmp_rootmode_rann_cb(void *);
86 static void     hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *,
87                     const struct ieee80211_frame *,
88                     const struct ieee80211_meshpreq_ie *);
89 static int      hwmp_send_preq(struct ieee80211_node *,
90                     const uint8_t [IEEE80211_ADDR_LEN],
91                     const uint8_t [IEEE80211_ADDR_LEN],
92                     struct ieee80211_meshpreq_ie *);
93 static void     hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *,
94                     const struct ieee80211_frame *,
95                     const struct ieee80211_meshprep_ie *);
96 static int      hwmp_send_prep(struct ieee80211_node *,
97                     const uint8_t [IEEE80211_ADDR_LEN],
98                     const uint8_t [IEEE80211_ADDR_LEN],
99                     struct ieee80211_meshprep_ie *);
100 static void     hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *,
101                     const struct ieee80211_frame *,
102                     const struct ieee80211_meshperr_ie *);
103 static int      hwmp_send_perr(struct ieee80211_node *,
104                     const uint8_t [IEEE80211_ADDR_LEN],
105                     const uint8_t [IEEE80211_ADDR_LEN],
106                     struct ieee80211_meshperr_ie *);
107 static void     hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *,
108                    const struct ieee80211_frame *,
109                    const struct ieee80211_meshrann_ie *);
110 static int      hwmp_send_rann(struct ieee80211_node *,
111                     const uint8_t [IEEE80211_ADDR_LEN],
112                     const uint8_t [IEEE80211_ADDR_LEN],
113                     struct ieee80211_meshrann_ie *);
114 static struct ieee80211_node *
115                 hwmp_discover(struct ieee80211vap *,
116                     const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *);
117 static void     hwmp_peerdown(struct ieee80211_node *);
118
119 static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
120 static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
121
122 /* unalligned little endian access */
123 #define LE_WRITE_2(p, v) do {                           \
124         ((uint8_t *)(p))[0] = (v) & 0xff;               \
125         ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;        \
126 } while (0)
127 #define LE_WRITE_4(p, v) do {                           \
128         ((uint8_t *)(p))[0] = (v) & 0xff;               \
129         ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;        \
130         ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff;       \
131         ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff;       \
132 } while (0)
133
134
135 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
136 static const uint8_t    broadcastaddr[IEEE80211_ADDR_LEN] =
137         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
138
139 typedef uint32_t ieee80211_hwmp_seq;
140 #define HWMP_SEQ_LT(a, b)       ((int32_t)((a)-(b)) < 0)
141 #define HWMP_SEQ_LEQ(a, b)      ((int32_t)((a)-(b)) <= 0)
142 #define HWMP_SEQ_GT(a, b)       ((int32_t)((a)-(b)) > 0)
143 #define HWMP_SEQ_GEQ(a, b)      ((int32_t)((a)-(b)) >= 0)
144
145 /*
146  * Private extension of ieee80211_mesh_route.
147  */
148 struct ieee80211_hwmp_route {
149         ieee80211_hwmp_seq      hr_seq;         /* last HWMP seq seen from dst*/
150         ieee80211_hwmp_seq      hr_preqid;      /* last PREQ ID seen from dst */
151         ieee80211_hwmp_seq      hr_origseq;     /* seq. no. on our latest PREQ*/
152         int                     hr_preqretries;
153 };
154 struct ieee80211_hwmp_state {
155         ieee80211_hwmp_seq      hs_seq;         /* next seq to be used */
156         ieee80211_hwmp_seq      hs_preqid;      /* next PREQ ID to be used */
157         struct timeval          hs_lastpreq;    /* last time we sent a PREQ */
158         struct timeval          hs_lastperr;    /* last time we sent a PERR */
159         int                     hs_rootmode;    /* proactive HWMP */
160         struct callout          hs_roottimer;
161         uint8_t                 hs_maxhops;     /* max hop count */
162 };
163
164 static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0,
165     "IEEE 802.11s HWMP parameters");
166 static int      ieee80211_hwmp_targetonly = 0;
167 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW,
168     &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
169 static int      ieee80211_hwmp_replyforward = 1;
170 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW,
171     &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs");
172 static int      ieee80211_hwmp_pathtimeout = -1;
173 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW,
174     &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
175     "path entry lifetime (ms)");
176 static int      ieee80211_hwmp_roottimeout = -1;
177 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW,
178     &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
179     "root PREQ timeout (ms)");
180 static int      ieee80211_hwmp_rootint = -1;
181 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW,
182     &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I",
183     "root interval (ms)");
184 static int      ieee80211_hwmp_rannint = -1;
185 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
186     &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I",
187     "root announcement interval (ms)");
188
189 #define IEEE80211_HWMP_DEFAULT_MAXHOPS  31
190
191 static  ieee80211_recv_action_func hwmp_recv_action_meshpath;
192
193 static struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
194         .mpp_descr      = "HWMP",
195         .mpp_ie         = IEEE80211_MESHCONF_PATH_HWMP,
196         .mpp_discover   = hwmp_discover,
197         .mpp_peerdown   = hwmp_peerdown,
198         .mpp_vattach    = hwmp_vattach,
199         .mpp_vdetach    = hwmp_vdetach,
200         .mpp_newstate   = hwmp_newstate,
201         .mpp_privlen    = sizeof(struct ieee80211_hwmp_route),
202 };
203 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW,
204         &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I",
205         "mesh route inactivity timeout (ms)");
206
207
208 static void
209 ieee80211_hwmp_init(void)
210 {
211         ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
212         ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
213         ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
214         ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
215
216         /*
217          * Register action frame handler.
218          */
219         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
220             IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath);
221
222         /* NB: default is 5 secs per spec */
223         mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
224
225         /*
226          * Register HWMP.
227          */
228         ieee80211_mesh_register_proto_path(&mesh_proto_hwmp);
229 }
230 SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL);
231
232 void
233 hwmp_vattach(struct ieee80211vap *vap)
234 {
235         struct ieee80211_hwmp_state *hs;
236
237         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
238             ("not a mesh vap, opmode %d", vap->iv_opmode));
239
240         hs = malloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP,
241             M_NOWAIT | M_ZERO);
242         if (hs == NULL) {
243                 printf("%s: couldn't alloc HWMP state\n", __func__);
244                 return;
245         }
246         hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
247         callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE);
248         vap->iv_hwmp = hs;
249 }
250
251 void
252 hwmp_vdetach(struct ieee80211vap *vap)
253 {
254         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
255
256         callout_drain(&hs->hs_roottimer);
257         free(vap->iv_hwmp, M_80211_VAP);
258         vap->iv_hwmp = NULL;
259
260
261 int
262 hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
263 {
264         enum ieee80211_state nstate = vap->iv_state;
265         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
266
267         IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
268             __func__, ieee80211_state_name[ostate],
269             ieee80211_state_name[nstate], arg);
270
271         if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
272                 callout_drain(&hs->hs_roottimer);
273         if (nstate == IEEE80211_S_RUN)
274                 hwmp_rootmode_setup(vap);
275         return 0;
276 }
277
278 static int
279 hwmp_recv_action_meshpath(struct ieee80211_node *ni,
280         const struct ieee80211_frame *wh,
281         const uint8_t *frm, const uint8_t *efrm)
282 {
283         struct ieee80211vap *vap = ni->ni_vap;
284         struct ieee80211_meshpreq_ie preq;
285         struct ieee80211_meshprep_ie prep;
286         struct ieee80211_meshperr_ie perr;
287         struct ieee80211_meshrann_ie rann;
288         const uint8_t *iefrm = frm + 2; /* action + code */
289         int found = 0;
290
291         while (efrm - iefrm > 1) {
292                 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
293                 switch (*iefrm) {
294                 case IEEE80211_ELEMID_MESHPREQ:
295                 {
296                         const struct ieee80211_meshpreq_ie *mpreq =
297                             (const struct ieee80211_meshpreq_ie *) iefrm;
298                         /* XXX > 1 target */
299                         if (mpreq->preq_len !=
300                             sizeof(struct ieee80211_meshpreq_ie) - 2) {
301                                 IEEE80211_DISCARD(vap,
302                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
303                                     wh, NULL, "%s", "PREQ with wrong len");
304                                 vap->iv_stats.is_rx_mgtdiscard++;
305                                 break;
306                         }
307                         memcpy(&preq, mpreq, sizeof(preq));
308                         preq.preq_id = LE_READ_4(&mpreq->preq_id);
309                         preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq);
310                         preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime);
311                         preq.preq_metric = LE_READ_4(&mpreq->preq_metric);
312                         preq.preq_targets[0].target_seq =
313                             LE_READ_4(&mpreq->preq_targets[0].target_seq);
314                         hwmp_recv_preq(vap, ni, wh, &preq);
315                         found++;
316                         break;  
317                 }
318                 case IEEE80211_ELEMID_MESHPREP:
319                 {
320                         const struct ieee80211_meshprep_ie *mprep =
321                             (const struct ieee80211_meshprep_ie *) iefrm;
322                         if (mprep->prep_len !=
323                             sizeof(struct ieee80211_meshprep_ie) - 2) {
324                                 IEEE80211_DISCARD(vap,
325                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
326                                     wh, NULL, "%s", "PREP with wrong len");
327                                 vap->iv_stats.is_rx_mgtdiscard++;
328                                 break;
329                         }
330                         memcpy(&prep, mprep, sizeof(prep));
331                         prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq);
332                         prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime);
333                         prep.prep_metric = LE_READ_4(&mprep->prep_metric);
334                         prep.prep_origseq = LE_READ_4(&mprep->prep_origseq);
335                         hwmp_recv_prep(vap, ni, wh, &prep);
336                         found++;
337                         break;
338                 }
339                 case IEEE80211_ELEMID_MESHPERR:
340                 {
341                         const struct ieee80211_meshperr_ie *mperr =
342                             (const struct ieee80211_meshperr_ie *) iefrm;
343                         /* XXX > 1 target */
344                         if (mperr->perr_len !=
345                             sizeof(struct ieee80211_meshperr_ie) - 2) {
346                                 IEEE80211_DISCARD(vap,
347                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
348                                     wh, NULL, "%s", "PERR with wrong len");
349                                 vap->iv_stats.is_rx_mgtdiscard++;
350                                 break;
351                         }
352                         memcpy(&perr, mperr, sizeof(perr));
353                         perr.perr_dests[0].dest_seq =
354                             LE_READ_4(&mperr->perr_dests[0].dest_seq);
355                         hwmp_recv_perr(vap, ni, wh, &perr);
356                         found++;
357                         break;
358                 }
359                 case IEEE80211_ELEMID_MESHRANN:
360                 {
361                         const struct ieee80211_meshrann_ie *mrann =
362                             (const struct ieee80211_meshrann_ie *) iefrm;
363                         if (mrann->rann_len !=
364                             sizeof(struct ieee80211_meshrann_ie) - 2) {
365                                 IEEE80211_DISCARD(vap,
366                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
367                                     wh, NULL, "%s", "RAN with wrong len");
368                                 vap->iv_stats.is_rx_mgtdiscard++;
369                                 return 1;
370                         }
371                         memcpy(&rann, mrann, sizeof(rann));
372                         rann.rann_seq = LE_READ_4(&mrann->rann_seq);
373                         rann.rann_metric = LE_READ_4(&mrann->rann_metric);
374                         hwmp_recv_rann(vap, ni, wh, &rann);
375                         found++;
376                         break;
377                 }
378                 }
379                 iefrm += iefrm[1] + 2;
380         }
381         if (!found) {
382                 IEEE80211_DISCARD(vap,
383                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
384                     wh, NULL, "%s", "PATH SEL action without IE");
385                 vap->iv_stats.is_rx_mgtdiscard++;
386         }
387         return 0;
388 }
389
390 static int
391 hwmp_send_action(struct ieee80211_node *ni,
392     const uint8_t sa[IEEE80211_ADDR_LEN],
393     const uint8_t da[IEEE80211_ADDR_LEN],
394     uint8_t *ie, size_t len)
395 {
396         struct ieee80211vap *vap = ni->ni_vap;
397         struct ieee80211com *ic = ni->ni_ic;
398         struct ieee80211_bpf_params params;
399         struct mbuf *m;
400         uint8_t *frm;
401
402         if (vap->iv_state == IEEE80211_S_CAC) {
403                 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
404                     "block %s frame in CAC state", "HWMP action");
405                 vap->iv_stats.is_tx_badstate++;
406                 return EIO;     /* XXX */
407         }
408
409         KASSERT(ni != NULL, ("null node"));
410         /*
411          * Hold a reference on the node so it doesn't go away until after
412          * the xmit is complete all the way in the driver.  On error we
413          * will remove our reference.
414          */
415 #ifdef IEEE80211_DEBUG_REFCNT
416         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
417             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
418             __func__, __LINE__,
419             ni, ether_sprintf(ni->ni_macaddr),
420             ieee80211_node_refcnt(ni)+1);
421 #endif
422         ieee80211_ref_node(ni);
423
424         m = ieee80211_getmgtframe(&frm,
425             ic->ic_headroom + sizeof(struct ieee80211_frame),
426             sizeof(struct ieee80211_action) + len
427         );
428         if (m == NULL) {
429                 ieee80211_free_node(ni);
430                 vap->iv_stats.is_tx_nobuf++;
431                 return ENOMEM;
432         }
433         *frm++ = IEEE80211_ACTION_CAT_MESHPATH;
434         *frm++ = IEEE80211_ACTION_MESHPATH_SEL;
435         switch (*ie) {
436         case IEEE80211_ELEMID_MESHPREQ:
437                 frm = hwmp_add_meshpreq(frm,
438                     (struct ieee80211_meshpreq_ie *)ie);
439                 break;
440         case IEEE80211_ELEMID_MESHPREP:
441                 frm = hwmp_add_meshprep(frm,
442                     (struct ieee80211_meshprep_ie *)ie);
443                 break;
444         case IEEE80211_ELEMID_MESHPERR:
445                 frm = hwmp_add_meshperr(frm,
446                     (struct ieee80211_meshperr_ie *)ie);
447                 break;
448         case IEEE80211_ELEMID_MESHRANN:
449                 frm = hwmp_add_meshrann(frm,
450                     (struct ieee80211_meshrann_ie *)ie);
451                 break;
452         }
453
454         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
455         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
456         if (m == NULL) {
457                 ieee80211_free_node(ni);
458                 vap->iv_stats.is_tx_nobuf++;
459                 return ENOMEM;
460         }
461         ieee80211_send_setup(ni, m,
462             IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
463             IEEE80211_NONQOS_TID, sa, da, sa);
464
465         m->m_flags |= M_ENCAP;          /* mark encapsulated */
466         IEEE80211_NODE_STAT(ni, tx_mgmt);
467
468         memset(&params, 0, sizeof(params));
469         params.ibp_pri = WME_AC_VO;
470         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
471         if (IEEE80211_IS_MULTICAST(da))
472                 params.ibp_try0 = 1;
473         else
474                 params.ibp_try0 = ni->ni_txparms->maxretry;
475         params.ibp_power = ni->ni_txpower;
476         return ic->ic_raw_xmit(ni, m, &params);
477 }
478
479 #define ADDSHORT(frm, v) do {           \
480         frm[0] = (v) & 0xff;            \
481         frm[1] = (v) >> 8;              \
482         frm += 2;                       \
483 } while (0)
484 #define ADDWORD(frm, v) do {            \
485         LE_WRITE_4(frm, v);             \
486         frm += 4;                       \
487 } while (0)
488 /*
489  * Add a Mesh Path Request IE to a frame.
490  */
491 static uint8_t *
492 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
493 {
494         int i;
495
496         *frm++ = IEEE80211_ELEMID_MESHPREQ;
497         *frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 +
498             (preq->preq_tcount - 1) * sizeof(*preq->preq_targets);
499         *frm++ = preq->preq_flags;
500         *frm++ = preq->preq_hopcount;
501         *frm++ = preq->preq_ttl;
502         ADDWORD(frm, preq->preq_id);
503         IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
504         ADDWORD(frm, preq->preq_origseq);
505         ADDWORD(frm, preq->preq_lifetime);
506         ADDWORD(frm, preq->preq_metric);
507         *frm++ = preq->preq_tcount;
508         for (i = 0; i < preq->preq_tcount; i++) {
509                 *frm++ = preq->preq_targets[i].target_flags;
510                 IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr);
511                 frm += 6;
512                 ADDWORD(frm, preq->preq_targets[i].target_seq);
513         }
514         return frm;
515 }
516
517 /*
518  * Add a Mesh Path Reply IE to a frame.
519  */
520 static uint8_t *
521 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
522 {
523         *frm++ = IEEE80211_ELEMID_MESHPREP;
524         *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2;
525         *frm++ = prep->prep_flags;
526         *frm++ = prep->prep_hopcount;
527         *frm++ = prep->prep_ttl;
528         IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
529         ADDWORD(frm, prep->prep_targetseq);
530         ADDWORD(frm, prep->prep_lifetime);
531         ADDWORD(frm, prep->prep_metric);
532         IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
533         ADDWORD(frm, prep->prep_origseq);
534         return frm;
535 }
536
537 /*
538  * Add a Mesh Path Error IE to a frame.
539  */
540 static uint8_t *
541 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
542 {
543         int i;
544
545         *frm++ = IEEE80211_ELEMID_MESHPERR;
546         *frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 +
547             (perr->perr_ndests - 1) * sizeof(*perr->perr_dests);
548         *frm++ = perr->perr_ttl;
549         *frm++ = perr->perr_ndests;
550         for (i = 0; i < perr->perr_ndests; i++) {
551                 *frm++ = perr->perr_dests[i].dest_flags;
552                 IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
553                 frm += 6;
554                 ADDWORD(frm, perr->perr_dests[i].dest_seq);
555                 ADDSHORT(frm, perr->perr_dests[i].dest_rcode);
556         }
557         return frm;
558 }
559
560 /*
561  * Add a Root Annoucement IE to a frame.
562  */
563 static uint8_t *
564 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
565 {
566         *frm++ = IEEE80211_ELEMID_MESHRANN;
567         *frm++ = sizeof(struct ieee80211_meshrann_ie) - 2;
568         *frm++ = rann->rann_flags;
569         *frm++ = rann->rann_hopcount;
570         *frm++ = rann->rann_ttl;
571         IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
572         ADDWORD(frm, rann->rann_seq);
573         ADDWORD(frm, rann->rann_metric);
574         return frm;
575 }
576
577 static void
578 hwmp_rootmode_setup(struct ieee80211vap *vap)
579 {
580         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
581
582         switch (hs->hs_rootmode) {
583         case IEEE80211_HWMP_ROOTMODE_DISABLED:
584                 callout_drain(&hs->hs_roottimer);
585                 break;
586         case IEEE80211_HWMP_ROOTMODE_NORMAL:
587         case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
588                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
589                     hwmp_rootmode_cb, vap);
590                 break;
591         case IEEE80211_HWMP_ROOTMODE_RANN:
592                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
593                     hwmp_rootmode_rann_cb, vap);
594                 break;
595         }
596 }
597
598 /*
599  * Send a broadcast Path Request to find all nodes on the mesh. We are
600  * called when the vap is configured as a HWMP root node.
601  */
602 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
603 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
604 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
605 static void
606 hwmp_rootmode_cb(void *arg)
607 {
608         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
609         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
610         struct ieee80211_mesh_state *ms = vap->iv_mesh;
611         struct ieee80211_meshpreq_ie preq;
612
613         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
614             "%s", "send broadcast PREQ");
615
616         preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
617         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
618                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
619         if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
620                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
621         preq.preq_hopcount = 0;
622         preq.preq_ttl = ms->ms_ttl;
623         preq.preq_id = ++hs->hs_preqid;
624         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
625         preq.preq_origseq = ++hs->hs_seq;
626         preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout);
627         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
628         preq.preq_tcount = 1;
629         IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
630         PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
631             IEEE80211_MESHPREQ_TFLAGS_RF;
632         PREQ_TSEQ(0) = 0;
633         vap->iv_stats.is_hwmp_rootreqs++;
634         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
635         hwmp_rootmode_setup(vap);
636 }
637 #undef  PREQ_TFLAGS
638 #undef  PREQ_TADDR
639 #undef  PREQ_TSEQ
640
641 /*
642  * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
643  * called when the vap is configured as a HWMP RANN root node.
644  */
645 static void
646 hwmp_rootmode_rann_cb(void *arg)
647 {
648         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
649         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
650         struct ieee80211_mesh_state *ms = vap->iv_mesh;
651         struct ieee80211_meshrann_ie rann;
652
653         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
654             "%s", "send broadcast RANN");
655
656         rann.rann_flags = 0;
657         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
658                 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
659         rann.rann_hopcount = 0;
660         rann.rann_ttl = ms->ms_ttl;
661         IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
662         rann.rann_seq = ++hs->hs_seq;
663         rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
664
665         vap->iv_stats.is_hwmp_rootrann++;
666         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
667         hwmp_rootmode_setup(vap);
668 }
669
670 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
671 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
672 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
673 static void
674 hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
675     const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
676 {
677         struct ieee80211_mesh_state *ms = vap->iv_mesh;
678         struct ieee80211_mesh_route *rt = NULL;
679         struct ieee80211_mesh_route *rtorig = NULL;
680         struct ieee80211_hwmp_route *hrorig;
681         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
682         struct ieee80211_meshprep_ie prep;
683
684         if (ni == vap->iv_bss ||
685             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
686                 return;
687         /*
688          * Ignore PREQs from us. Could happen because someone forward it
689          * back to us.
690          */
691         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr))
692                 return;
693
694         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
695             "received PREQ, source %s", ether_sprintf(preq->preq_origaddr));
696
697         /*
698          * Acceptance criteria: if the PREQ is not for us and
699          * forwarding is disabled, discard this PREQ.
700          */
701         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) &&
702             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
703                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
704                     preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
705                 return;
706         }
707         rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
708         if (rtorig == NULL)
709                 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
710         if (rtorig == NULL) {
711                 /* XXX stat */
712                 return;
713         }
714         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
715         /*
716          * Sequence number validation.
717          */
718         if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
719             HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
720                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
721                     "discard PREQ from %s, old seq no %u <= %u",
722                     ether_sprintf(preq->preq_origaddr),
723                     preq->preq_origseq, hrorig->hr_seq);
724                 return;
725         }
726         hrorig->hr_preqid = preq->preq_id;
727         hrorig->hr_seq = preq->preq_origseq;
728
729         /*
730          * Check if the PREQ is addressed to us.
731          */
732         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
733                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
734                     "reply to %s", ether_sprintf(preq->preq_origaddr));
735                 /*
736                  * Build and send a PREP frame.
737                  */
738                 prep.prep_flags = 0;
739                 prep.prep_hopcount = 0;
740                 prep.prep_ttl = ms->ms_ttl;
741                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
742                 prep.prep_targetseq = ++hs->hs_seq;
743                 prep.prep_lifetime = preq->preq_lifetime;
744                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
745                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
746                 prep.prep_origseq = preq->preq_origseq;
747                 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
748                 /*
749                  * Build the reverse path, if we don't have it already.
750                  */
751                 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
752                 if (rt == NULL)
753                         hwmp_discover(vap, preq->preq_origaddr, NULL);
754                 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
755                         hwmp_discover(vap, rt->rt_dest, NULL);
756                 return;
757         }
758         /*
759          * Proactive PREQ: reply with a proactive PREP to the
760          * root STA if requested.
761          */
762         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
763             (PREQ_TFLAGS(0) &
764             ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
765             (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
766                 uint8_t rootmac[IEEE80211_ADDR_LEN];
767
768                 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
769                 rt = ieee80211_mesh_rt_find(vap, rootmac);
770                 if (rt == NULL) {
771                         rt = ieee80211_mesh_rt_add(vap, rootmac);
772                         if (rt == NULL) {
773                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
774                                     "unable to add root mesh path to %s",
775                                     ether_sprintf(rootmac));
776                                 vap->iv_stats.is_mesh_rtaddfailed++;
777                                 return;
778                         }
779                 }
780                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
781                     "root mesh station @ %s", ether_sprintf(rootmac));
782
783                 /*
784                  * Reply with a PREP if we don't have a path to the root
785                  * or if the root sent us a proactive PREQ.
786                  */
787                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
788                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
789                         prep.prep_flags = 0;
790                         prep.prep_hopcount = 0;
791                         prep.prep_ttl = ms->ms_ttl;
792                         IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
793                         prep.prep_origseq = preq->preq_origseq;
794                         prep.prep_lifetime = preq->preq_lifetime;
795                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
796                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
797                             vap->iv_myaddr);
798                         prep.prep_targetseq = ++hs->hs_seq;
799                         hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
800                             broadcastaddr, &prep);
801                 }
802                 hwmp_discover(vap, rootmac, NULL);
803                 return;
804         }
805         rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
806
807         /*
808          * Forwarding and Intermediate reply for PREQs with 1 target.
809          */
810         if (preq->preq_tcount == 1) {
811                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
812
813                 memcpy(&ppreq, preq, sizeof(ppreq));
814                 /*
815                  * We have a valid route to this node.
816                  */
817                 if (rt != NULL &&
818                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
819                         if (preq->preq_ttl > 1 &&
820                             preq->preq_hopcount < hs->hs_maxhops) {
821                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
822                                     "forward PREQ from %s",
823                                     ether_sprintf(preq->preq_origaddr));
824                                 /*
825                                  * Propagate the original PREQ.
826                                  */
827                                 ppreq.preq_hopcount += 1;
828                                 ppreq.preq_ttl -= 1;
829                                 ppreq.preq_metric +=
830                                     ms->ms_pmetric->mpm_metric(ni);
831                                 /*
832                                  * Set TO and unset RF bits because we are going
833                                  * to send a PREP next.
834                                  */
835                                 ppreq.preq_targets[0].target_flags |=
836                                     IEEE80211_MESHPREQ_TFLAGS_TO;
837                                 ppreq.preq_targets[0].target_flags &=
838                                     ~IEEE80211_MESHPREQ_TFLAGS_RF;
839                                 hwmp_send_preq(ni, vap->iv_myaddr,
840                                     broadcastaddr, &ppreq);
841                         }
842                         /*
843                          * Check if we can send an intermediate Path Reply,
844                          * i.e., Target Only bit is not set.
845                          */
846                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
847                                 struct ieee80211_meshprep_ie prep;
848
849                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
850                                     "intermediate reply for PREQ from %s",
851                                     ether_sprintf(preq->preq_origaddr));
852                                 prep.prep_flags = 0;
853                                 prep.prep_hopcount = rt->rt_nhops + 1;
854                                 prep.prep_ttl = ms->ms_ttl;
855                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
856                                     PREQ_TADDR(0));
857                                 prep.prep_targetseq = hrorig->hr_seq;
858                                 prep.prep_lifetime = preq->preq_lifetime;
859                                 prep.prep_metric = rt->rt_metric +
860                                     ms->ms_pmetric->mpm_metric(ni);
861                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
862                                     preq->preq_origaddr);
863                                 prep.prep_origseq = hrorig->hr_seq;
864                                 hwmp_send_prep(ni, vap->iv_myaddr,
865                                     broadcastaddr, &prep);
866                         }
867                 /*
868                  * We have no information about this path,
869                  * propagate the PREQ.
870                  */
871                 } else if (preq->preq_ttl > 1 &&
872                     preq->preq_hopcount < hs->hs_maxhops) {
873                         if (rt == NULL) {
874                                 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
875                                 if (rt == NULL) {
876                                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
877                                             ni, "unable to add PREQ path to %s",
878                                             ether_sprintf(PREQ_TADDR(0)));
879                                         vap->iv_stats.is_mesh_rtaddfailed++;
880                                         return;
881                                 }
882                         }
883                         rt->rt_metric = preq->preq_metric;
884                         rt->rt_lifetime = preq->preq_lifetime;
885                         hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
886                             struct ieee80211_hwmp_route);
887                         hrorig->hr_seq = preq->preq_origseq;
888                         hrorig->hr_preqid = preq->preq_id;
889
890                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
891                             "forward PREQ from %s",
892                             ether_sprintf(preq->preq_origaddr));
893                         ppreq.preq_hopcount += 1;
894                         ppreq.preq_ttl -= 1;
895                         ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
896                         hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
897                             &ppreq);
898                 }
899         }
900
901 }
902 #undef  PREQ_TFLAGS
903 #undef  PREQ_TADDR
904 #undef  PREQ_TSEQ
905
906 static int
907 hwmp_send_preq(struct ieee80211_node *ni,
908     const uint8_t sa[IEEE80211_ADDR_LEN],
909     const uint8_t da[IEEE80211_ADDR_LEN],
910     struct ieee80211_meshpreq_ie *preq)
911 {
912         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
913
914         /*
915          * Enforce PREQ interval.
916          */
917         if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
918                 return EALREADY;
919         getmicrouptime(&hs->hs_lastpreq);
920
921         /*
922          * mesh preq action frame format
923          *     [6] da
924          *     [6] sa 
925          *     [6] addr3 = sa
926          *     [1] action
927          *     [1] category
928          *     [tlv] mesh path request
929          */
930         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
931         return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
932             sizeof(struct ieee80211_meshpreq_ie));
933 }
934
935 static void
936 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
937     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
938 {
939         struct ieee80211_mesh_state *ms = vap->iv_mesh;
940         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
941         struct ieee80211_mesh_route *rt = NULL;
942         struct ieee80211_hwmp_route *hr;
943         struct ieee80211com *ic = vap->iv_ic;
944         struct ifnet *ifp = vap->iv_ifp;
945         struct mbuf *m, *next;
946
947         /*
948          * Acceptance criteria: if the corresponding PREQ was not generated
949          * by us and forwarding is disabled, discard this PREP.
950          */
951         if (ni == vap->iv_bss ||
952             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
953                 return;
954         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
955             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
956                 return;
957
958         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
959             "received PREP from %s", ether_sprintf(prep->prep_targetaddr));
960
961         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
962         if (rt == NULL) {
963                 /*
964                  * If we have no entry this could be a reply to a root PREQ.
965                  */
966                 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
967                         rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
968                         if (rt == NULL) {
969                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
970                                     ni, "unable to add PREP path to %s",
971                                     ether_sprintf(prep->prep_targetaddr));
972                                 vap->iv_stats.is_mesh_rtaddfailed++;
973                                 return;
974                         }
975                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
976                         rt->rt_nhops = prep->prep_hopcount;
977                         rt->rt_lifetime = prep->prep_lifetime;
978                         rt->rt_metric = prep->prep_metric;
979                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
980                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
981                             "add root path to %s nhops %d metric %d (PREP)",
982                             ether_sprintf(prep->prep_targetaddr),
983                             rt->rt_nhops, rt->rt_metric);
984                         return;
985                 } 
986                 return;
987         }
988         /*
989          * Sequence number validation.
990          */
991         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
992         if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
993                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
994                     "discard PREP from %s, old seq no %u <= %u",
995                     ether_sprintf(prep->prep_targetaddr),
996                     prep->prep_targetseq, hr->hr_seq);
997                 return;
998         }
999         hr->hr_seq = prep->prep_targetseq;
1000         /*
1001          * If it's NOT for us, propagate the PREP.
1002          */
1003         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1004             prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
1005                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1006
1007                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1008                     "propagate PREP from %s",
1009                     ether_sprintf(prep->prep_targetaddr));
1010
1011                 memcpy(&pprep, prep, sizeof(pprep));
1012                 pprep.prep_hopcount += 1;
1013                 pprep.prep_ttl -= 1;
1014                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1015                 IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
1016                 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
1017         }
1018         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1019         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1020                 /* NB: never clobber a proxy entry */;
1021                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1022                     "discard PREP for %s, route is marked PROXY",
1023                     ether_sprintf(prep->prep_targetaddr));
1024                 vap->iv_stats.is_hwmp_proxy++;
1025         } else if (prep->prep_origseq == hr->hr_origseq) {
1026                 /*
1027                  * Check if we already have a path to this node.
1028                  * If we do, check if this path reply contains a
1029                  * better route.
1030                  */
1031                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1032                     (prep->prep_hopcount < rt->rt_nhops ||
1033                      prep->prep_metric < rt->rt_metric)) {
1034                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1035                             "%s path to %s, hopcount %d:%d metric %d:%d",
1036                             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1037                                 "prefer" : "update",
1038                             ether_sprintf(prep->prep_origaddr),
1039                             rt->rt_nhops, prep->prep_hopcount,
1040                             rt->rt_metric, prep->prep_metric);
1041                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
1042                         rt->rt_nhops = prep->prep_hopcount;
1043                         rt->rt_lifetime = prep->prep_lifetime;
1044                         rt->rt_metric = prep->prep_metric;
1045                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
1046                 } else {
1047                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1048                             "ignore PREP for %s, hopcount %d:%d metric %d:%d",
1049                             ether_sprintf(prep->prep_targetaddr),
1050                             rt->rt_nhops, prep->prep_hopcount,
1051                             rt->rt_metric, prep->prep_metric);
1052                 }
1053         } else {
1054                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1055                     "discard PREP for %s, wrong seqno %u != %u",
1056                     ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
1057                     hr->hr_seq);
1058                 vap->iv_stats.is_hwmp_wrongseq++;
1059         } 
1060         /*
1061          * Check for frames queued awaiting path discovery.
1062          * XXX probably can tell exactly and avoid remove call
1063          * NB: hash may have false matches, if so they will get
1064          *     stuck back on the stageq because there won't be
1065          *     a path.
1066          */
1067         m = ieee80211_ageq_remove(&ic->ic_stageq, 
1068             (struct ieee80211_node *)(uintptr_t)
1069                 ieee80211_mac_hash(ic, rt->rt_dest));
1070         for (; m != NULL; m = next) {
1071                 next = m->m_nextpkt;
1072                 m->m_nextpkt = NULL;
1073                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1074                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1075                 ifp->if_transmit(ifp, m);
1076         }
1077 }
1078
1079 static int
1080 hwmp_send_prep(struct ieee80211_node *ni,
1081     const uint8_t sa[IEEE80211_ADDR_LEN],
1082     const uint8_t da[IEEE80211_ADDR_LEN],
1083     struct ieee80211_meshprep_ie *prep)
1084 {
1085         /* NB: there's no PREP minimum interval. */
1086
1087         /*
1088          * mesh prep action frame format
1089          *     [6] da
1090          *     [6] sa 
1091          *     [6] addr3 = sa
1092          *     [1] action
1093          *     [1] category
1094          *     [tlv] mesh path reply
1095          */
1096         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1097         return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
1098             sizeof(struct ieee80211_meshprep_ie));
1099 }
1100
1101 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1102 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1103 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1104 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1105 static void
1106 hwmp_peerdown(struct ieee80211_node *ni)
1107 {
1108         struct ieee80211vap *vap = ni->ni_vap;
1109         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1110         struct ieee80211_meshperr_ie perr;
1111         struct ieee80211_mesh_route *rt;
1112         struct ieee80211_hwmp_route *hr;
1113
1114         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1115         if (rt == NULL)
1116                 return;
1117         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1118         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1119             "%s", "delete route entry");
1120         perr.perr_ttl = ms->ms_ttl;
1121         perr.perr_ndests = 1;
1122         PERR_DFLAGS(0) = 0;
1123         if (hr->hr_seq == 0)
1124                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1125         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1126         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1127         PERR_DSEQ(0) = hr->hr_seq;
1128         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1129         /* NB: flush everything passing through peer */
1130         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1131         hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
1132 }
1133 #undef  PERR_DFLAGS
1134 #undef  PERR_DADDR
1135 #undef  PERR_DSEQ
1136 #undef  PERR_DRCODE
1137
1138 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
1139 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
1140 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
1141 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
1142 static void
1143 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1144     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1145 {
1146         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1147         struct ieee80211_mesh_route *rt = NULL;
1148         struct ieee80211_hwmp_route *hr;
1149         struct ieee80211_meshperr_ie pperr;
1150         int i, forward = 0;
1151
1152         /*
1153          * Acceptance criteria: check if we received a PERR from a
1154          * neighbor and forwarding is enabled.
1155          */
1156         if (ni == vap->iv_bss ||
1157             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1158             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
1159                 return;
1160         /*
1161          * Find all routing entries that match and delete them.
1162          */
1163         for (i = 0; i < perr->perr_ndests; i++) {
1164                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1165                 if (rt == NULL)
1166                         continue;
1167                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1168                 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 
1169                     HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
1170                         ieee80211_mesh_rt_del(vap, rt->rt_dest);
1171                         ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
1172                         rt = NULL;
1173                         forward = 1;
1174                 }
1175         }
1176         /*
1177          * Propagate the PERR if we previously found it on our routing table.
1178          * XXX handle ndest > 1
1179          */
1180         if (forward && perr->perr_ttl > 1) {
1181                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1182                     "propagate PERR from %s", ether_sprintf(wh->i_addr2));
1183                 memcpy(&pperr, perr, sizeof(*perr));
1184                 pperr.perr_ttl--;
1185                 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
1186                     &pperr);
1187         }
1188 }
1189 #undef  PEER_DADDR
1190 #undef  PERR_DSEQ
1191
1192 static int
1193 hwmp_send_perr(struct ieee80211_node *ni,
1194     const uint8_t sa[IEEE80211_ADDR_LEN],
1195     const uint8_t da[IEEE80211_ADDR_LEN],
1196     struct ieee80211_meshperr_ie *perr)
1197 {
1198         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1199
1200         /*
1201          * Enforce PERR interval.
1202          */
1203         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1204                 return EALREADY;
1205         getmicrouptime(&hs->hs_lastperr);
1206
1207         /*
1208          * mesh perr action frame format
1209          *     [6] da
1210          *     [6] sa
1211          *     [6] addr3 = sa
1212          *     [1] action
1213          *     [1] category
1214          *     [tlv] mesh path error
1215          */
1216         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1217         return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
1218             sizeof(struct ieee80211_meshperr_ie));
1219 }
1220
1221 static void
1222 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1223     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1224 {
1225         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1226         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1227         struct ieee80211_mesh_route *rt = NULL;
1228         struct ieee80211_hwmp_route *hr;
1229         struct ieee80211_meshrann_ie prann;
1230
1231         if (ni == vap->iv_bss ||
1232             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1233             IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1234                 return;
1235
1236         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1237         /*
1238          * Discover the path to the root mesh STA.
1239          * If we already know it, propagate the RANN element.
1240          */
1241         if (rt == NULL) {
1242                 hwmp_discover(vap, rann->rann_addr, NULL);
1243                 return;
1244         }
1245         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1246         if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
1247                 hr->hr_seq = rann->rann_seq;
1248                 if (rann->rann_ttl > 1 &&
1249                     rann->rann_hopcount < hs->hs_maxhops &&
1250                     (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1251                         memcpy(&prann, rann, sizeof(prann));
1252                         prann.rann_hopcount += 1;
1253                         prann.rann_ttl -= 1;
1254                         prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1255                         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
1256                             broadcastaddr, &prann);
1257                 }
1258         }
1259 }
1260
1261 static int
1262 hwmp_send_rann(struct ieee80211_node *ni,
1263     const uint8_t sa[IEEE80211_ADDR_LEN],
1264     const uint8_t da[IEEE80211_ADDR_LEN],
1265     struct ieee80211_meshrann_ie *rann)
1266 {
1267         /*
1268          * mesh rann action frame format
1269          *     [6] da
1270          *     [6] sa 
1271          *     [6] addr3 = sa
1272          *     [1] action
1273          *     [1] category
1274          *     [tlv] root annoucement
1275          */
1276         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1277         return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
1278             sizeof(struct ieee80211_meshrann_ie));
1279 }
1280
1281 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1282 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1283 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1284 static struct ieee80211_node *
1285 hwmp_discover(struct ieee80211vap *vap,
1286     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1287 {
1288         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1289         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1290         struct ieee80211_mesh_route *rt = NULL;
1291         struct ieee80211_hwmp_route *hr;
1292         struct ieee80211_meshpreq_ie preq;
1293         struct ieee80211_node *ni;
1294         int sendpreq = 0;
1295
1296         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1297             ("not a mesh vap, opmode %d", vap->iv_opmode));
1298
1299         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1300             ("%s: discovering self!", __func__));
1301
1302         ni = NULL;
1303         if (!IEEE80211_IS_MULTICAST(dest)) {
1304                 rt = ieee80211_mesh_rt_find(vap, dest);
1305                 if (rt == NULL) {
1306                         rt = ieee80211_mesh_rt_add(vap, dest);
1307                         if (rt == NULL) {
1308                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1309                                     ni, "unable to add discovery path to %s",
1310                                     ether_sprintf(dest));
1311                                 vap->iv_stats.is_mesh_rtaddfailed++;
1312                                 goto done;
1313                         }
1314                 }
1315                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1316                     struct ieee80211_hwmp_route);
1317                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1318                         if (hr->hr_origseq == 0)
1319                                 hr->hr_origseq = ++hs->hs_seq;
1320                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1321                         rt->rt_lifetime =
1322                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1323                         /* XXX check preq retries */
1324                         sendpreq = 1;
1325                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1326                             "start path discovery (src %s)",
1327                             m == NULL ? "<none>" : ether_sprintf(
1328                                 mtod(m, struct ether_header *)->ether_shost));
1329                         /*
1330                          * Try to discover the path for this node.
1331                          */
1332                         preq.preq_flags = 0;
1333                         preq.preq_hopcount = 0;
1334                         preq.preq_ttl = ms->ms_ttl;
1335                         preq.preq_id = ++hs->hs_preqid;
1336                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1337                         preq.preq_origseq = hr->hr_origseq;
1338                         preq.preq_lifetime = rt->rt_lifetime;
1339                         preq.preq_metric = rt->rt_metric;
1340                         preq.preq_tcount = 1;
1341                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1342                         PREQ_TFLAGS(0) = 0;
1343                         if (ieee80211_hwmp_targetonly)
1344                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1345                         if (ieee80211_hwmp_replyforward)
1346                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
1347                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1348                         PREQ_TSEQ(0) = 0;
1349                         /* XXX check return value */
1350                         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
1351                             broadcastaddr, &preq);
1352                 }
1353                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
1354                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
1355         } else {
1356                 ni = ieee80211_find_txnode(vap, dest);
1357                 /* NB: if null then we leak mbuf */
1358                 KASSERT(ni != NULL, ("leak mcast frame"));
1359                 return ni;
1360         }
1361 done:
1362         if (ni == NULL && m != NULL) {
1363                 if (sendpreq) {
1364                         struct ieee80211com *ic = vap->iv_ic;
1365                         /*
1366                          * Queue packet for transmit when path discovery
1367                          * completes.  If discovery never completes the
1368                          * frame will be flushed by way of the aging timer.
1369                          */
1370                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1371                             "%s", "queue frame until path found");
1372                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
1373                             ieee80211_mac_hash(ic, dest);
1374                         /* XXX age chosen randomly */
1375                         ieee80211_ageq_append(&ic->ic_stageq, m,
1376                             IEEE80211_INACT_WAIT);
1377                 } else {
1378                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
1379                             dest, NULL, "%s", "no valid path to this node");
1380                         m_freem(m);
1381                 }
1382         }
1383         return ni;
1384 }
1385 #undef  PREQ_TFLAGS
1386 #undef  PREQ_TADDR
1387 #undef  PREQ_TSEQ
1388
1389 static int
1390 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1391 {
1392         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1393         int error;
1394  
1395         if (vap->iv_opmode != IEEE80211_M_MBSS)
1396                 return ENOSYS;
1397         error = 0;
1398         switch (ireq->i_type) {
1399         case IEEE80211_IOC_HWMP_ROOTMODE:
1400                 ireq->i_val = hs->hs_rootmode;
1401                 break;
1402         case IEEE80211_IOC_HWMP_MAXHOPS:
1403                 ireq->i_val = hs->hs_maxhops;
1404                 break;
1405         default:
1406                 return ENOSYS;
1407         }
1408         return error;
1409 }
1410 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
1411
1412 static int
1413 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1414 {
1415         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1416         int error;
1417
1418         if (vap->iv_opmode != IEEE80211_M_MBSS)
1419                 return ENOSYS;
1420         error = 0;
1421         switch (ireq->i_type) {
1422         case IEEE80211_IOC_HWMP_ROOTMODE:
1423                 if (ireq->i_val < 0 || ireq->i_val > 3)
1424                         return EINVAL;
1425                 hs->hs_rootmode = ireq->i_val;
1426                 hwmp_rootmode_setup(vap);
1427                 break;
1428         case IEEE80211_IOC_HWMP_MAXHOPS:
1429                 if (ireq->i_val <= 0 || ireq->i_val > 255)
1430                         return EINVAL;
1431                 hs->hs_maxhops = ireq->i_val;
1432                 break;
1433         default:
1434                 return ENOSYS;
1435         }
1436         return error;
1437 }
1438 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);