]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/net80211/ieee80211_hwmp.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 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         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
714         /*
715          * Sequence number validation.
716          */
717         if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
718             HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
719                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
720                     "discard PREQ from %s, old seq no %u <= %u",
721                     ether_sprintf(preq->preq_origaddr),
722                     preq->preq_origseq, hrorig->hr_seq);
723                 return;
724         }
725         hrorig->hr_preqid = preq->preq_id;
726         hrorig->hr_seq = preq->preq_origseq;
727
728         /*
729          * Check if the PREQ is addressed to us.
730          */
731         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
732                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
733                     "reply to %s", ether_sprintf(preq->preq_origaddr));
734                 /*
735                  * Build and send a PREP frame.
736                  */
737                 prep.prep_flags = 0;
738                 prep.prep_hopcount = 0;
739                 prep.prep_ttl = ms->ms_ttl;
740                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
741                 prep.prep_targetseq = ++hs->hs_seq;
742                 prep.prep_lifetime = preq->preq_lifetime;
743                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
744                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
745                 prep.prep_origseq = preq->preq_origseq;
746                 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
747                 /*
748                  * Build the reverse path, if we don't have it already.
749                  */
750                 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
751                 if (rt == NULL)
752                         hwmp_discover(vap, preq->preq_origaddr, NULL);
753                 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
754                         hwmp_discover(vap, rt->rt_dest, NULL);
755                 return;
756         }
757         /*
758          * Proactive PREQ: reply with a proactive PREP to the
759          * root STA if requested.
760          */
761         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
762             (PREQ_TFLAGS(0) &
763             ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
764             (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
765                 uint8_t rootmac[IEEE80211_ADDR_LEN];
766
767                 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
768                 rt = ieee80211_mesh_rt_find(vap, rootmac);
769                 if (rt == NULL) {
770                         rt = ieee80211_mesh_rt_add(vap, rootmac);
771                         if (rt == NULL) {
772                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
773                                     "unable to add root mesh path to %s",
774                                     ether_sprintf(rootmac));
775                                 vap->iv_stats.is_mesh_rtaddfailed++;
776                                 return;
777                         }
778                 }
779                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
780                     "root mesh station @ %s", ether_sprintf(rootmac));
781
782                 /*
783                  * Reply with a PREP if we don't have a path to the root
784                  * or if the root sent us a proactive PREQ.
785                  */
786                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
787                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
788                         prep.prep_flags = 0;
789                         prep.prep_hopcount = 0;
790                         prep.prep_ttl = ms->ms_ttl;
791                         IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
792                         prep.prep_origseq = preq->preq_origseq;
793                         prep.prep_lifetime = preq->preq_lifetime;
794                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
795                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
796                             vap->iv_myaddr);
797                         prep.prep_targetseq = ++hs->hs_seq;
798                         hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
799                             broadcastaddr, &prep);
800                 }
801                 hwmp_discover(vap, rootmac, NULL);
802                 return;
803         }
804         rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
805
806         /*
807          * Forwarding and Intermediate reply for PREQs with 1 target.
808          */
809         if (preq->preq_tcount == 1) {
810                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
811
812                 memcpy(&ppreq, preq, sizeof(ppreq));
813                 /*
814                  * We have a valid route to this node.
815                  */
816                 if (rt != NULL &&
817                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
818                         if (preq->preq_ttl > 1 &&
819                             preq->preq_hopcount < hs->hs_maxhops) {
820                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
821                                     "forward PREQ from %s",
822                                     ether_sprintf(preq->preq_origaddr));
823                                 /*
824                                  * Propagate the original PREQ.
825                                  */
826                                 ppreq.preq_hopcount += 1;
827                                 ppreq.preq_ttl -= 1;
828                                 ppreq.preq_metric +=
829                                     ms->ms_pmetric->mpm_metric(ni);
830                                 /*
831                                  * Set TO and unset RF bits because we are going
832                                  * to send a PREP next.
833                                  */
834                                 ppreq.preq_targets[0].target_flags |=
835                                     IEEE80211_MESHPREQ_TFLAGS_TO;
836                                 ppreq.preq_targets[0].target_flags &=
837                                     ~IEEE80211_MESHPREQ_TFLAGS_RF;
838                                 hwmp_send_preq(ni, vap->iv_myaddr,
839                                     broadcastaddr, &ppreq);
840                         }
841                         /*
842                          * Check if we can send an intermediate Path Reply,
843                          * i.e., Target Only bit is not set.
844                          */
845                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
846                                 struct ieee80211_meshprep_ie prep;
847
848                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
849                                     "intermediate reply for PREQ from %s",
850                                     ether_sprintf(preq->preq_origaddr));
851                                 prep.prep_flags = 0;
852                                 prep.prep_hopcount = rt->rt_nhops + 1;
853                                 prep.prep_ttl = ms->ms_ttl;
854                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
855                                     PREQ_TADDR(0));
856                                 prep.prep_targetseq = hrorig->hr_seq;
857                                 prep.prep_lifetime = preq->preq_lifetime;
858                                 prep.prep_metric = rt->rt_metric +
859                                     ms->ms_pmetric->mpm_metric(ni);
860                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
861                                     preq->preq_origaddr);
862                                 prep.prep_origseq = hrorig->hr_seq;
863                                 hwmp_send_prep(ni, vap->iv_myaddr,
864                                     broadcastaddr, &prep);
865                         }
866                 /*
867                  * We have no information about this path,
868                  * propagate the PREQ.
869                  */
870                 } else if (preq->preq_ttl > 1 &&
871                     preq->preq_hopcount < hs->hs_maxhops) {
872                         if (rt == NULL) {
873                                 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
874                                 if (rt == NULL) {
875                                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
876                                             ni, "unable to add PREQ path to %s",
877                                             ether_sprintf(PREQ_TADDR(0)));
878                                         vap->iv_stats.is_mesh_rtaddfailed++;
879                                         return;
880                                 }
881                         }
882                         rt->rt_metric = preq->preq_metric;
883                         rt->rt_lifetime = preq->preq_lifetime;
884                         hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
885                             struct ieee80211_hwmp_route);
886                         hrorig->hr_seq = preq->preq_origseq;
887                         hrorig->hr_preqid = preq->preq_id;
888
889                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
890                             "forward PREQ from %s",
891                             ether_sprintf(preq->preq_origaddr));
892                         ppreq.preq_hopcount += 1;
893                         ppreq.preq_ttl -= 1;
894                         ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
895                         hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
896                             &ppreq);
897                 }
898         }
899
900 }
901 #undef  PREQ_TFLAGS
902 #undef  PREQ_TADDR
903 #undef  PREQ_TSEQ
904
905 static int
906 hwmp_send_preq(struct ieee80211_node *ni,
907     const uint8_t sa[IEEE80211_ADDR_LEN],
908     const uint8_t da[IEEE80211_ADDR_LEN],
909     struct ieee80211_meshpreq_ie *preq)
910 {
911         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
912
913         /*
914          * Enforce PREQ interval.
915          */
916         if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
917                 return EALREADY;
918         getmicrouptime(&hs->hs_lastpreq);
919
920         /*
921          * mesh preq action frame format
922          *     [6] da
923          *     [6] sa 
924          *     [6] addr3 = sa
925          *     [1] action
926          *     [1] category
927          *     [tlv] mesh path request
928          */
929         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
930         return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
931             sizeof(struct ieee80211_meshpreq_ie));
932 }
933
934 static void
935 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
936     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
937 {
938         struct ieee80211_mesh_state *ms = vap->iv_mesh;
939         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
940         struct ieee80211_mesh_route *rt = NULL;
941         struct ieee80211_hwmp_route *hr;
942         struct ieee80211com *ic = vap->iv_ic;
943         struct ifnet *ifp = vap->iv_ifp;
944         struct mbuf *m, *next;
945
946         /*
947          * Acceptance criteria: if the corresponding PREQ was not generated
948          * by us and forwarding is disabled, discard this PREP.
949          */
950         if (ni == vap->iv_bss ||
951             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
952                 return;
953         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
954             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
955                 return;
956
957         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
958             "received PREP from %s", ether_sprintf(prep->prep_targetaddr));
959
960         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
961         if (rt == NULL) {
962                 /*
963                  * If we have no entry this could be a reply to a root PREQ.
964                  */
965                 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
966                         rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
967                         if (rt == NULL) {
968                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
969                                     ni, "unable to add PREP path to %s",
970                                     ether_sprintf(prep->prep_targetaddr));
971                                 vap->iv_stats.is_mesh_rtaddfailed++;
972                                 return;
973                         }
974                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
975                         rt->rt_nhops = prep->prep_hopcount;
976                         rt->rt_lifetime = prep->prep_lifetime;
977                         rt->rt_metric = prep->prep_metric;
978                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
979                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
980                             "add root path to %s nhops %d metric %d (PREP)",
981                             ether_sprintf(prep->prep_targetaddr),
982                             rt->rt_nhops, rt->rt_metric);
983                         return;
984                 } 
985                 return;
986         }
987         /*
988          * Sequence number validation.
989          */
990         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
991         if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
992                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
993                     "discard PREP from %s, old seq no %u <= %u",
994                     ether_sprintf(prep->prep_targetaddr),
995                     prep->prep_targetseq, hr->hr_seq);
996                 return;
997         }
998         hr->hr_seq = prep->prep_targetseq;
999         /*
1000          * If it's NOT for us, propagate the PREP.
1001          */
1002         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1003             prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
1004                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1005
1006                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1007                     "propagate PREP from %s",
1008                     ether_sprintf(prep->prep_targetaddr));
1009
1010                 memcpy(&pprep, prep, sizeof(pprep));
1011                 pprep.prep_hopcount += 1;
1012                 pprep.prep_ttl -= 1;
1013                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1014                 IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
1015                 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
1016         }
1017         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1018         if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
1019                 /* NB: never clobber a proxy entry */;
1020                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1021                     "discard PREP for %s, route is marked PROXY",
1022                     ether_sprintf(prep->prep_targetaddr));
1023                 vap->iv_stats.is_hwmp_proxy++;
1024         } else if (prep->prep_origseq == hr->hr_origseq) {
1025                 /*
1026                  * Check if we already have a path to this node.
1027                  * If we do, check if this path reply contains a
1028                  * better route.
1029                  */
1030                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1031                     (prep->prep_hopcount < rt->rt_nhops ||
1032                      prep->prep_metric < rt->rt_metric)) {
1033                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1034                             "%s path to %s, hopcount %d:%d metric %d:%d",
1035                             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1036                                 "prefer" : "update",
1037                             ether_sprintf(prep->prep_origaddr),
1038                             rt->rt_nhops, prep->prep_hopcount,
1039                             rt->rt_metric, prep->prep_metric);
1040                         IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
1041                         rt->rt_nhops = prep->prep_hopcount;
1042                         rt->rt_lifetime = prep->prep_lifetime;
1043                         rt->rt_metric = prep->prep_metric;
1044                         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
1045                 } else {
1046                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1047                             "ignore PREP for %s, hopcount %d:%d metric %d:%d",
1048                             ether_sprintf(prep->prep_targetaddr),
1049                             rt->rt_nhops, prep->prep_hopcount,
1050                             rt->rt_metric, prep->prep_metric);
1051                 }
1052         } else {
1053                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1054                     "discard PREP for %s, wrong seqno %u != %u",
1055                     ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
1056                     hr->hr_seq);
1057                 vap->iv_stats.is_hwmp_wrongseq++;
1058         } 
1059         /*
1060          * Check for frames queued awaiting path discovery.
1061          * XXX probably can tell exactly and avoid remove call
1062          * NB: hash may have false matches, if so they will get
1063          *     stuck back on the stageq because there won't be
1064          *     a path.
1065          */
1066         m = ieee80211_ageq_remove(&ic->ic_stageq, 
1067             (struct ieee80211_node *)(uintptr_t)
1068                 ieee80211_mac_hash(ic, rt->rt_dest));
1069         for (; m != NULL; m = next) {
1070                 next = m->m_nextpkt;
1071                 m->m_nextpkt = NULL;
1072                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1073                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1074                 ifp->if_transmit(ifp, m);
1075         }
1076 }
1077
1078 static int
1079 hwmp_send_prep(struct ieee80211_node *ni,
1080     const uint8_t sa[IEEE80211_ADDR_LEN],
1081     const uint8_t da[IEEE80211_ADDR_LEN],
1082     struct ieee80211_meshprep_ie *prep)
1083 {
1084         /* NB: there's no PREP minimum interval. */
1085
1086         /*
1087          * mesh prep action frame format
1088          *     [6] da
1089          *     [6] sa 
1090          *     [6] addr3 = sa
1091          *     [1] action
1092          *     [1] category
1093          *     [tlv] mesh path reply
1094          */
1095         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1096         return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
1097             sizeof(struct ieee80211_meshprep_ie));
1098 }
1099
1100 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1101 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1102 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1103 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1104 static void
1105 hwmp_peerdown(struct ieee80211_node *ni)
1106 {
1107         struct ieee80211vap *vap = ni->ni_vap;
1108         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1109         struct ieee80211_meshperr_ie perr;
1110         struct ieee80211_mesh_route *rt;
1111         struct ieee80211_hwmp_route *hr;
1112
1113         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1114         if (rt == NULL)
1115                 return;
1116         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1117         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1118             "%s", "delete route entry");
1119         perr.perr_ttl = ms->ms_ttl;
1120         perr.perr_ndests = 1;
1121         PERR_DFLAGS(0) = 0;
1122         if (hr->hr_seq == 0)
1123                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1124         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1125         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1126         PERR_DSEQ(0) = hr->hr_seq;
1127         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1128         /* NB: flush everything passing through peer */
1129         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1130         hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
1131 }
1132 #undef  PERR_DFLAGS
1133 #undef  PERR_DADDR
1134 #undef  PERR_DSEQ
1135 #undef  PERR_DRCODE
1136
1137 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
1138 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
1139 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
1140 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
1141 static void
1142 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1143     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1144 {
1145         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1146         struct ieee80211_mesh_route *rt = NULL;
1147         struct ieee80211_hwmp_route *hr;
1148         struct ieee80211_meshperr_ie pperr;
1149         int i, forward = 0;
1150
1151         /*
1152          * Acceptance criteria: check if we received a PERR from a
1153          * neighbor and forwarding is enabled.
1154          */
1155         if (ni == vap->iv_bss ||
1156             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1157             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
1158                 return;
1159         /*
1160          * Find all routing entries that match and delete them.
1161          */
1162         for (i = 0; i < perr->perr_ndests; i++) {
1163                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1164                 if (rt == NULL)
1165                         continue;
1166                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1167                 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 
1168                     HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
1169                         ieee80211_mesh_rt_del(vap, rt->rt_dest);
1170                         ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
1171                         rt = NULL;
1172                         forward = 1;
1173                 }
1174         }
1175         /*
1176          * Propagate the PERR if we previously found it on our routing table.
1177          * XXX handle ndest > 1
1178          */
1179         if (forward && perr->perr_ttl > 1) {
1180                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1181                     "propagate PERR from %s", ether_sprintf(wh->i_addr2));
1182                 memcpy(&pperr, perr, sizeof(*perr));
1183                 pperr.perr_ttl--;
1184                 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
1185                     &pperr);
1186         }
1187 }
1188 #undef  PEER_DADDR
1189 #undef  PERR_DSEQ
1190
1191 static int
1192 hwmp_send_perr(struct ieee80211_node *ni,
1193     const uint8_t sa[IEEE80211_ADDR_LEN],
1194     const uint8_t da[IEEE80211_ADDR_LEN],
1195     struct ieee80211_meshperr_ie *perr)
1196 {
1197         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1198
1199         /*
1200          * Enforce PERR interval.
1201          */
1202         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1203                 return EALREADY;
1204         getmicrouptime(&hs->hs_lastperr);
1205
1206         /*
1207          * mesh perr action frame format
1208          *     [6] da
1209          *     [6] sa
1210          *     [6] addr3 = sa
1211          *     [1] action
1212          *     [1] category
1213          *     [tlv] mesh path error
1214          */
1215         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1216         return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
1217             sizeof(struct ieee80211_meshperr_ie));
1218 }
1219
1220 static void
1221 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1222     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1223 {
1224         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1225         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1226         struct ieee80211_mesh_route *rt = NULL;
1227         struct ieee80211_hwmp_route *hr;
1228         struct ieee80211_meshrann_ie prann;
1229
1230         if (ni == vap->iv_bss ||
1231             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1232             IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1233                 return;
1234
1235         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1236         /*
1237          * Discover the path to the root mesh STA.
1238          * If we already know it, propagate the RANN element.
1239          */
1240         if (rt == NULL) {
1241                 hwmp_discover(vap, rann->rann_addr, NULL);
1242                 return;
1243         }
1244         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1245         if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
1246                 hr->hr_seq = rann->rann_seq;
1247                 if (rann->rann_ttl > 1 &&
1248                     rann->rann_hopcount < hs->hs_maxhops &&
1249                     (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1250                         memcpy(&prann, rann, sizeof(prann));
1251                         prann.rann_hopcount += 1;
1252                         prann.rann_ttl -= 1;
1253                         prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1254                         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
1255                             broadcastaddr, &prann);
1256                 }
1257         }
1258 }
1259
1260 static int
1261 hwmp_send_rann(struct ieee80211_node *ni,
1262     const uint8_t sa[IEEE80211_ADDR_LEN],
1263     const uint8_t da[IEEE80211_ADDR_LEN],
1264     struct ieee80211_meshrann_ie *rann)
1265 {
1266         /*
1267          * mesh rann action frame format
1268          *     [6] da
1269          *     [6] sa 
1270          *     [6] addr3 = sa
1271          *     [1] action
1272          *     [1] category
1273          *     [tlv] root annoucement
1274          */
1275         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1276         return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
1277             sizeof(struct ieee80211_meshrann_ie));
1278 }
1279
1280 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1281 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1282 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1283 static struct ieee80211_node *
1284 hwmp_discover(struct ieee80211vap *vap,
1285     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1286 {
1287         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1288         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1289         struct ieee80211_mesh_route *rt = NULL;
1290         struct ieee80211_hwmp_route *hr;
1291         struct ieee80211_meshpreq_ie preq;
1292         struct ieee80211_node *ni;
1293         int sendpreq = 0;
1294
1295         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1296             ("not a mesh vap, opmode %d", vap->iv_opmode));
1297
1298         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1299             ("%s: discovering self!", __func__));
1300
1301         ni = NULL;
1302         if (!IEEE80211_IS_MULTICAST(dest)) {
1303                 rt = ieee80211_mesh_rt_find(vap, dest);
1304                 if (rt == NULL) {
1305                         rt = ieee80211_mesh_rt_add(vap, dest);
1306                         if (rt == NULL) {
1307                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1308                                     ni, "unable to add discovery path to %s",
1309                                     ether_sprintf(dest));
1310                                 vap->iv_stats.is_mesh_rtaddfailed++;
1311                                 goto done;
1312                         }
1313                 }
1314                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1315                     struct ieee80211_hwmp_route);
1316                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1317                         if (hr->hr_origseq == 0)
1318                                 hr->hr_origseq = ++hs->hs_seq;
1319                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1320                         rt->rt_lifetime =
1321                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1322                         /* XXX check preq retries */
1323                         sendpreq = 1;
1324                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1325                             "start path discovery (src %s)",
1326                             m == NULL ? "<none>" : ether_sprintf(
1327                                 mtod(m, struct ether_header *)->ether_shost));
1328                         /*
1329                          * Try to discover the path for this node.
1330                          */
1331                         preq.preq_flags = 0;
1332                         preq.preq_hopcount = 0;
1333                         preq.preq_ttl = ms->ms_ttl;
1334                         preq.preq_id = ++hs->hs_preqid;
1335                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1336                         preq.preq_origseq = hr->hr_origseq;
1337                         preq.preq_lifetime = rt->rt_lifetime;
1338                         preq.preq_metric = rt->rt_metric;
1339                         preq.preq_tcount = 1;
1340                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1341                         PREQ_TFLAGS(0) = 0;
1342                         if (ieee80211_hwmp_targetonly)
1343                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1344                         if (ieee80211_hwmp_replyforward)
1345                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
1346                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1347                         PREQ_TSEQ(0) = 0;
1348                         /* XXX check return value */
1349                         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
1350                             broadcastaddr, &preq);
1351                 }
1352                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
1353                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
1354         } else {
1355                 ni = ieee80211_find_txnode(vap, dest);
1356                 /* NB: if null then we leak mbuf */
1357                 KASSERT(ni != NULL, ("leak mcast frame"));
1358                 return ni;
1359         }
1360 done:
1361         if (ni == NULL && m != NULL) {
1362                 if (sendpreq) {
1363                         struct ieee80211com *ic = vap->iv_ic;
1364                         /*
1365                          * Queue packet for transmit when path discovery
1366                          * completes.  If discovery never completes the
1367                          * frame will be flushed by way of the aging timer.
1368                          */
1369                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1370                             "%s", "queue frame until path found");
1371                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
1372                             ieee80211_mac_hash(ic, dest);
1373                         /* XXX age chosen randomly */
1374                         ieee80211_ageq_append(&ic->ic_stageq, m,
1375                             IEEE80211_INACT_WAIT);
1376                 } else {
1377                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
1378                             dest, NULL, "%s", "no valid path to this node");
1379                         m_freem(m);
1380                 }
1381         }
1382         return ni;
1383 }
1384 #undef  PREQ_TFLAGS
1385 #undef  PREQ_TADDR
1386 #undef  PREQ_TSEQ
1387
1388 static int
1389 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1390 {
1391         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1392         int error;
1393  
1394         if (vap->iv_opmode != IEEE80211_M_MBSS)
1395                 return ENOSYS;
1396         error = 0;
1397         switch (ireq->i_type) {
1398         case IEEE80211_IOC_HWMP_ROOTMODE:
1399                 ireq->i_val = hs->hs_rootmode;
1400                 break;
1401         case IEEE80211_IOC_HWMP_MAXHOPS:
1402                 ireq->i_val = hs->hs_maxhops;
1403                 break;
1404         default:
1405                 return ENOSYS;
1406         }
1407         return error;
1408 }
1409 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
1410
1411 static int
1412 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1413 {
1414         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1415         int error;
1416
1417         if (vap->iv_opmode != IEEE80211_M_MBSS)
1418                 return ENOSYS;
1419         error = 0;
1420         switch (ireq->i_type) {
1421         case IEEE80211_IOC_HWMP_ROOTMODE:
1422                 if (ireq->i_val < 0 || ireq->i_val > 3)
1423                         return EINVAL;
1424                 hs->hs_rootmode = ireq->i_val;
1425                 hwmp_rootmode_setup(vap);
1426                 break;
1427         case IEEE80211_IOC_HWMP_MAXHOPS:
1428                 if (ireq->i_val <= 0 || ireq->i_val > 255)
1429                         return EINVAL;
1430                 hs->hs_maxhops = ireq->i_val;
1431                 break;
1432         default:
1433                 return ENOSYS;
1434         }
1435         return error;
1436 }
1437 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);