]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_hwmp.c
PREP update
[FreeBSD/FreeBSD.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_EQ(a, b)       ((int32_t)((a)-(b)) == 0)
143 #define HWMP_SEQ_GT(a, b)       ((int32_t)((a)-(b)) > 0)
144 #define HWMP_SEQ_GEQ(a, b)      ((int32_t)((a)-(b)) >= 0)
145
146 #define HWMP_SEQ_MAX(a, b)      (a > b ? a : b)
147
148 /*
149  * Private extension of ieee80211_mesh_route.
150  */
151 struct ieee80211_hwmp_route {
152         ieee80211_hwmp_seq      hr_seq;         /* last HWMP seq seen from dst*/
153         ieee80211_hwmp_seq      hr_preqid;      /* last PREQ ID seen from dst */
154         ieee80211_hwmp_seq      hr_origseq;     /* seq. no. on our latest PREQ*/
155         int                     hr_preqretries;
156 };
157 struct ieee80211_hwmp_state {
158         ieee80211_hwmp_seq      hs_seq;         /* next seq to be used */
159         ieee80211_hwmp_seq      hs_preqid;      /* next PREQ ID to be used */
160         struct timeval          hs_lastpreq;    /* last time we sent a PREQ */
161         struct timeval          hs_lastperr;    /* last time we sent a PERR */
162         int                     hs_rootmode;    /* proactive HWMP */
163         struct callout          hs_roottimer;
164         uint8_t                 hs_maxhops;     /* max hop count */
165 };
166
167 static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0,
168     "IEEE 802.11s HWMP parameters");
169 static int      ieee80211_hwmp_targetonly = 0;
170 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW,
171     &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
172 static int      ieee80211_hwmp_replyforward = 1;
173 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW,
174     &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs");
175 static int      ieee80211_hwmp_pathtimeout = -1;
176 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW,
177     &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
178     "path entry lifetime (ms)");
179 static int      ieee80211_hwmp_roottimeout = -1;
180 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW,
181     &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
182     "root PREQ timeout (ms)");
183 static int      ieee80211_hwmp_rootint = -1;
184 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW,
185     &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I",
186     "root interval (ms)");
187 static int      ieee80211_hwmp_rannint = -1;
188 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
189     &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I",
190     "root announcement interval (ms)");
191
192 #define IEEE80211_HWMP_DEFAULT_MAXHOPS  31
193
194 static  ieee80211_recv_action_func hwmp_recv_action_meshpath;
195
196 static struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
197         .mpp_descr      = "HWMP",
198         .mpp_ie         = IEEE80211_MESHCONF_PATH_HWMP,
199         .mpp_discover   = hwmp_discover,
200         .mpp_peerdown   = hwmp_peerdown,
201         .mpp_vattach    = hwmp_vattach,
202         .mpp_vdetach    = hwmp_vdetach,
203         .mpp_newstate   = hwmp_newstate,
204         .mpp_privlen    = sizeof(struct ieee80211_hwmp_route),
205 };
206 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW,
207         &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I",
208         "mesh route inactivity timeout (ms)");
209
210
211 static void
212 ieee80211_hwmp_init(void)
213 {
214         ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
215         ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
216         ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
217         ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
218
219         /*
220          * Register action frame handler.
221          */
222         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
223             IEEE80211_ACTION_MESH_HWMP, hwmp_recv_action_meshpath);
224
225         /* NB: default is 5 secs per spec */
226         mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
227
228         /*
229          * Register HWMP.
230          */
231         ieee80211_mesh_register_proto_path(&mesh_proto_hwmp);
232 }
233 SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL);
234
235 void
236 hwmp_vattach(struct ieee80211vap *vap)
237 {
238         struct ieee80211_hwmp_state *hs;
239
240         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
241             ("not a mesh vap, opmode %d", vap->iv_opmode));
242
243         hs = malloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP,
244             M_NOWAIT | M_ZERO);
245         if (hs == NULL) {
246                 printf("%s: couldn't alloc HWMP state\n", __func__);
247                 return;
248         }
249         hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
250         callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE);
251         vap->iv_hwmp = hs;
252 }
253
254 void
255 hwmp_vdetach(struct ieee80211vap *vap)
256 {
257         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
258
259         callout_drain(&hs->hs_roottimer);
260         free(vap->iv_hwmp, M_80211_VAP);
261         vap->iv_hwmp = NULL;
262
263
264 int
265 hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
266 {
267         enum ieee80211_state nstate = vap->iv_state;
268         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
269
270         IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
271             __func__, ieee80211_state_name[ostate],
272             ieee80211_state_name[nstate], arg);
273
274         if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
275                 callout_drain(&hs->hs_roottimer);
276         if (nstate == IEEE80211_S_RUN)
277                 hwmp_rootmode_setup(vap);
278         return 0;
279 }
280
281 /*
282  * Verify the length of an HWMP PREQ and return the number
283  * of destinations >= 1, if verification fails -1 is returned.
284  */
285 static int
286 verify_mesh_preq_len(struct ieee80211vap *vap,
287     const struct ieee80211_frame *wh, const uint8_t *iefrm)
288 {
289         int alloc_sz = -1;
290         int ndest = -1;
291         if (iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE) {
292                 /* Originator External Address  present */
293                 alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ_AE;
294                 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET_AE];
295         } else {
296                 /* w/o Originator External Address */
297                 alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ;
298                 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET];
299         }
300         alloc_sz += ndest * IEEE80211_MESHPREQ_TRGT_SZ;
301
302         if(iefrm[1] != (alloc_sz)) {
303                 IEEE80211_DISCARD(vap,
304                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
305                     wh, NULL, "PREQ (AE=%s) with wrong len",
306                     iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE ? "1" : "0");
307                 return (-1);
308         }
309         return ndest;
310 }
311
312 /*
313  * Verify the length of an HWMP PREP and returns 1 on success,
314  * otherwise -1.
315  */
316 static int
317 verify_mesh_prep_len(struct ieee80211vap *vap,
318     const struct ieee80211_frame *wh, const uint8_t *iefrm)
319 {
320         int alloc_sz = -1;
321         if (iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE) {
322                 if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ_AE)
323                         alloc_sz = IEEE80211_MESHPREP_BASE_SZ_AE;
324         } else if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ)
325                 alloc_sz = IEEE80211_MESHPREP_BASE_SZ;
326         if(alloc_sz < 0) {
327                 IEEE80211_DISCARD(vap,
328                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
329                     wh, NULL, "PREP (AE=%s) with wrong len",
330                     iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE ? "1" : "0");
331                 return (-1);
332         }
333         return (1);
334 }
335
336 /*
337  * Verify the length of an HWMP PERR and return the number
338  * of destinations >= 1, if verification fails -1 is returned.
339  */
340 static int
341 verify_mesh_perr_len(struct ieee80211vap *vap,
342     const struct ieee80211_frame *wh, const uint8_t *iefrm)
343 {
344         int alloc_sz = -1;
345         const uint8_t *iefrm_t = iefrm;
346         uint8_t ndest = iefrm_t[IEEE80211_MESHPERR_NDEST_OFFSET];
347         int i;
348
349         if(ndest > IEEE80211_MESHPERR_MAXDEST) {
350                 IEEE80211_DISCARD(vap,
351                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
352                     wh, NULL, "PERR with wrong number of destionat (>19), %u",
353                     ndest);
354                 return (-1);
355         }
356
357         iefrm_t += IEEE80211_MESHPERR_NDEST_OFFSET + 1; /* flag is next field */
358         /* We need to check each destionation flag to know size */
359         for(i = 0; i<ndest; i++) {
360                 if ((*iefrm_t) & IEEE80211_MESHPERR_FLAGS_AE)
361                         iefrm_t += IEEE80211_MESHPERR_DEST_SZ_AE;
362                 else
363                         iefrm_t += IEEE80211_MESHPERR_DEST_SZ;
364         }
365
366         alloc_sz = (iefrm_t - iefrm) - 2; /* action + code */
367         if(alloc_sz !=  iefrm[1]) {
368                 IEEE80211_DISCARD(vap,
369                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
370                     wh, NULL, "%s", "PERR with wrong len");
371                 return (-1);
372         }
373         return ndest;
374 }
375
376 static int
377 hwmp_recv_action_meshpath(struct ieee80211_node *ni,
378         const struct ieee80211_frame *wh,
379         const uint8_t *frm, const uint8_t *efrm)
380 {
381         struct ieee80211vap *vap = ni->ni_vap;
382         struct ieee80211_meshpreq_ie *preq;
383         struct ieee80211_meshprep_ie *prep;
384         struct ieee80211_meshperr_ie *perr;
385         struct ieee80211_meshrann_ie rann;
386         const uint8_t *iefrm = frm + 2; /* action + code */
387         const uint8_t *iefrm_t = iefrm; /* temporary pointer */
388         int ndest = -1;
389         int found = 0;
390
391         while (efrm - iefrm > 1) {
392                 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
393                 switch (*iefrm) {
394                 case IEEE80211_ELEMID_MESHPREQ:
395                 {
396                         int i = 0;
397
398                         iefrm_t = iefrm;
399                         ndest = verify_mesh_preq_len(vap, wh, iefrm_t);
400                         if (ndest < 0) {
401                                 vap->iv_stats.is_rx_mgtdiscard++;
402                                 break;
403                         }
404                         preq = malloc(sizeof(*preq) +
405                             (ndest - 1) * sizeof(*preq->preq_targets),
406                             M_80211_MESH_PREQ, M_NOWAIT | M_ZERO);
407                         KASSERT(preq != NULL, ("preq == NULL"));
408
409                         preq->preq_ie = *iefrm_t++;
410                         preq->preq_len = *iefrm_t++;
411                         preq->preq_flags = *iefrm_t++;
412                         preq->preq_hopcount = *iefrm_t++;
413                         preq->preq_ttl = *iefrm_t++;
414                         preq->preq_id = LE_READ_4(iefrm_t); iefrm_t += 4;
415                         IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm_t);
416                         iefrm_t += 6;
417                         preq->preq_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
418                         /* NB: may have Originator Proxied Address */
419                         if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE)  {
420                                 IEEE80211_ADDR_COPY(
421                                     preq->preq_orig_ext_addr, iefrm_t);
422                                 iefrm_t += 6;
423                         }
424                         preq->preq_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
425                         preq->preq_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
426                         preq->preq_tcount = *iefrm_t++;
427                         
428                         for (i = 0; i < preq->preq_tcount; i++) {
429                                 preq->preq_targets[i].target_flags = *iefrm_t++;
430                                 IEEE80211_ADDR_COPY(
431                                     preq->preq_targets[i].target_addr, iefrm_t);
432                                 iefrm_t += 6;
433                                 preq->preq_targets[i].target_seq =
434                                     LE_READ_4(iefrm_t);
435                                 iefrm_t += 4;
436                         }
437
438                         hwmp_recv_preq(vap, ni, wh, preq);
439                         free(preq, M_80211_MESH_PREQ);
440                         found++;
441                         break;
442                 }
443                 case IEEE80211_ELEMID_MESHPREP:
444                 {
445                         iefrm_t = iefrm;
446                         ndest = verify_mesh_prep_len(vap, wh, iefrm_t);
447                         if (ndest < 0) {
448                                 vap->iv_stats.is_rx_mgtdiscard++;
449                                 break;
450                         }
451                         prep = malloc(sizeof(*prep),
452                             M_80211_MESH_PREP, M_NOWAIT | M_ZERO);
453                         KASSERT(prep != NULL, ("prep == NULL"));
454
455                         prep->prep_ie = *iefrm_t++;
456                         prep->prep_len = *iefrm_t++;
457                         prep->prep_flags = *iefrm_t++;
458                         prep->prep_hopcount = *iefrm_t++;
459                         prep->prep_ttl = *iefrm_t++;
460                         IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm_t);
461                         iefrm_t += 6;
462                         prep->prep_targetseq = LE_READ_4(iefrm_t); iefrm_t += 4;
463                         /* NB: May have Target Proxied Address */
464                         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE)  {
465                                 IEEE80211_ADDR_COPY(
466                                     prep->prep_target_ext_addr, iefrm_t);
467                                 iefrm_t += 6;
468                         }
469                         prep->prep_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
470                         prep->prep_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
471                         IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm_t);
472                         iefrm_t += 6;
473                         prep->prep_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
474
475                         hwmp_recv_prep(vap, ni, wh, prep);
476                         free(prep, M_80211_MESH_PREP);
477                         found++;
478                         break;
479                 }
480                 case IEEE80211_ELEMID_MESHPERR:
481                 {
482                         int i = 0;
483
484                         iefrm_t = iefrm;
485                         ndest = verify_mesh_perr_len(vap, wh, iefrm_t);
486                         if (ndest < 0) {
487                                 vap->iv_stats.is_rx_mgtdiscard++;
488                                 break;
489                         }
490                         perr = malloc(sizeof(*perr) +
491                             (ndest - 1) * sizeof(*perr->perr_dests),
492                             M_80211_MESH_PERR, M_NOWAIT | M_ZERO);
493                         KASSERT(perr != NULL, ("perr == NULL"));
494
495                         perr->perr_ie = *iefrm_t++;
496                         perr->perr_len = *iefrm_t++;
497                         perr->perr_ttl = *iefrm_t++;
498                         perr->perr_ndests = *iefrm_t++;
499
500                         for (i = 0; i<perr->perr_ndests; i++) {
501                                 perr->perr_dests[i].dest_flags = *iefrm_t++;
502                                 IEEE80211_ADDR_COPY(
503                                     perr->perr_dests[i].dest_addr, iefrm_t);
504                                 iefrm_t += 6;
505                                 perr->perr_dests[i].dest_seq = LE_READ_4(iefrm_t);
506                                 iefrm_t += 4;
507                                 /* NB: May have Target Proxied Address */
508                                 if (perr->perr_dests[i].dest_flags &
509                                     IEEE80211_MESHPERR_FLAGS_AE) {
510                                         IEEE80211_ADDR_COPY(
511                                             perr->perr_dests[i].dest_ext_addr,
512                                             iefrm_t);
513                                         iefrm_t += 6;
514                                 }
515                                 perr->perr_dests[i].dest_rcode =
516                                     LE_READ_2(iefrm_t);
517                                 iefrm_t += 2;
518                         }
519
520                         hwmp_recv_perr(vap, ni, wh, perr);
521                         free(perr, M_80211_MESH_PERR);
522                         found++;
523                         break;
524                 }
525                 case IEEE80211_ELEMID_MESHRANN:
526                 {
527                         const struct ieee80211_meshrann_ie *mrann =
528                             (const struct ieee80211_meshrann_ie *) iefrm;
529                         if (mrann->rann_len !=
530                             sizeof(struct ieee80211_meshrann_ie) - 2) {
531                                 IEEE80211_DISCARD(vap,
532                                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
533                                     wh, NULL, "%s", "RAN with wrong len");
534                                     vap->iv_stats.is_rx_mgtdiscard++;
535                                 return 1;
536                         }
537                         memcpy(&rann, mrann, sizeof(rann));
538                         rann.rann_seq = LE_READ_4(&mrann->rann_seq);
539                         rann.rann_metric = LE_READ_4(&mrann->rann_metric);
540                         hwmp_recv_rann(vap, ni, wh, &rann);
541                         found++;
542                         break;
543                 }
544                 }
545                 iefrm += iefrm[1] + 2;
546         }
547         if (!found) {
548                 IEEE80211_DISCARD(vap,
549                     IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
550                     wh, NULL, "%s", "PATH SEL action without IE");
551                 vap->iv_stats.is_rx_mgtdiscard++;
552         }
553         return 0;
554 }
555
556 static int
557 hwmp_send_action(struct ieee80211_node *ni,
558     const uint8_t sa[IEEE80211_ADDR_LEN],
559     const uint8_t da[IEEE80211_ADDR_LEN],
560     uint8_t *ie, size_t len)
561 {
562         struct ieee80211vap *vap = ni->ni_vap;
563         struct ieee80211com *ic = ni->ni_ic;
564         struct ieee80211_bpf_params params;
565         struct mbuf *m;
566         uint8_t *frm;
567
568         if (vap->iv_state == IEEE80211_S_CAC) {
569                 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
570                     "block %s frame in CAC state", "HWMP action");
571                 vap->iv_stats.is_tx_badstate++;
572                 return EIO;     /* XXX */
573         }
574
575         KASSERT(ni != NULL, ("null node"));
576         /*
577          * Hold a reference on the node so it doesn't go away until after
578          * the xmit is complete all the way in the driver.  On error we
579          * will remove our reference.
580          */
581 #ifdef IEEE80211_DEBUG_REFCNT
582         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
583             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
584             __func__, __LINE__,
585             ni, ether_sprintf(ni->ni_macaddr),
586             ieee80211_node_refcnt(ni)+1);
587 #endif
588         ieee80211_ref_node(ni);
589
590         m = ieee80211_getmgtframe(&frm,
591             ic->ic_headroom + sizeof(struct ieee80211_frame),
592             sizeof(struct ieee80211_action) + len
593         );
594         if (m == NULL) {
595                 ieee80211_free_node(ni);
596                 vap->iv_stats.is_tx_nobuf++;
597                 return ENOMEM;
598         }
599         *frm++ = IEEE80211_ACTION_CAT_MESH;
600         *frm++ = IEEE80211_ACTION_MESH_HWMP;
601         switch (*ie) {
602         case IEEE80211_ELEMID_MESHPREQ:
603                 frm = hwmp_add_meshpreq(frm,
604                     (struct ieee80211_meshpreq_ie *)ie);
605                 break;
606         case IEEE80211_ELEMID_MESHPREP:
607                 frm = hwmp_add_meshprep(frm,
608                     (struct ieee80211_meshprep_ie *)ie);
609                 break;
610         case IEEE80211_ELEMID_MESHPERR:
611                 frm = hwmp_add_meshperr(frm,
612                     (struct ieee80211_meshperr_ie *)ie);
613                 break;
614         case IEEE80211_ELEMID_MESHRANN:
615                 frm = hwmp_add_meshrann(frm,
616                     (struct ieee80211_meshrann_ie *)ie);
617                 break;
618         }
619
620         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
621         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
622         if (m == NULL) {
623                 ieee80211_free_node(ni);
624                 vap->iv_stats.is_tx_nobuf++;
625                 return ENOMEM;
626         }
627         ieee80211_send_setup(ni, m,
628             IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
629             IEEE80211_NONQOS_TID, sa, da, sa);
630
631         m->m_flags |= M_ENCAP;          /* mark encapsulated */
632         IEEE80211_NODE_STAT(ni, tx_mgmt);
633
634         memset(&params, 0, sizeof(params));
635         params.ibp_pri = WME_AC_VO;
636         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
637         if (IEEE80211_IS_MULTICAST(da))
638                 params.ibp_try0 = 1;
639         else
640                 params.ibp_try0 = ni->ni_txparms->maxretry;
641         params.ibp_power = ni->ni_txpower;
642         return ic->ic_raw_xmit(ni, m, &params);
643 }
644
645 #define ADDSHORT(frm, v) do {           \
646         frm[0] = (v) & 0xff;            \
647         frm[1] = (v) >> 8;              \
648         frm += 2;                       \
649 } while (0)
650 #define ADDWORD(frm, v) do {            \
651         LE_WRITE_4(frm, v);             \
652         frm += 4;                       \
653 } while (0)
654 /*
655  * Add a Mesh Path Request IE to a frame.
656  */
657 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
658 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
659 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
660 static uint8_t *
661 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
662 {
663         int i;
664
665         *frm++ = IEEE80211_ELEMID_MESHPREQ;
666         *frm++ = preq->preq_len;        /* len already calculated */
667         *frm++ = preq->preq_flags;
668         *frm++ = preq->preq_hopcount;
669         *frm++ = preq->preq_ttl;
670         ADDWORD(frm, preq->preq_id);
671         IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
672         ADDWORD(frm, preq->preq_origseq);
673         if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
674                 IEEE80211_ADDR_COPY(frm, preq->preq_orig_ext_addr);
675                 frm += 6;
676         }
677         ADDWORD(frm, preq->preq_lifetime);
678         ADDWORD(frm, preq->preq_metric);
679         *frm++ = preq->preq_tcount;
680         for (i = 0; i < preq->preq_tcount; i++) {
681                 *frm++ = PREQ_TFLAGS(i);
682                 IEEE80211_ADDR_COPY(frm, PREQ_TADDR(i));
683                 frm += 6;
684                 ADDWORD(frm, PREQ_TSEQ(i));
685         }
686         return frm;
687 }
688 #undef  PREQ_TFLAGS
689 #undef  PREQ_TADDR
690 #undef  PREQ_TSEQ
691
692 /*
693  * Add a Mesh Path Reply IE to a frame.
694  */
695 static uint8_t *
696 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
697 {
698         *frm++ = IEEE80211_ELEMID_MESHPREP;
699         *frm++ = prep->prep_len;        /* len already calculated */
700         *frm++ = prep->prep_flags;
701         *frm++ = prep->prep_hopcount;
702         *frm++ = prep->prep_ttl;
703         IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
704         ADDWORD(frm, prep->prep_targetseq);
705         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
706                 IEEE80211_ADDR_COPY(frm, prep->prep_target_ext_addr);
707                 frm += 6;
708         }
709         ADDWORD(frm, prep->prep_lifetime);
710         ADDWORD(frm, prep->prep_metric);
711         IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
712         ADDWORD(frm, prep->prep_origseq);
713         return frm;
714 }
715
716 /*
717  * Add a Mesh Path Error IE to a frame.
718  */
719 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
720 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
721 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
722 #define PERR_EXTADDR(n) perr->perr_dests[n].dest_ext_addr
723 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
724 static uint8_t *
725 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
726 {
727         int i;
728
729         *frm++ = IEEE80211_ELEMID_MESHPERR;
730         *frm++ = perr->perr_len;        /* len already calculated */
731         *frm++ = perr->perr_ttl;
732         *frm++ = perr->perr_ndests;
733         for (i = 0; i < perr->perr_ndests; i++) {
734                 *frm++ = PERR_DFLAGS(i);
735                 IEEE80211_ADDR_COPY(frm, PERR_DADDR(i));
736                 frm += 6;
737                 ADDWORD(frm, PERR_DSEQ(i));
738                 if (PERR_DFLAGS(i) & IEEE80211_MESHPERR_FLAGS_AE) {
739                         IEEE80211_ADDR_COPY(frm, PERR_EXTADDR(i));
740                         frm += 6;
741                 }
742                 ADDSHORT(frm, PERR_DRCODE(i));
743         }
744         return frm;
745 }
746 #undef  PERR_DFLAGS
747 #undef  PERR_DADDR
748 #undef  PERR_DSEQ
749 #undef  PERR_EXTADDR
750 #undef  PERR_DRCODE
751
752 /*
753  * Add a Root Annoucement IE to a frame.
754  */
755 static uint8_t *
756 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
757 {
758         *frm++ = IEEE80211_ELEMID_MESHRANN;
759         *frm++ = rann->rann_len;
760         *frm++ = rann->rann_flags;
761         *frm++ = rann->rann_hopcount;
762         *frm++ = rann->rann_ttl;
763         IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
764         ADDWORD(frm, rann->rann_seq);
765         ADDWORD(frm, rann->rann_interval);
766         ADDWORD(frm, rann->rann_metric);
767         return frm;
768 }
769
770 static void
771 hwmp_rootmode_setup(struct ieee80211vap *vap)
772 {
773         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
774
775         switch (hs->hs_rootmode) {
776         case IEEE80211_HWMP_ROOTMODE_DISABLED:
777                 callout_drain(&hs->hs_roottimer);
778                 break;
779         case IEEE80211_HWMP_ROOTMODE_NORMAL:
780         case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
781                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
782                     hwmp_rootmode_cb, vap);
783                 break;
784         case IEEE80211_HWMP_ROOTMODE_RANN:
785                 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
786                     hwmp_rootmode_rann_cb, vap);
787                 break;
788         }
789 }
790
791 /*
792  * Send a broadcast Path Request to find all nodes on the mesh. We are
793  * called when the vap is configured as a HWMP root node.
794  */
795 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
796 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
797 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
798 static void
799 hwmp_rootmode_cb(void *arg)
800 {
801         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
802         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
803         struct ieee80211_mesh_state *ms = vap->iv_mesh;
804         struct ieee80211_meshpreq_ie preq;
805
806         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
807             "%s", "send broadcast PREQ");
808
809         preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
810         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
811                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
812         if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
813                 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
814         preq.preq_hopcount = 0;
815         preq.preq_ttl = ms->ms_ttl;
816         preq.preq_id = ++hs->hs_preqid;
817         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
818         preq.preq_origseq = ++hs->hs_seq;
819         preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout);
820         preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
821         preq.preq_tcount = 1;
822         IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
823         PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
824             IEEE80211_MESHPREQ_TFLAGS_RF;
825         PREQ_TSEQ(0) = 0;
826         vap->iv_stats.is_hwmp_rootreqs++;
827         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
828         hwmp_rootmode_setup(vap);
829 }
830 #undef  PREQ_TFLAGS
831 #undef  PREQ_TADDR
832 #undef  PREQ_TSEQ
833
834 /*
835  * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are
836  * called when the vap is configured as a HWMP RANN root node.
837  */
838 static void
839 hwmp_rootmode_rann_cb(void *arg)
840 {
841         struct ieee80211vap *vap = (struct ieee80211vap *)arg;
842         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
843         struct ieee80211_mesh_state *ms = vap->iv_mesh;
844         struct ieee80211_meshrann_ie rann;
845
846         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
847             "%s", "send broadcast RANN");
848
849         rann.rann_flags = 0;
850         if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
851                 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
852         rann.rann_hopcount = 0;
853         rann.rann_ttl = ms->ms_ttl;
854         IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
855         rann.rann_seq = ++hs->hs_seq;
856         rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
857
858         vap->iv_stats.is_hwmp_rootrann++;
859         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
860         hwmp_rootmode_setup(vap);
861 }
862
863 #define PREQ_TFLAGS(n)  preq->preq_targets[n].target_flags
864 #define PREQ_TADDR(n)   preq->preq_targets[n].target_addr
865 #define PREQ_TSEQ(n)    preq->preq_targets[n].target_seq
866 static void
867 hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
868     const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
869 {
870         struct ieee80211_mesh_state *ms = vap->iv_mesh;
871         struct ieee80211_mesh_route *rt = NULL; /* pro-active code */
872         struct ieee80211_mesh_route *rtorig = NULL;
873         struct ieee80211_mesh_route *rttarg = NULL;
874         struct ieee80211_hwmp_route *hrorig = NULL;
875         struct ieee80211_hwmp_route *hrtarg = NULL;
876         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
877         struct ieee80211_meshprep_ie prep;
878
879         if (ni == vap->iv_bss ||
880             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
881                 return;
882         /*
883          * Ignore PREQs from us. Could happen because someone forward it
884          * back to us.
885          */
886         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr))
887                 return;
888
889         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
890             "received PREQ, orig %6D, targ(0) %6D", preq->preq_origaddr, ":",
891             PREQ_TADDR(0), ":");
892
893         /*
894          * Acceptance criteria: if the PREQ is not for us or not broadcast
895          * AND forwarding is disabled, discard this PREQ.
896          * XXX: need to check PROXY
897          */
898         if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
899             !IEEE80211_IS_MULTICAST(PREQ_TADDR(0))) &&
900             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
901                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
902                     preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
903                 return;
904         }
905         /*
906          * Acceptance criteria: if unicast addressed 
907          * AND no valid forwarding for Target of PREQ, discard this PREQ.
908          */
909         rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
910         if(rttarg != NULL)
911                 hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg,
912                     struct ieee80211_hwmp_route);
913         /* Address mode: ucast */
914         if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 &&
915             rttarg == NULL &&
916             !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
917                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
918                     preq->preq_origaddr, NULL,
919                     "unicast addressed PREQ of unknown target %6D",
920                     PREQ_TADDR(0), ":");
921                 return;
922         }
923
924         /* PREQ ACCEPTED */
925
926         rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
927         if (rtorig == NULL) {
928                 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
929                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
930                     "adding originator %6D", preq->preq_origaddr, ":");
931         }
932         if (rtorig == NULL) {
933                 /* XXX stat */
934                 return;
935         }
936         hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
937
938         /* Data creation and update of forwarding information
939          * according to Table 11C-8 for originator mesh STA.
940          */
941         if (HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) ||
942             (HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) &&
943             preq->preq_metric < rtorig->rt_metric)) {
944                 hrorig->hr_seq = preq->preq_origseq;
945                 IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2);
946                 rtorig->rt_metric = preq->preq_metric +
947                         ms->ms_pmetric->mpm_metric(ni);
948                 rtorig->rt_nhops  = preq->preq_hopcount + 1;
949                 ieee80211_mesh_rt_update(rtorig, preq->preq_lifetime);
950                 /* path to orig is valid now */
951                 rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
952         }else if(hrtarg != NULL &&
953                 HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0)) &&
954                 (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
955                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
956                     "discard PREQ from %6D, old seq no %u <= %u",
957                     preq->preq_origaddr, ":",
958                     preq->preq_origseq, hrorig->hr_seq);
959                 return;
960         }
961
962         /*
963          * Forwarding information for transmitter mesh STA
964          * [OPTIONAL: if metric improved]
965          */
966
967         /*
968          * Check if the PREQ is addressed to us.
969          * or a Proxy currently supplied by us.
970          */
971         if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
972             (rttarg != NULL &&
973             rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
974             rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
975                 /*
976                  * When we are the target we shall update our own HWMP seq
977                  * number with max of (current and preq->seq) + 1
978                  */
979                 hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1;
980
981                 prep.prep_flags = 0;
982                 if (rttarg != NULL && /* if NULL it means we are the target */
983                     rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
984                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
985                             "reply for proxy %6D", rttarg->rt_dest, ":");
986                         prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE;
987                         IEEE80211_ADDR_COPY(prep.prep_target_ext_addr,
988                             rttarg->rt_dest);
989                         /* update proxy seqno to HWMP seqno */
990                         rttarg->rt_ext_seq = hs->hs_seq;
991                 }
992                 /*
993                  * Build and send a PREP frame.
994                  */
995                 prep.prep_hopcount = 0;
996                 prep.prep_ttl = ms->ms_ttl;
997                 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
998                 prep.prep_targetseq = hs->hs_seq;
999                 prep.prep_lifetime = preq->preq_lifetime;
1000                 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1001                 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
1002                 prep.prep_origseq = preq->preq_origseq;
1003
1004                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1005                     "reply to %6D", preq->preq_origaddr, ":");
1006                 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
1007                 return;
1008         }
1009         /*
1010          * Proactive PREQ: reply with a proactive PREP to the
1011          * root STA if requested.
1012          */
1013         if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
1014             (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
1015                 uint8_t rootmac[IEEE80211_ADDR_LEN];
1016
1017                 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
1018                 rt = ieee80211_mesh_rt_find(vap, rootmac);
1019                 if (rt == NULL) {
1020                         rt = ieee80211_mesh_rt_add(vap, rootmac);
1021                         if (rt == NULL) {
1022                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1023                                     "unable to add root mesh path to %6D",
1024                                     rootmac, ":");
1025                                 vap->iv_stats.is_mesh_rtaddfailed++;
1026                                 return;
1027                         }
1028                 }
1029                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1030                     "root mesh station @ %6D", rootmac, ":");
1031
1032                 /*
1033                  * Reply with a PREP if we don't have a path to the root
1034                  * or if the root sent us a proactive PREQ.
1035                  */
1036                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
1037                     (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
1038                         prep.prep_flags = 0;
1039                         prep.prep_hopcount = 0;
1040                         prep.prep_ttl = ms->ms_ttl;
1041                         IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
1042                         prep.prep_origseq = preq->preq_origseq;
1043                         prep.prep_lifetime = preq->preq_lifetime;
1044                         prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1045                         IEEE80211_ADDR_COPY(prep.prep_targetaddr,
1046                             vap->iv_myaddr);
1047                         prep.prep_targetseq = ++hs->hs_seq;
1048                         hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
1049                             broadcastaddr, &prep);
1050                 }
1051                 hwmp_discover(vap, rootmac, NULL);
1052                 return;
1053         }
1054         rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
1055
1056         /*
1057          * Forwarding and Intermediate reply for PREQs with 1 target.
1058          */
1059         if (preq->preq_tcount == 1) {
1060                 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
1061
1062                 memcpy(&ppreq, preq, sizeof(ppreq));
1063                 /*
1064                  * We have a valid route to this node.
1065                  */
1066                 if (rt != NULL &&
1067                     (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
1068                         if (preq->preq_ttl > 1 &&
1069                             preq->preq_hopcount < hs->hs_maxhops) {
1070                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1071                                     "forward PREQ from %6D",
1072                                     preq->preq_origaddr, ":");
1073                                 /*
1074                                  * Propagate the original PREQ.
1075                                  * PREQ is unicast now to rt->rt_nexthop
1076                                  */
1077                                 ppreq.preq_flags &=
1078                                     ~IEEE80211_MESHPREQ_FLAGS_AM;
1079                                 ppreq.preq_hopcount += 1;
1080                                 ppreq.preq_ttl -= 1;
1081                                 ppreq.preq_metric +=
1082                                     ms->ms_pmetric->mpm_metric(ni);
1083                                 /*
1084                                  * Set TO and unset RF bits because we are
1085                                  * going to send a PREP next.
1086                                  */
1087                                 ppreq.preq_targets[0].target_flags |=
1088                                     IEEE80211_MESHPREQ_TFLAGS_TO;
1089                                 ppreq.preq_targets[0].target_flags &=
1090                                     ~IEEE80211_MESHPREQ_TFLAGS_RF;
1091                                 hwmp_send_preq(ni, vap->iv_myaddr,
1092                                     rt->rt_nexthop, &ppreq);
1093                         }
1094                         /*
1095                          * Check if we can send an intermediate Path Reply,
1096                          * i.e., Target Only bit is not set.
1097                          */
1098                         if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO) &&
1099                             HWMP_SEQ_GEQ(hrtarg->hr_seq, PREQ_TSEQ(0))) {
1100                                 struct ieee80211_meshprep_ie prep;
1101
1102                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1103                                     "intermediate reply for PREQ from %6D",
1104                                     preq->preq_origaddr, ":");
1105                                 prep.prep_flags = 0;
1106                                 prep.prep_hopcount = rttarg->rt_nhops;
1107                                 prep.prep_ttl = ms->ms_ttl;
1108                                 IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
1109                                     PREQ_TADDR(0));
1110                                 prep.prep_targetseq = hrtarg->hr_seq;
1111                                 prep.prep_lifetime = preq->preq_lifetime;
1112                                 prep.prep_metric =rttarg->rt_metric;
1113                                 IEEE80211_ADDR_COPY(&prep.prep_origaddr,
1114                                     preq->preq_origaddr);
1115                                 prep.prep_origseq = hrorig->hr_seq;
1116                                 hwmp_send_prep(ni, vap->iv_myaddr,
1117                                     rtorig->rt_nexthop, &prep);
1118                         }
1119                 /*
1120                  * We have no information about this path,
1121                  * propagate the PREQ.
1122                  */
1123                 } else if (preq->preq_ttl > 1 &&
1124                     preq->preq_hopcount < hs->hs_maxhops) {
1125                         if (rt == NULL) {
1126                                 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
1127                                 if (rt == NULL) {
1128                                         IEEE80211_NOTE(vap,
1129                                             IEEE80211_MSG_HWMP, ni,
1130                                             "unable to add PREQ path to %6D",
1131                                             PREQ_TADDR(0), ":");
1132                                         vap->iv_stats.is_mesh_rtaddfailed++;
1133                                         return;
1134                                 }
1135                         }
1136                         rt->rt_metric = preq->preq_metric;
1137                         ieee80211_mesh_rt_update(rt, preq->preq_lifetime);
1138                         hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
1139                             struct ieee80211_hwmp_route);
1140                         hrorig->hr_seq = preq->preq_origseq;
1141                         hrorig->hr_preqid = preq->preq_id;
1142
1143                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1144                             "forward PREQ from %6D",
1145                             preq->preq_origaddr, ":");
1146                         ppreq.preq_hopcount += 1;
1147                         ppreq.preq_ttl -= 1;
1148                         ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
1149                         hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
1150                             &ppreq);
1151                 }
1152         }
1153 }
1154 #undef  PREQ_TFLAGS
1155 #undef  PREQ_TADDR
1156 #undef  PREQ_TSEQ
1157
1158 static int
1159 hwmp_send_preq(struct ieee80211_node *ni,
1160     const uint8_t sa[IEEE80211_ADDR_LEN],
1161     const uint8_t da[IEEE80211_ADDR_LEN],
1162     struct ieee80211_meshpreq_ie *preq)
1163 {
1164         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1165
1166         /*
1167          * Enforce PREQ interval.
1168          */
1169         if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
1170                 return EALREADY;
1171         getmicrouptime(&hs->hs_lastpreq);
1172
1173         /*
1174          * mesh preq action frame format
1175          *     [6] da
1176          *     [6] sa
1177          *     [6] addr3 = sa
1178          *     [1] action
1179          *     [1] category
1180          *     [tlv] mesh path request
1181          */
1182         preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
1183         preq->preq_len = (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE ?
1184             IEEE80211_MESHPREQ_BASE_SZ_AE : IEEE80211_MESHPREQ_BASE_SZ) +
1185             preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ;
1186         return hwmp_send_action(ni, sa, da, (uint8_t *)preq, preq->preq_len+2);
1187 }
1188
1189 static void
1190 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
1191     const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
1192 {
1193 #define IS_PROXY(rt)    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)
1194 #define PROXIED_BY_US(rt)               \
1195     (IEEE80211_ADDR_EQ(vap->iv_myaddr, rt->rt_mesh_gate))
1196         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1197         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1198         struct ieee80211_mesh_route *rt = NULL;
1199         struct ieee80211_mesh_route *rtorig = NULL;
1200         struct ieee80211_mesh_route *rtext = NULL;
1201         struct ieee80211_hwmp_route *hr;
1202         struct ieee80211com *ic = vap->iv_ic;
1203         struct ifnet *ifp = vap->iv_ifp;
1204         struct mbuf *m, *next;
1205         uint32_t metric = 0;
1206         const uint8_t *addr;
1207
1208         if (ni == vap->iv_bss ||
1209             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
1210                 return;
1211
1212         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1213             "received PREP, orig %6D, targ %6D", prep->prep_origaddr, ":",
1214             prep->prep_targetaddr, ":");
1215
1216         /*
1217          * Acceptance criteria: (If the corresponding PREP was not generated
1218          * by us OR not generated by an external mac that is not proxied by us)
1219          * AND forwarding is disabled, discard this PREP.
1220          */
1221         rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
1222         if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) ||
1223             (rtorig != NULL && IS_PROXY(rtorig) && !PROXIED_BY_US(rtorig))) &&
1224             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)){
1225                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1226                     "discard PREP, orig(%6D) not proxied or generated by us",
1227                     prep->prep_origaddr, ":");
1228                 return;
1229         }
1230
1231         /* PREP ACCEPTED */
1232
1233         /*
1234          * If accepted shall create or update the active forwarding information
1235          * it maintains for the target mesh STA of the PREP (according to the
1236          * rules defined in 13.10.8.4). If the conditions for creating or
1237          * updating the forwarding information have not been met in those
1238          * rules, no further steps are applied to the PREP.
1239          * [OPTIONAL]: update forwarding information to TA if metric improves.
1240          */
1241         rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
1242         if (rt == NULL) {
1243                 rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
1244                 if (rt == NULL) {
1245                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1246                             "unable to add PREP path to %6D",
1247                             prep->prep_targetaddr, ":");
1248                         vap->iv_stats.is_mesh_rtaddfailed++;
1249                         return;
1250                 }
1251                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1252                     "adding target %6D", prep->prep_targetaddr, ":");
1253         }
1254         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1255         /* update path metric */
1256         metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
1257         if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
1258                 if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
1259                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1260                             "discard PREP from %6D, old seq no %u < %u",
1261                             prep->prep_targetaddr, ":",
1262                             prep->prep_targetseq, hr->hr_seq);
1263                         return;
1264                 } else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) &&
1265                     metric > rt->rt_metric) {
1266                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1267                             "discard PREP from %6D, new metric %u > %u",
1268                             prep->prep_targetaddr, ":",
1269                             prep->prep_metric, rt->rt_metric);
1270                         return;
1271                 }
1272         }
1273
1274         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1275             "%s path to %6D, hopcount %d:%d metric %d:%d",
1276             rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1277             "prefer" : "update",
1278             prep->prep_targetaddr, ":",
1279             rt->rt_nhops, prep->prep_hopcount,
1280             rt->rt_metric, metric);
1281
1282         hr->hr_seq = prep->prep_targetseq;
1283         IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr);
1284         rt->rt_metric = metric;
1285         rt->rt_nhops = prep->prep_hopcount + 1;
1286         ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
1287         rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */
1288
1289         /*
1290          * If it's NOT for us, propagate the PREP
1291          */
1292         if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
1293             prep->prep_ttl > 1 &&
1294             prep->prep_hopcount < hs->hs_maxhops) {
1295                 struct ieee80211_meshprep_ie pprep; /* propagated PREP */
1296                 /*
1297                  * NB: We should already have setup the path to orig
1298                  * mesh STA when we propagated PREQ to target mesh STA,
1299                  * no PREP is generated without a corresponding PREQ.
1300                  * XXX: for now just ignore.
1301                  */
1302                 if (rtorig == NULL) {
1303                         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1304                             "received PREP for an unknown orig(%6D)",
1305                             prep->prep_origaddr, ":");
1306                         return;
1307                 }
1308
1309                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1310                     "propagate PREP from %6D",
1311                     prep->prep_targetaddr, ":");
1312
1313                 memcpy(&pprep, prep, sizeof(pprep));
1314                 pprep.prep_hopcount += 1;
1315                 pprep.prep_ttl -= 1;
1316                 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
1317                 hwmp_send_prep(ni, vap->iv_myaddr, rtorig->rt_nexthop, &pprep);
1318
1319                 /* precursor list for the Target Mesh STA Address is updated */
1320         }
1321
1322         /*
1323          * Check if we received a PREP w/ AE and store target external address.
1324          * We may store target external address if recevied PREP w/ AE
1325          * and we are not final destination
1326          */
1327         if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
1328                 rtext = ieee80211_mesh_rt_find(vap,
1329                         prep->prep_target_ext_addr);
1330                 if (rtext == NULL) {
1331                         rtext = ieee80211_mesh_rt_add(vap,
1332                                 prep->prep_target_ext_addr);
1333                         if (rtext == NULL) {
1334                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1335                                     "unable to add PREP path to proxy %6D",
1336                                     prep->prep_targetaddr, ":");
1337                                 vap->iv_stats.is_mesh_rtaddfailed++;
1338                                 return;
1339                         }
1340                 }
1341                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1342                     "%s path to %6D, hopcount %d:%d metric %d:%d",
1343                     rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
1344                     "prefer" : "update",
1345                     prep->prep_target_ext_addr, ":",
1346                     rtext->rt_nhops, prep->prep_hopcount,
1347                     rtext->rt_metric, metric);
1348
1349                 rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
1350                         IEEE80211_MESHRT_FLAGS_VALID;
1351                 IEEE80211_ADDR_COPY(rtext->rt_dest,
1352                     prep->prep_target_ext_addr);
1353                 IEEE80211_ADDR_COPY(rtext->rt_mesh_gate,
1354                     prep->prep_targetaddr);
1355                 IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2);
1356                 rtext->rt_metric = metric;
1357                 rtext->rt_lifetime = prep->prep_lifetime;
1358                 rtext->rt_nhops = prep->prep_hopcount + 1;
1359                 rtext->rt_ext_seq = prep->prep_origseq; /* new proxy seq */
1360                 /*
1361                  * XXX: proxy entries have no HWMP priv data,
1362                  * nullify them to be sure?
1363                  */
1364         }
1365         /*
1366          * Check for frames queued awaiting path discovery.
1367          * XXX probably can tell exactly and avoid remove call
1368          * NB: hash may have false matches, if so they will get
1369          *     stuck back on the stageq because there won't be
1370          *     a path.
1371          */
1372         addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
1373             prep->prep_target_ext_addr : prep->prep_targetaddr;
1374         m = ieee80211_ageq_remove(&ic->ic_stageq,
1375             (struct ieee80211_node *)(uintptr_t)
1376             ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */
1377         for (; m != NULL; m = next) {
1378                 next = m->m_nextpkt;
1379                 m->m_nextpkt = NULL;
1380                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1381                     "flush queued frame %p len %d", m, m->m_pkthdr.len);
1382                 ifp->if_transmit(ifp, m);
1383         }
1384 #undef  IS_PROXY
1385 #undef  PROXIED_BY_US
1386 }
1387
1388 static int
1389 hwmp_send_prep(struct ieee80211_node *ni,
1390     const uint8_t sa[IEEE80211_ADDR_LEN],
1391     const uint8_t da[IEEE80211_ADDR_LEN],
1392     struct ieee80211_meshprep_ie *prep)
1393 {
1394         /* NB: there's no PREP minimum interval. */
1395
1396         /*
1397          * mesh prep action frame format
1398          *     [6] da
1399          *     [6] sa
1400          *     [6] addr3 = sa
1401          *     [1] action
1402          *     [1] category
1403          *     [tlv] mesh path reply
1404          */
1405         prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
1406         prep->prep_len = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
1407             IEEE80211_MESHPREP_BASE_SZ_AE : IEEE80211_MESHPREP_BASE_SZ;
1408         return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
1409             prep->prep_len + 2);
1410 }
1411
1412 #define PERR_DFLAGS(n)  perr.perr_dests[n].dest_flags
1413 #define PERR_DADDR(n)   perr.perr_dests[n].dest_addr
1414 #define PERR_DSEQ(n)    perr.perr_dests[n].dest_seq
1415 #define PERR_DRCODE(n)  perr.perr_dests[n].dest_rcode
1416 static void
1417 hwmp_peerdown(struct ieee80211_node *ni)
1418 {
1419         struct ieee80211vap *vap = ni->ni_vap;
1420         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1421         struct ieee80211_meshperr_ie perr;
1422         struct ieee80211_mesh_route *rt;
1423         struct ieee80211_hwmp_route *hr;
1424
1425         rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
1426         if (rt == NULL)
1427                 return;
1428         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1429         IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1430             "%s", "delete route entry");
1431         perr.perr_ttl = ms->ms_ttl;
1432         perr.perr_ndests = 1;
1433         PERR_DFLAGS(0) = 0;
1434         if (hr->hr_seq == 0)
1435                 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
1436         PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
1437         IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
1438         PERR_DSEQ(0) = hr->hr_seq;
1439         PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
1440         /* NB: flush everything passing through peer */
1441         ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
1442         hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
1443 }
1444 #undef  PERR_DFLAGS
1445 #undef  PERR_DADDR
1446 #undef  PERR_DSEQ
1447 #undef  PERR_DRCODE
1448
1449 #define PERR_DFLAGS(n)  perr->perr_dests[n].dest_flags
1450 #define PERR_DADDR(n)   perr->perr_dests[n].dest_addr
1451 #define PERR_DSEQ(n)    perr->perr_dests[n].dest_seq
1452 #define PERR_DRCODE(n)  perr->perr_dests[n].dest_rcode
1453 static void
1454 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
1455     const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
1456 {
1457         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1458         struct ieee80211_mesh_route *rt = NULL;
1459         struct ieee80211_hwmp_route *hr;
1460         struct ieee80211_meshperr_ie pperr;
1461         int i, forward = 0;
1462
1463         /*
1464          * Acceptance criteria: check if we received a PERR from a
1465          * neighbor and forwarding is enabled.
1466          */
1467         if (ni == vap->iv_bss ||
1468             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1469             !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
1470                 return;
1471         /*
1472          * Find all routing entries that match and delete them.
1473          */
1474         for (i = 0; i < perr->perr_ndests; i++) {
1475                 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
1476                 if (rt == NULL)
1477                         continue;
1478                 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1479                 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) &&
1480                     HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
1481                         ieee80211_mesh_rt_del(vap, rt->rt_dest);
1482                         ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
1483                         rt = NULL;
1484                         forward = 1;
1485                 }
1486         }
1487         /*
1488          * Propagate the PERR if we previously found it on our routing table.
1489          * XXX handle ndest > 1
1490          */
1491         if (forward && perr->perr_ttl > 1) {
1492                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
1493                     "propagate PERR from %6D", wh->i_addr2, ":");
1494                 memcpy(&pperr, perr, sizeof(*perr));
1495                 pperr.perr_ttl--;
1496                 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
1497                     &pperr);
1498         }
1499 }
1500 #undef  PERR_DFLAGS
1501 #undef  PEER_DADDR
1502 #undef  PERR_DSEQ
1503 #undef  PERR_DRCODE
1504
1505 static int
1506 hwmp_send_perr(struct ieee80211_node *ni,
1507     const uint8_t sa[IEEE80211_ADDR_LEN],
1508     const uint8_t da[IEEE80211_ADDR_LEN],
1509     struct ieee80211_meshperr_ie *perr)
1510 {
1511         struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
1512         int i;
1513         uint8_t length = 0;
1514
1515         /*
1516          * Enforce PERR interval.
1517          */
1518         if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0)
1519                 return EALREADY;
1520         getmicrouptime(&hs->hs_lastperr);
1521
1522         /*
1523          * mesh perr action frame format
1524          *     [6] da
1525          *     [6] sa
1526          *     [6] addr3 = sa
1527          *     [1] action
1528          *     [1] category
1529          *     [tlv] mesh path error
1530          */
1531         perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
1532         length = IEEE80211_MESHPERR_BASE_SZ;
1533         for (i = 0; i<perr->perr_ndests; i++) {
1534                 if (perr->perr_dests[i].dest_flags &
1535                     IEEE80211_MESHPERR_FLAGS_AE) {
1536                         length += IEEE80211_MESHPERR_DEST_SZ_AE;
1537                         continue ;
1538                 }
1539                 length += IEEE80211_MESHPERR_DEST_SZ;
1540         }
1541         perr->perr_len =length;
1542         return hwmp_send_action(ni, sa, da, (uint8_t *)perr, perr->perr_len+2);
1543 }
1544
1545 static void
1546 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
1547     const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
1548 {
1549         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1550         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1551         struct ieee80211_mesh_route *rt = NULL;
1552         struct ieee80211_hwmp_route *hr;
1553         struct ieee80211_meshrann_ie prann;
1554
1555         if (ni == vap->iv_bss ||
1556             ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
1557             IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
1558                 return;
1559
1560         rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
1561         /*
1562          * Discover the path to the root mesh STA.
1563          * If we already know it, propagate the RANN element.
1564          */
1565         if (rt == NULL) {
1566                 hwmp_discover(vap, rann->rann_addr, NULL);
1567                 return;
1568         }
1569         hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
1570         if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
1571                 hr->hr_seq = rann->rann_seq;
1572                 if (rann->rann_ttl > 1 &&
1573                     rann->rann_hopcount < hs->hs_maxhops &&
1574                     (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
1575                         memcpy(&prann, rann, sizeof(prann));
1576                         prann.rann_hopcount += 1;
1577                         prann.rann_ttl -= 1;
1578                         prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
1579                         hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
1580                             broadcastaddr, &prann);
1581                 }
1582         }
1583 }
1584
1585 static int
1586 hwmp_send_rann(struct ieee80211_node *ni,
1587     const uint8_t sa[IEEE80211_ADDR_LEN],
1588     const uint8_t da[IEEE80211_ADDR_LEN],
1589     struct ieee80211_meshrann_ie *rann)
1590 {
1591         /*
1592          * mesh rann action frame format
1593          *     [6] da
1594          *     [6] sa
1595          *     [6] addr3 = sa
1596          *     [1] action
1597          *     [1] category
1598          *     [tlv] root annoucement
1599          */
1600         rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
1601         rann->rann_len = IEEE80211_MESHRANN_BASE_SZ;
1602         return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
1603             rann->rann_len + 2);
1604 }
1605
1606 #define PREQ_TFLAGS(n)  preq.preq_targets[n].target_flags
1607 #define PREQ_TADDR(n)   preq.preq_targets[n].target_addr
1608 #define PREQ_TSEQ(n)    preq.preq_targets[n].target_seq
1609 static struct ieee80211_node *
1610 hwmp_discover(struct ieee80211vap *vap,
1611     const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
1612 {
1613         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1614         struct ieee80211_mesh_state *ms = vap->iv_mesh;
1615         struct ieee80211_mesh_route *rt = NULL;
1616         struct ieee80211_hwmp_route *hr;
1617         struct ieee80211_meshpreq_ie preq;
1618         struct ieee80211_node *ni;
1619         int sendpreq = 0;
1620
1621         KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
1622             ("not a mesh vap, opmode %d", vap->iv_opmode));
1623
1624         KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
1625             ("%s: discovering self!", __func__));
1626
1627         ni = NULL;
1628         if (!IEEE80211_IS_MULTICAST(dest)) {
1629                 rt = ieee80211_mesh_rt_find(vap, dest);
1630                 if (rt == NULL) {
1631                         rt = ieee80211_mesh_rt_add(vap, dest);
1632                         if (rt == NULL) {
1633                                 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
1634                                     ni, "unable to add discovery path to %6D",
1635                                     dest, ":");
1636                                 vap->iv_stats.is_mesh_rtaddfailed++;
1637                                 goto done;
1638                         }
1639                 }
1640                 hr = IEEE80211_MESH_ROUTE_PRIV(rt,
1641                     struct ieee80211_hwmp_route);
1642                 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
1643                         if (hr->hr_origseq == 0)
1644                                 hr->hr_origseq = ++hs->hs_seq;
1645                         rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
1646                         /* XXX: special discovery timeout, larger lifetime? */
1647                         ieee80211_mesh_rt_update(rt,
1648                             ticks_to_msecs(ieee80211_hwmp_pathtimeout));
1649                         /* XXX check preq retries */
1650                         sendpreq = 1;
1651                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1652                             "start path discovery (src %s), target seq %u",
1653                             m == NULL ? "<none>" : ether_sprintf(
1654                             mtod(m, struct ether_header *)->ether_shost),
1655                             hr->hr_seq);
1656                         /*
1657                          * Try to discover the path for this node.
1658                          * Group addressed PREQ Case A
1659                          */
1660                         preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
1661                         preq.preq_hopcount = 0;
1662                         preq.preq_ttl = ms->ms_ttl;
1663                         preq.preq_id = ++hs->hs_preqid;
1664                         IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
1665                         preq.preq_origseq = hr->hr_origseq;
1666                         preq.preq_lifetime =
1667                             ticks_to_msecs(ieee80211_hwmp_pathtimeout);
1668                         preq.preq_metric = rt->rt_metric;
1669                         preq.preq_tcount = 1;
1670                         IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
1671                         PREQ_TFLAGS(0) = 0;
1672                         if (ieee80211_hwmp_targetonly)
1673                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
1674                         if (ieee80211_hwmp_replyforward)
1675                                 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
1676                         PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
1677                         PREQ_TSEQ(0) = hr->hr_seq;
1678                         /* XXX check return value */
1679                         hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
1680                             broadcastaddr, &preq);
1681                 }
1682                 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
1683                         ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
1684         } else {
1685                 ni = ieee80211_find_txnode(vap, dest);
1686                 /* NB: if null then we leak mbuf */
1687                 KASSERT(ni != NULL, ("leak mcast frame"));
1688                 return ni;
1689         }
1690 done:
1691         if (ni == NULL && m != NULL) {
1692                 if (sendpreq) {
1693                         struct ieee80211com *ic = vap->iv_ic;
1694                         /*
1695                          * Queue packet for transmit when path discovery
1696                          * completes.  If discovery never completes the
1697                          * frame will be flushed by way of the aging timer.
1698                          */
1699                         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
1700                             "%s", "queue frame until path found");
1701                         m->m_pkthdr.rcvif = (void *)(uintptr_t)
1702                             ieee80211_mac_hash(ic, dest);
1703                         /* XXX age chosen randomly */
1704                         ieee80211_ageq_append(&ic->ic_stageq, m,
1705                             IEEE80211_INACT_WAIT);
1706                 } else {
1707                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
1708                             dest, NULL, "%s", "no valid path to this node");
1709                         m_freem(m);
1710                 }
1711         }
1712         return ni;
1713 }
1714 #undef  PREQ_TFLAGS
1715 #undef  PREQ_TADDR
1716 #undef  PREQ_TSEQ
1717
1718 static int
1719 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1720 {
1721         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1722         int error;
1723
1724         if (vap->iv_opmode != IEEE80211_M_MBSS)
1725                 return ENOSYS;
1726         error = 0;
1727         switch (ireq->i_type) {
1728         case IEEE80211_IOC_HWMP_ROOTMODE:
1729                 ireq->i_val = hs->hs_rootmode;
1730                 break;
1731         case IEEE80211_IOC_HWMP_MAXHOPS:
1732                 ireq->i_val = hs->hs_maxhops;
1733                 break;
1734         default:
1735                 return ENOSYS;
1736         }
1737         return error;
1738 }
1739 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211);
1740
1741 static int
1742 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
1743 {
1744         struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
1745         int error;
1746
1747         if (vap->iv_opmode != IEEE80211_M_MBSS)
1748                 return ENOSYS;
1749         error = 0;
1750         switch (ireq->i_type) {
1751         case IEEE80211_IOC_HWMP_ROOTMODE:
1752                 if (ireq->i_val < 0 || ireq->i_val > 3)
1753                         return EINVAL;
1754                 hs->hs_rootmode = ireq->i_val;
1755                 hwmp_rootmode_setup(vap);
1756                 break;
1757         case IEEE80211_IOC_HWMP_MAXHOPS:
1758                 if (ireq->i_val <= 0 || ireq->i_val > 255)
1759                         return EINVAL;
1760                 hs->hs_maxhops = ireq->i_val;
1761                 break;
1762         default:
1763                 return ENOSYS;
1764         }
1765         return error;
1766 }
1767 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211);