Update 802.11s mesh support to draft 3.03. This includes a revised frame
format for peering and changes to the PERR frames. Note that this is incompatible with the previous code. Reviewed by: sam MFC after: 1 week
This commit is contained in:
parent
4d7a22b3ee
commit
f41eff35af
@ -708,7 +708,7 @@ enum {
|
||||
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
|
||||
|
||||
/*
|
||||
* 802.11s IEs based on D3.0 spec and were not assigned by
|
||||
* 802.11s IEs based on D3.03 spec and were not assigned by
|
||||
* ANA. Beware changing them because some of them are being
|
||||
* kept compatible with Linux.
|
||||
*/
|
||||
@ -726,10 +726,9 @@ enum {
|
||||
IEEE80211_ELEMID_MESHPREQ = 68,
|
||||
IEEE80211_ELEMID_MESHPREP = 69,
|
||||
IEEE80211_ELEMID_MESHPERR = 70,
|
||||
IEEE80211_ELEMID_MESHPU = 53,
|
||||
IEEE80211_ELEMID_MESHPUC = 54,
|
||||
IEEE80211_ELEMID_MESHPXU = 53,
|
||||
IEEE80211_ELEMID_MESHPXUC = 54,
|
||||
IEEE80211_ELEMID_MESHAH = 60, /* Abbreviated Handshake */
|
||||
IEEE80211_ELEMID_MESHPEERVER = 80, /* Peering Protocol Version */
|
||||
};
|
||||
|
||||
struct ieee80211_tim_ie {
|
||||
@ -925,6 +924,9 @@ enum {
|
||||
IEEE80211_REASON_MESH_INVALID_GTK = 8, /* 11s */
|
||||
IEEE80211_REASON_MESH_INCONS_PARAMS = 9, /* 11s */
|
||||
IEEE80211_REASON_MESH_INVALID_SECURITY = 10, /* 11s */
|
||||
IEEE80211_REASON_MESH_PERR_UNSPEC = 11, /* 11s */
|
||||
IEEE80211_REASON_MESH_PERR_NO_FI = 12, /* 11s */
|
||||
IEEE80211_REASON_MESH_PERR_DEST_UNREACH = 13, /* 11s */
|
||||
|
||||
IEEE80211_STATUS_SUCCESS = 0,
|
||||
IEEE80211_STATUS_UNSPECIFIED = 1,
|
||||
|
@ -188,10 +188,7 @@ SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
|
||||
|
||||
#define IEEE80211_HWMP_DEFAULT_MAXHOPS 31
|
||||
|
||||
static ieee80211_recv_action_func hwmp_recv_action_meshpath_preq;
|
||||
static ieee80211_recv_action_func hwmp_recv_action_meshpath_prep;
|
||||
static ieee80211_recv_action_func hwmp_recv_action_meshpath_perr;
|
||||
static ieee80211_recv_action_func hwmp_recv_action_meshpath_rann;
|
||||
static ieee80211_recv_action_func hwmp_recv_action_meshpath;
|
||||
|
||||
static struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
|
||||
.mpp_descr = "HWMP",
|
||||
@ -217,16 +214,10 @@ ieee80211_hwmp_init(void)
|
||||
ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
|
||||
|
||||
/*
|
||||
* Register action frame handlers.
|
||||
* Register action frame handler.
|
||||
*/
|
||||
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
|
||||
IEEE80211_ACTION_MESHPATH_REQ, hwmp_recv_action_meshpath_preq);
|
||||
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
|
||||
IEEE80211_ACTION_MESHPATH_REP, hwmp_recv_action_meshpath_prep);
|
||||
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
|
||||
IEEE80211_ACTION_MESHPATH_ERR, hwmp_recv_action_meshpath_perr);
|
||||
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
|
||||
IEEE80211_ACTION_MESHPATH_RANN, hwmp_recv_action_meshpath_rann);
|
||||
IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath);
|
||||
|
||||
/* NB: default is 5 secs per spec */
|
||||
mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
|
||||
@ -285,17 +276,23 @@ hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
|
||||
}
|
||||
|
||||
static int
|
||||
hwmp_recv_action_meshpath_preq(struct ieee80211_node *ni,
|
||||
hwmp_recv_action_meshpath(struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh,
|
||||
const uint8_t *frm, const uint8_t *efrm)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct ieee80211_meshpreq_ie preq;
|
||||
struct ieee80211_meshprep_ie prep;
|
||||
struct ieee80211_meshperr_ie perr;
|
||||
struct ieee80211_meshrann_ie rann;
|
||||
const uint8_t *iefrm = frm + 2; /* action + code */
|
||||
int found = 0;
|
||||
|
||||
while (efrm - iefrm > 1) {
|
||||
IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
|
||||
if (*iefrm == IEEE80211_ELEMID_MESHPREQ) {
|
||||
switch (*iefrm) {
|
||||
case IEEE80211_ELEMID_MESHPREQ:
|
||||
{
|
||||
const struct ieee80211_meshpreq_ie *mpreq =
|
||||
(const struct ieee80211_meshpreq_ie *) iefrm;
|
||||
/* XXX > 1 target */
|
||||
@ -305,7 +302,7 @@ hwmp_recv_action_meshpath_preq(struct ieee80211_node *ni,
|
||||
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PREQ with wrong len");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
memcpy(&preq, mpreq, sizeof(preq));
|
||||
preq.preq_id = LE_READ_4(&mpreq->preq_id);
|
||||
@ -315,28 +312,11 @@ hwmp_recv_action_meshpath_preq(struct ieee80211_node *ni,
|
||||
preq.preq_targets[0].target_seq =
|
||||
LE_READ_4(&mpreq->preq_targets[0].target_seq);
|
||||
hwmp_recv_preq(vap, ni, wh, &preq);
|
||||
return 0;
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
iefrm += iefrm[1] + 2;
|
||||
}
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PREQ without IE");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hwmp_recv_action_meshpath_prep(struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh,
|
||||
const uint8_t *frm, const uint8_t *efrm)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct ieee80211_meshprep_ie prep;
|
||||
const uint8_t *iefrm = frm + 2; /* action + code */
|
||||
|
||||
while (efrm - iefrm > 1) {
|
||||
IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
|
||||
if (*iefrm == IEEE80211_ELEMID_MESHPREP) {
|
||||
case IEEE80211_ELEMID_MESHPREP:
|
||||
{
|
||||
const struct ieee80211_meshprep_ie *mprep =
|
||||
(const struct ieee80211_meshprep_ie *) iefrm;
|
||||
if (mprep->prep_len !=
|
||||
@ -345,7 +325,7 @@ hwmp_recv_action_meshpath_prep(struct ieee80211_node *ni,
|
||||
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PREP with wrong len");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
memcpy(&prep, mprep, sizeof(prep));
|
||||
prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq);
|
||||
@ -353,28 +333,11 @@ hwmp_recv_action_meshpath_prep(struct ieee80211_node *ni,
|
||||
prep.prep_metric = LE_READ_4(&mprep->prep_metric);
|
||||
prep.prep_origseq = LE_READ_4(&mprep->prep_origseq);
|
||||
hwmp_recv_prep(vap, ni, wh, &prep);
|
||||
return 0;
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
iefrm += iefrm[1] + 2;
|
||||
}
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PREP without IE");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hwmp_recv_action_meshpath_perr(struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh,
|
||||
const uint8_t *frm, const uint8_t *efrm)
|
||||
{
|
||||
struct ieee80211_meshperr_ie perr;
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
const uint8_t *iefrm = frm + 2; /* action + code */
|
||||
|
||||
while (efrm - iefrm > 1) {
|
||||
IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
|
||||
if (*iefrm == IEEE80211_ELEMID_MESHPERR) {
|
||||
case IEEE80211_ELEMID_MESHPERR:
|
||||
{
|
||||
const struct ieee80211_meshperr_ie *mperr =
|
||||
(const struct ieee80211_meshperr_ie *) iefrm;
|
||||
/* XXX > 1 target */
|
||||
@ -384,34 +347,17 @@ hwmp_recv_action_meshpath_perr(struct ieee80211_node *ni,
|
||||
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PERR with wrong len");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
memcpy(&perr, mperr, sizeof(perr));
|
||||
perr.perr_dests[0].dest_seq =
|
||||
LE_READ_4(&mperr->perr_dests[0].dest_seq);
|
||||
hwmp_recv_perr(vap, ni, wh, &perr);
|
||||
return 0;
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
iefrm += iefrm[1] + 2;
|
||||
}
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PERR without IE");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hwmp_recv_action_meshpath_rann(struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh,
|
||||
const uint8_t *frm, const uint8_t *efrm)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct ieee80211_meshrann_ie rann;
|
||||
const uint8_t *iefrm = frm + 2; /* action + code */
|
||||
|
||||
while (efrm - iefrm > 1) {
|
||||
IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0);
|
||||
if (*iefrm == IEEE80211_ELEMID_MESHRANN) {
|
||||
case IEEE80211_ELEMID_MESHRANN:
|
||||
{
|
||||
const struct ieee80211_meshrann_ie *mrann =
|
||||
(const struct ieee80211_meshrann_ie *) iefrm;
|
||||
if (mrann->rann_len !=
|
||||
@ -426,13 +372,18 @@ hwmp_recv_action_meshpath_rann(struct ieee80211_node *ni,
|
||||
rann.rann_seq = LE_READ_4(&mrann->rann_seq);
|
||||
rann.rann_metric = LE_READ_4(&mrann->rann_metric);
|
||||
hwmp_recv_rann(vap, ni, wh, &rann);
|
||||
return 0;
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iefrm += iefrm[1] + 2;
|
||||
}
|
||||
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "RANN without IE");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
if (!found) {
|
||||
IEEE80211_DISCARD(vap,
|
||||
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
|
||||
wh, NULL, "%s", "PATH SEL action without IE");
|
||||
vap->iv_stats.is_rx_mgtdiscard++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -480,24 +431,21 @@ hwmp_send_action(struct ieee80211_node *ni,
|
||||
return ENOMEM;
|
||||
}
|
||||
*frm++ = IEEE80211_ACTION_CAT_MESHPATH;
|
||||
*frm++ = IEEE80211_ACTION_MESHPATH_SEL;
|
||||
switch (*ie) {
|
||||
case IEEE80211_ELEMID_MESHPREQ:
|
||||
*frm++ = IEEE80211_ACTION_MESHPATH_REQ;
|
||||
frm = hwmp_add_meshpreq(frm,
|
||||
(struct ieee80211_meshpreq_ie *)ie);
|
||||
break;
|
||||
case IEEE80211_ELEMID_MESHPREP:
|
||||
*frm++ = IEEE80211_ACTION_MESHPATH_REP;
|
||||
frm = hwmp_add_meshprep(frm,
|
||||
(struct ieee80211_meshprep_ie *)ie);
|
||||
break;
|
||||
case IEEE80211_ELEMID_MESHPERR:
|
||||
*frm++ = IEEE80211_ACTION_MESHPATH_ERR;
|
||||
frm = hwmp_add_meshperr(frm,
|
||||
(struct ieee80211_meshperr_ie *)ie);
|
||||
break;
|
||||
case IEEE80211_ELEMID_MESHRANN:
|
||||
*frm++ = IEEE80211_ACTION_MESHPATH_RANN;
|
||||
frm = hwmp_add_meshrann(frm,
|
||||
(struct ieee80211_meshrann_ie *)ie);
|
||||
break;
|
||||
@ -528,6 +476,11 @@ hwmp_send_action(struct ieee80211_node *ni,
|
||||
return ic->ic_raw_xmit(ni, m, ¶ms);
|
||||
}
|
||||
|
||||
#define ADDSHORT(frm, v) do { \
|
||||
frm[0] = (v) & 0xff; \
|
||||
frm[1] = (v) >> 8; \
|
||||
frm += 2; \
|
||||
} while (0)
|
||||
#define ADDWORD(frm, v) do { \
|
||||
LE_WRITE_4(frm, v); \
|
||||
frm += 4; \
|
||||
@ -592,12 +545,14 @@ hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
|
||||
*frm++ = IEEE80211_ELEMID_MESHPERR;
|
||||
*frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 +
|
||||
(perr->perr_ndests - 1) * sizeof(*perr->perr_dests);
|
||||
*frm++ = perr->perr_mode;
|
||||
*frm++ = perr->perr_ttl;
|
||||
*frm++ = perr->perr_ndests;
|
||||
for (i = 0; i < perr->perr_ndests; i++) {
|
||||
*frm += perr->perr_dests[i].dest_flags;
|
||||
IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
|
||||
frm += 6;
|
||||
ADDWORD(frm, perr->perr_dests[i].dest_seq);
|
||||
ADDSHORT(frm, perr->perr_dests[i].dest_rcode);
|
||||
}
|
||||
return frm;
|
||||
}
|
||||
@ -1138,12 +1093,15 @@ hwmp_send_prep(struct ieee80211_node *ni,
|
||||
sizeof(struct ieee80211_meshprep_ie));
|
||||
}
|
||||
|
||||
#define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags
|
||||
#define PERR_DADDR(n) perr.perr_dests[n].dest_addr
|
||||
#define PERR_DSEQ(n) perr.perr_dests[n].dest_seq
|
||||
#define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode
|
||||
static void
|
||||
hwmp_peerdown(struct ieee80211_node *ni)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||
struct ieee80211_meshperr_ie perr;
|
||||
struct ieee80211_mesh_route *rt;
|
||||
struct ieee80211_hwmp_route *hr;
|
||||
@ -1154,19 +1112,27 @@ hwmp_peerdown(struct ieee80211_node *ni)
|
||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"%s", "delete route entry");
|
||||
perr.perr_mode = 0;
|
||||
perr.perr_ttl = ms->ms_ttl;
|
||||
perr.perr_ndests = 1;
|
||||
if (hr->hr_seq == 0)
|
||||
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
|
||||
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
|
||||
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
|
||||
PERR_DSEQ(0) = hr->hr_seq;
|
||||
PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
|
||||
/* NB: flush everything passing through peer */
|
||||
ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
|
||||
hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
|
||||
}
|
||||
#undef PERR_DFLAGS
|
||||
#undef PERR_DADDR
|
||||
#undef PERR_DSEQ
|
||||
#undef PERR_DRCODE
|
||||
|
||||
#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
|
||||
#define PERR_DADDR(n) perr->perr_dests[n].dest_addr
|
||||
#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
|
||||
#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
|
||||
static void
|
||||
hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
|
||||
@ -1192,9 +1158,9 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
|
||||
if (rt == NULL)
|
||||
continue;
|
||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
||||
struct ieee80211_hwmp_route);
|
||||
if (HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
|
||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
||||
if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) &&
|
||||
HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
|
||||
ieee80211_mesh_rt_del(vap, rt->rt_dest);
|
||||
ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
|
||||
rt = NULL;
|
||||
@ -1205,10 +1171,11 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
||||
* Propagate the PERR if we previously found it on our routing table.
|
||||
* XXX handle ndest > 1
|
||||
*/
|
||||
if (forward) {
|
||||
if (forward && perr->perr_ttl > 1) {
|
||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||
"propagate PERR from %s", ether_sprintf(wh->i_addr2));
|
||||
memcpy(&pperr, perr, sizeof(*perr));
|
||||
pperr.perr_ttl--;
|
||||
hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
|
||||
&pperr);
|
||||
}
|
||||
|
@ -87,10 +87,10 @@ static void mesh_peer_timeout_backoff(struct ieee80211_node *);
|
||||
static void mesh_peer_timeout_cb(void *);
|
||||
static __inline void
|
||||
mesh_peer_timeout_stop(struct ieee80211_node *);
|
||||
static int mesh_verify_meshpeerver(struct ieee80211vap *, const uint8_t *);
|
||||
static int mesh_verify_meshid(struct ieee80211vap *, const uint8_t *);
|
||||
static int mesh_verify_meshconf(struct ieee80211vap *, const uint8_t *);
|
||||
static int mesh_verify_meshpeer(struct ieee80211vap *, const uint8_t *);
|
||||
static int mesh_verify_meshpeer(struct ieee80211vap *, uint8_t,
|
||||
const uint8_t *);
|
||||
uint32_t mesh_airtime_calc(struct ieee80211_node *);
|
||||
|
||||
/*
|
||||
@ -1544,19 +1544,16 @@ static const struct ieee80211_meshpeer_ie *
|
||||
mesh_parse_meshpeering_action(struct ieee80211_node *ni,
|
||||
const struct ieee80211_frame *wh, /* XXX for VERIFY_LENGTH */
|
||||
const uint8_t *frm, const uint8_t *efrm,
|
||||
struct ieee80211_meshpeer_ie *mp)
|
||||
struct ieee80211_meshpeer_ie *mp, uint8_t subtype)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
const struct ieee80211_meshpeer_ie *mpie;
|
||||
const uint8_t *meshid, *meshconf, *meshpeerver, *meshpeer;
|
||||
const uint8_t *meshid, *meshconf, *meshpeer;
|
||||
|
||||
meshid = meshconf = meshpeerver = meshpeer = NULL;
|
||||
meshid = meshconf = meshpeer = NULL;
|
||||
while (efrm - frm > 1) {
|
||||
IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return NULL);
|
||||
switch (*frm) {
|
||||
case IEEE80211_ELEMID_MESHPEERVER:
|
||||
meshpeerver = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_MESHID:
|
||||
meshid = frm;
|
||||
break;
|
||||
@ -1567,12 +1564,10 @@ mesh_parse_meshpeering_action(struct ieee80211_node *ni,
|
||||
meshpeer = frm;
|
||||
mpie = (const struct ieee80211_meshpeer_ie *) frm;
|
||||
memset(mp, 0, sizeof(*mp));
|
||||
mp->peer_subtype = mpie->peer_subtype;
|
||||
mp->peer_llinkid = LE_READ_2(&mpie->peer_llinkid);
|
||||
/* NB: peer link ID is optional on these frames */
|
||||
if (mpie->peer_subtype ==
|
||||
IEEE80211_MESH_PEER_LINK_CLOSE &&
|
||||
mpie->peer_len == 5) {
|
||||
if (subtype == IEEE80211_MESH_PEER_LINK_CLOSE &&
|
||||
mpie->peer_len == 8) {
|
||||
mp->peer_linkid = 0;
|
||||
mp->peer_rcode = LE_READ_2(&mpie->peer_linkid);
|
||||
} else {
|
||||
@ -1589,12 +1584,12 @@ mesh_parse_meshpeering_action(struct ieee80211_node *ni,
|
||||
* close subtype don't have a Mesh Configuration IE.
|
||||
* If if fails validation, close the peer link.
|
||||
*/
|
||||
KASSERT(meshpeer != NULL && mp->peer_subtype !=
|
||||
IEEE80211_ACTION_MESHPEERING_CLOSE, ("parsing close action"));
|
||||
KASSERT(meshpeer != NULL &&
|
||||
subtype != IEEE80211_ACTION_MESHPEERING_CLOSE,
|
||||
("parsing close action"));
|
||||
|
||||
if (mesh_verify_meshpeerver(vap, meshpeerver) ||
|
||||
mesh_verify_meshid(vap, meshid) ||
|
||||
mesh_verify_meshpeer(vap, meshpeer) ||
|
||||
if (mesh_verify_meshid(vap, meshid) ||
|
||||
mesh_verify_meshpeer(vap, subtype, meshpeer) ||
|
||||
mesh_verify_meshconf(vap, meshconf)) {
|
||||
uint16_t args[3];
|
||||
|
||||
@ -1638,7 +1633,8 @@ mesh_recv_action_meshpeering_open(struct ieee80211_node *ni,
|
||||
uint16_t args[3];
|
||||
|
||||
/* +2+2 for action + code + capabilites */
|
||||
meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2, efrm, &ie);
|
||||
meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2, efrm, &ie,
|
||||
IEEE80211_ACTION_MESHPEERING_OPEN);
|
||||
if (meshpeer == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@ -1770,7 +1766,8 @@ mesh_recv_action_meshpeering_confirm(struct ieee80211_node *ni,
|
||||
uint16_t args[3];
|
||||
|
||||
/* +2+2+2+2 for action + code + capabilites + status code + AID */
|
||||
meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2+2+2, efrm, &ie);
|
||||
meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2+2+2+2, efrm, &ie,
|
||||
IEEE80211_ACTION_MESHPEERING_CONFIRM);
|
||||
if (meshpeer == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@ -1933,7 +1930,6 @@ mesh_send_action_meshpeering_open(struct ieee80211_node *ni,
|
||||
ic->ic_headroom + sizeof(struct ieee80211_frame),
|
||||
sizeof(uint16_t) /* action+category */
|
||||
+ sizeof(uint16_t) /* capabilites */
|
||||
+ sizeof(struct ieee80211_meshpeerver_ie)
|
||||
+ 2 + IEEE80211_RATE_SIZE
|
||||
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
|
||||
+ 2 + IEEE80211_MESHID_LEN
|
||||
@ -1946,7 +1942,6 @@ mesh_send_action_meshpeering_open(struct ieee80211_node *ni,
|
||||
* [1] category
|
||||
* [1] action
|
||||
* [2] capabilities
|
||||
* [tlv] mesh peer protocol version
|
||||
* [tlv] rates
|
||||
* [tlv] xrates
|
||||
* [tlv] mesh id
|
||||
@ -1956,7 +1951,6 @@ mesh_send_action_meshpeering_open(struct ieee80211_node *ni,
|
||||
*frm++ = category;
|
||||
*frm++ = action;
|
||||
ADDSHORT(frm, ieee80211_getcapinfo(vap, ni->ni_chan));
|
||||
frm = ieee80211_add_meshpeerver(frm, vap);
|
||||
rs = ieee80211_get_suprates(ic, ic->ic_curchan);
|
||||
frm = ieee80211_add_rates(frm, rs);
|
||||
frm = ieee80211_add_xrates(frm, rs);
|
||||
@ -1999,7 +1993,6 @@ mesh_send_action_meshpeering_confirm(struct ieee80211_node *ni,
|
||||
+ sizeof(uint16_t) /* capabilites */
|
||||
+ sizeof(uint16_t) /* status code */
|
||||
+ sizeof(uint16_t) /* AID */
|
||||
+ sizeof(struct ieee80211_meshpeerver_ie)
|
||||
+ 2 + IEEE80211_RATE_SIZE
|
||||
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
|
||||
+ 2 + IEEE80211_MESHID_LEN
|
||||
@ -2014,7 +2007,6 @@ mesh_send_action_meshpeering_confirm(struct ieee80211_node *ni,
|
||||
* [2] capabilities
|
||||
* [2] status code
|
||||
* [2] association id (peer ID)
|
||||
* [tlv] mesh peer protocol version
|
||||
* [tlv] rates
|
||||
* [tlv] xrates
|
||||
* [tlv] mesh id
|
||||
@ -2026,7 +2018,6 @@ mesh_send_action_meshpeering_confirm(struct ieee80211_node *ni,
|
||||
ADDSHORT(frm, ieee80211_getcapinfo(vap, ni->ni_chan));
|
||||
ADDSHORT(frm, 0); /* status code */
|
||||
ADDSHORT(frm, args[1]); /* AID */
|
||||
frm = ieee80211_add_meshpeerver(frm, vap);
|
||||
rs = ieee80211_get_suprates(ic, ic->ic_curchan);
|
||||
frm = ieee80211_add_rates(frm, rs);
|
||||
frm = ieee80211_add_xrates(frm, rs);
|
||||
@ -2067,7 +2058,6 @@ mesh_send_action_meshpeering_close(struct ieee80211_node *ni,
|
||||
ic->ic_headroom + sizeof(struct ieee80211_frame),
|
||||
sizeof(uint16_t) /* action+category */
|
||||
+ sizeof(uint16_t) /* reason code */
|
||||
+ sizeof(struct ieee80211_meshpeerver_ie)
|
||||
+ 2 + IEEE80211_MESHID_LEN
|
||||
+ sizeof(struct ieee80211_meshpeer_ie)
|
||||
);
|
||||
@ -2077,14 +2067,12 @@ mesh_send_action_meshpeering_close(struct ieee80211_node *ni,
|
||||
* [1] category
|
||||
* [1] action
|
||||
* [2] reason code
|
||||
* [tlv] mesh peer protocol version
|
||||
* [tlv] mesh id
|
||||
* [tlv] mesh peer link mgmt
|
||||
*/
|
||||
*frm++ = category;
|
||||
*frm++ = action;
|
||||
ADDSHORT(frm, args[2]); /* reason code */
|
||||
frm = ieee80211_add_meshpeerver(frm, vap);
|
||||
frm = ieee80211_add_meshid(frm, vap);
|
||||
frm = ieee80211_add_meshpeer(frm,
|
||||
IEEE80211_MESH_PEER_LINK_CLOSE,
|
||||
@ -2278,19 +2266,6 @@ mesh_peer_timeout_cb(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mesh_verify_meshpeerver(struct ieee80211vap *vap, const uint8_t *ie)
|
||||
{
|
||||
static const uint8_t peer[4] = IEEE80211_MESHPEERVER_PEER;
|
||||
const struct ieee80211_meshpeerver_ie *meshpeerver =
|
||||
(const struct ieee80211_meshpeerver_ie *) ie;
|
||||
|
||||
if (meshpeerver->peerver_len !=
|
||||
sizeof(struct ieee80211_meshpeerver_ie) - 2)
|
||||
return 1;
|
||||
return memcmp(meshpeerver->peerver_proto, peer, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
mesh_verify_meshid(struct ieee80211vap *vap, const uint8_t *ie)
|
||||
{
|
||||
@ -2364,26 +2339,28 @@ mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie)
|
||||
}
|
||||
|
||||
static int
|
||||
mesh_verify_meshpeer(struct ieee80211vap *vap, const uint8_t *ie)
|
||||
mesh_verify_meshpeer(struct ieee80211vap *vap, uint8_t subtype,
|
||||
const uint8_t *ie)
|
||||
{
|
||||
const struct ieee80211_meshpeer_ie *meshpeer =
|
||||
(const struct ieee80211_meshpeer_ie *) ie;
|
||||
|
||||
if (meshpeer == NULL)
|
||||
if (meshpeer == NULL || meshpeer->peer_len < 6 ||
|
||||
meshpeer->peer_len > 10)
|
||||
return 1;
|
||||
switch (meshpeer->peer_subtype) {
|
||||
switch (subtype) {
|
||||
case IEEE80211_MESH_PEER_LINK_OPEN:
|
||||
if (meshpeer->peer_len != 3)
|
||||
if (meshpeer->peer_len != 6)
|
||||
return 1;
|
||||
break;
|
||||
case IEEE80211_MESH_PEER_LINK_CONFIRM:
|
||||
if (meshpeer->peer_len != 5)
|
||||
if (meshpeer->peer_len != 8)
|
||||
return 1;
|
||||
break;
|
||||
case IEEE80211_MESH_PEER_LINK_CLOSE:
|
||||
if (meshpeer->peer_len < 5)
|
||||
if (meshpeer->peer_len < 8)
|
||||
return 1;
|
||||
if (meshpeer->peer_len == 5 && meshpeer->peer_linkid != 0)
|
||||
if (meshpeer->peer_len == 8 && meshpeer->peer_linkid != 0)
|
||||
return 1;
|
||||
if (meshpeer->peer_rcode == 0)
|
||||
return 1;
|
||||
@ -2448,25 +2425,6 @@ ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap)
|
||||
return frm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a Mesh Peer Protocol IE to a frame.
|
||||
* XXX: needs to grow support for Abbreviated Handshake
|
||||
*/
|
||||
uint8_t *
|
||||
ieee80211_add_meshpeerver(uint8_t *frm, struct ieee80211vap *vap)
|
||||
{
|
||||
static struct ieee80211_meshpeerver_ie ie = {
|
||||
.peerver_ie = IEEE80211_ELEMID_MESHPEERVER,
|
||||
.peerver_len = 4,
|
||||
.peerver_proto = IEEE80211_MESHPEERVER_PEER,
|
||||
};
|
||||
|
||||
KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap"));
|
||||
|
||||
memcpy(frm, &ie, sizeof(ie));
|
||||
return frm + sizeof(ie);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a Mesh Peer Management IE to a frame.
|
||||
*/
|
||||
@ -2474,28 +2432,34 @@ uint8_t *
|
||||
ieee80211_add_meshpeer(uint8_t *frm, uint8_t subtype, uint16_t localid,
|
||||
uint16_t peerid, uint16_t reason)
|
||||
{
|
||||
/* XXX change for AH */
|
||||
static const uint8_t meshpeerproto[4] = IEEE80211_MESH_PEER_PROTO;
|
||||
|
||||
KASSERT(localid != 0, ("localid == 0"));
|
||||
|
||||
*frm++ = IEEE80211_ELEMID_MESHPEER;
|
||||
switch (subtype) {
|
||||
case IEEE80211_MESH_PEER_LINK_OPEN:
|
||||
*frm++ = 3; /* length */
|
||||
*frm++ = subtype;
|
||||
*frm++ = 6; /* length */
|
||||
memcpy(frm, meshpeerproto, 4);
|
||||
frm += 4;
|
||||
ADDSHORT(frm, localid); /* local ID */
|
||||
break;
|
||||
case IEEE80211_MESH_PEER_LINK_CONFIRM:
|
||||
KASSERT(peerid != 0, ("sending peer confirm without peer id"));
|
||||
*frm++ = 5; /* length */
|
||||
*frm++ = subtype;
|
||||
*frm++ = 8; /* length */
|
||||
memcpy(frm, meshpeerproto, 4);
|
||||
frm += 4;
|
||||
ADDSHORT(frm, localid); /* local ID */
|
||||
ADDSHORT(frm, peerid); /* peer ID */
|
||||
break;
|
||||
case IEEE80211_MESH_PEER_LINK_CLOSE:
|
||||
if (peerid)
|
||||
*frm++ = 7; /* length */
|
||||
*frm++ = 10; /* length */
|
||||
else
|
||||
*frm++ = 5; /* length */
|
||||
*frm++ = subtype;
|
||||
*frm++ = 8; /* length */
|
||||
memcpy(frm, meshpeerproto, 4);
|
||||
frm += 4;
|
||||
ADDSHORT(frm, localid); /* local ID */
|
||||
if (peerid)
|
||||
ADDSHORT(frm, peerid); /* peer ID */
|
||||
|
@ -34,7 +34,7 @@
|
||||
#define IEEE80211_MESH_DEFAULT_TTL 31
|
||||
|
||||
/*
|
||||
* NB: all structures are__packed so sizeof works on arm, et. al.
|
||||
* NB: all structures are __packed so sizeof works on arm, et. al.
|
||||
*/
|
||||
/*
|
||||
* 802.11s Information Elements.
|
||||
@ -116,28 +116,11 @@ struct ieee80211_meshcngst_ie {
|
||||
AC_BE, AC_VI, AC_VO */
|
||||
} __packed;
|
||||
|
||||
/* Peer Version */
|
||||
struct ieee80211_meshpeerver_ie {
|
||||
uint8_t peerver_ie; /* IEEE80211_ELEMID_MESHPEERVER */
|
||||
uint8_t peerver_len;
|
||||
uint8_t peerver_proto[4];
|
||||
} __packed;
|
||||
/* Mesh Peering Management Protocol */
|
||||
#define IEEE80211_MESHPEERVER_PEER_OUI 0x00, 0x0f, 0xac
|
||||
#define IEEE80211_MESHPEERVER_PEER_VALUE 0x2a
|
||||
#define IEEE80211_MESHPEERVER_PEER { IEEE80211_MESHPEERVER_PEER_OUI, \
|
||||
IEEE80211_MESHPEERVER_PEER_VALUE }
|
||||
/* Abbreviated Handshake Protocol */
|
||||
#define IEEE80211_MESHPEERVER_AH_OUI 0x00, 0x0f, 0xac
|
||||
#define IEEE80211_MESHPEERVER_AH_VALUE 0x2b
|
||||
#define IEEE80211_MESHPEERVER_AH { IEEE80211_MESHPEERVER_AH_OUI, \
|
||||
IEEE80211_MESHPEERVER_AH_VALUE }
|
||||
|
||||
/* Peer Link Management */
|
||||
struct ieee80211_meshpeer_ie {
|
||||
uint8_t peer_ie; /* IEEE80211_ELEMID_MESHPEER */
|
||||
uint8_t peer_len;
|
||||
uint8_t peer_subtype;
|
||||
uint8_t peer_proto[4]; /* Peer Management Protocol */
|
||||
uint16_t peer_llinkid; /* Local Link ID */
|
||||
uint16_t peer_linkid; /* Peer Link ID */
|
||||
uint16_t peer_rcode;
|
||||
@ -150,6 +133,16 @@ enum {
|
||||
/* values 3-255 are reserved */
|
||||
};
|
||||
|
||||
/* Mesh Peering Management Protocol */
|
||||
#define IEEE80211_MESH_PEER_PROTO_OUI 0x00, 0x0f, 0xac
|
||||
#define IEEE80211_MESH_PEER_PROTO_VALUE 0x2a
|
||||
#define IEEE80211_MESH_PEER_PROTO { IEEE80211_MESH_PEER_PROTO_OUI, \
|
||||
IEEE80211_MESH_PEER_PROTO_VALUE }
|
||||
/* Abbreviated Handshake Protocol */
|
||||
#define IEEE80211_MESH_PEER_PROTO_AH_OUI 0x00, 0x0f, 0xac
|
||||
#define IEEE80211_MESH_PEER_PROTO_AH_VALUE 0x2b
|
||||
#define IEEE80211_MESH_PEER_PROTO_AH { IEEE80211_MESH_PEER_PROTO_AH_OUI, \
|
||||
IEEE80211_MESH_PEER_PROTO_AH_VALUE }
|
||||
#ifdef notyet
|
||||
/* Mesh Channel Switch Annoucement */
|
||||
struct ieee80211_meshcsa_ie {
|
||||
@ -256,11 +249,15 @@ struct ieee80211_meshprep_ie {
|
||||
struct ieee80211_meshperr_ie {
|
||||
uint8_t perr_ie; /* IEEE80211_ELEMID_MESHPERR */
|
||||
uint8_t perr_len;
|
||||
uint8_t perr_mode; /* NB: reserved */
|
||||
uint8_t perr_ttl;
|
||||
uint8_t perr_ndests; /* Number of Destinations */
|
||||
struct {
|
||||
uint8_t dest_flags;
|
||||
#define IEEE80211_MESHPERR_DFLAGS_USN 0x01
|
||||
#define IEEE80211_MESHPERR_DFLAGS_RC 0x02
|
||||
uint8_t dest_addr[IEEE80211_ADDR_LEN];
|
||||
uint32_t dest_seq; /* HWMP Sequence Number */
|
||||
uint16_t dest_rcode;
|
||||
} __packed perr_dests[1]; /* NB: variable size */
|
||||
} __packed;
|
||||
|
||||
@ -310,14 +307,11 @@ enum {
|
||||
};
|
||||
|
||||
/*
|
||||
* Mesh Path Selection Action codes.
|
||||
* Mesh Path Selection Action code.
|
||||
*/
|
||||
enum {
|
||||
IEEE80211_ACTION_MESHPATH_REQ = 0,
|
||||
IEEE80211_ACTION_MESHPATH_REP = 1,
|
||||
IEEE80211_ACTION_MESHPATH_ERR = 2,
|
||||
IEEE80211_ACTION_MESHPATH_RANN = 3,
|
||||
/* 4-255 reserved */
|
||||
IEEE80211_ACTION_MESHPATH_SEL = 0,
|
||||
/* 1-255 reserved */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -479,7 +473,6 @@ int ieee80211_mesh_register_proto_path(const
|
||||
int ieee80211_mesh_register_proto_metric(const
|
||||
struct ieee80211_mesh_proto_metric *);
|
||||
|
||||
uint8_t * ieee80211_add_meshpeerver(uint8_t *, struct ieee80211vap *);
|
||||
uint8_t * ieee80211_add_meshid(uint8_t *, struct ieee80211vap *);
|
||||
uint8_t * ieee80211_add_meshconf(uint8_t *, struct ieee80211vap *);
|
||||
uint8_t * ieee80211_add_meshpeer(uint8_t *, uint8_t, uint16_t, uint16_t,
|
||||
|
Loading…
Reference in New Issue
Block a user