More mesh bits, namely:

* bridge support (sam)
* handling of errors (sam)
* deletion of inactive routing entries
* more debug msgs (sam)
* fixed some inconsistencies with the spec.
* decap is now specific to mesh (sam)
* print mesh seq. no. on ifconfig list mesh
* small perf. improvements

Reviewed by:	sam
Approved by:	re (kib)
This commit is contained in:
Rui Paulo 2009-07-20 19:12:08 +00:00
parent 0a4747d4d0
commit c104cff26e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195784
7 changed files with 459 additions and 141 deletions

View File

@ -3965,21 +3965,23 @@ list_mesh(int s)
if (ioctl(s, SIOCG80211, &ireq) < 0) if (ioctl(s, SIOCG80211, &ireq) < 0)
err(1, "unable to get the Mesh routing table"); err(1, "unable to get the Mesh routing table");
printf("%-17.17s %-17.17s %4s %4s %4s\n" printf("%-17.17s %-17.17s %4s %4s %4s %6s\n"
, "DEST" , "DEST"
, "NEXT HOP" , "NEXT HOP"
, "HOPS" , "HOPS"
, "METRIC" , "METRIC"
, "LIFETIME"); , "LIFETIME"
, "MSEQ");
for (i = 0; i < ireq.i_len / sizeof(*routes); i++) { for (i = 0; i < ireq.i_len / sizeof(*routes); i++) {
printf("%s ", printf("%s ",
ether_ntoa((const struct ether_addr *)routes[i].imr_dest)); ether_ntoa((const struct ether_addr *)routes[i].imr_dest));
printf("%s %4u %4d %6d\n", printf("%s %4u %4u %6u %6u\n",
ether_ntoa((const struct ether_addr *) ether_ntoa((const struct ether_addr *)
routes[i].imr_nexthop), routes[i].imr_nexthop),
routes[i].imr_nhops, routes[i].imr_metric, routes[i].imr_nhops, routes[i].imr_metric,
routes[i].imr_lifetime); routes[i].imr_lifetime,
routes[i].imr_lastmseq);
} }
} }

View File

@ -121,7 +121,6 @@ static int ieee80211_hwmp_replyforward = 1;
static const int ieee80211_hwmp_maxprepretries = 3; static const int ieee80211_hwmp_maxprepretries = 3;
static const struct timeval ieee80211_hwmp_maxhopstime = { 0, 500000 }; static const struct timeval ieee80211_hwmp_maxhopstime = { 0, 500000 };
static const struct timeval ieee80211_hwmp_preqminint = { 0, 100000 }; static const struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
static const struct timeval ieee80211_hwmp_prepminint = { 0, 100000 };
static const struct timeval ieee80211_hwmp_perrminint = { 0, 100000 }; static const struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
static const struct timeval ieee80211_hwmp_roottimeout = { 5, 0 }; static const struct timeval ieee80211_hwmp_roottimeout = { 5, 0 };
static const struct timeval ieee80211_hwmp_pathtimeout = { 5, 0 }; static const struct timeval ieee80211_hwmp_pathtimeout = { 5, 0 };
@ -152,8 +151,6 @@ static const struct timeval ieee80211_hwmp_confirmint = { 2, 0 };
/* NB: the Target Address set in a Proactive PREQ is the broadcast address. */ /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] = static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static const uint8_t invalidaddr[IEEE80211_ADDR_LEN] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
typedef uint32_t ieee80211_hwmp_seq; typedef uint32_t ieee80211_hwmp_seq;
#define IEEE80211_HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0) #define IEEE80211_HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
@ -171,7 +168,6 @@ struct ieee80211_hwmp_state {
ieee80211_hwmp_seq hs_seq; /* next seq to be used */ ieee80211_hwmp_seq hs_seq; /* next seq to be used */
ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */ ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */
struct timeval hs_lastpreq; /* last time we sent a PREQ */ struct timeval hs_lastpreq; /* last time we sent a PREQ */
struct timeval hs_lastprep; /* last time we sent a PREP */
struct timeval hs_lastperr; /* last time we sent a PERR */ struct timeval hs_lastperr; /* last time we sent a PERR */
int hs_rootmode; /* proactive HWMP */ int hs_rootmode; /* proactive HWMP */
struct callout hs_roottimer; struct callout hs_roottimer;
@ -201,6 +197,8 @@ static const struct ieee80211_mesh_proto_path mesh_proto_hwmp = {
.mpp_vdetach = hwmp_vdetach, .mpp_vdetach = hwmp_vdetach,
.mpp_newstate = hwmp_newstate, .mpp_newstate = hwmp_newstate,
.mpp_privlen = sizeof(struct ieee80211_hwmp_route), .mpp_privlen = sizeof(struct ieee80211_hwmp_route),
/* ieee80211_hwmp_pathtimeout */
.mpp_inact = { 5, 0 },
}; };
@ -250,8 +248,7 @@ hwmp_vdetach(struct ieee80211vap *vap)
{ {
struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
if (callout_active(&hs->hs_roottimer)) callout_drain(&hs->hs_roottimer);
callout_drain(&hs->hs_roottimer);
free(vap->iv_hwmp, M_80211_VAP); free(vap->iv_hwmp, M_80211_VAP);
vap->iv_hwmp = NULL; vap->iv_hwmp = NULL;
} }
@ -269,6 +266,8 @@ hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
/* Flush the table on RUN -> !RUN, e.g. interface down & up */ /* Flush the table on RUN -> !RUN, e.g. interface down & up */
if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
callout_drain(&hs->hs_roottimer); callout_drain(&hs->hs_roottimer);
if (nstate == IEEE80211_S_RUN)
hwmp_rootmode_setup(vap);
return 0; return 0;
} }
@ -644,7 +643,7 @@ hwmp_rootmode_cb(void *arg)
struct ieee80211_meshpreq_ie preq; struct ieee80211_meshpreq_ie preq;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "sending broadcast PREQ"); "%s", "send broadcast PREQ");
/* XXX check portal role */ /* XXX check portal role */
preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
@ -683,7 +682,7 @@ hwmp_rootmode_rann_cb(void *arg)
struct ieee80211_meshrann_ie rann; struct ieee80211_meshrann_ie rann;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "sending broadcast RANN"); "%s", "send broadcast RANN");
/* XXX check portal role */ /* XXX check portal role */
rann.rann_flags = 0; rann.rann_flags = 0;
@ -740,7 +739,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
*/ */
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"replying to %s", ether_sprintf(preq->preq_origaddr)); "reply to %s", ether_sprintf(preq->preq_origaddr));
/* /*
* Build and send a PREP frame. * Build and send a PREP frame.
*/ */
@ -760,7 +759,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
if (rt == NULL) if (rt == NULL)
hwmp_discover(vap, preq->preq_origaddr, NULL); hwmp_discover(vap, preq->preq_origaddr, NULL);
else if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
hwmp_discover(vap, rt->rt_dest, NULL); hwmp_discover(vap, rt->rt_dest, NULL);
return; return;
} }
@ -774,30 +773,36 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
(IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) { (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
uint8_t rootmac[IEEE80211_ADDR_LEN]; uint8_t rootmac[IEEE80211_ADDR_LEN];
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"root mesh station @ %s",
ether_sprintf(preq->preq_origaddr));
IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr); IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
rt = ieee80211_mesh_rt_find(vap, rootmac); rt = ieee80211_mesh_rt_find(vap, rootmac);
if (rt == NULL) if (rt == NULL) {
rt = ieee80211_mesh_rt_add(vap, rootmac); rt = ieee80211_mesh_rt_add(vap, rootmac);
if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"unable to add root mesh path to %s",
ether_sprintf(rootmac));
vap->iv_stats.is_mesh_rtaddfailed++;
return;
}
}
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"root mesh station @ %s", ether_sprintf(rootmac));
/* /*
* Reply with a PREP if we don't have a path to the root * Reply with a PREP if we don't have a path to the root
* or if the root sent us a proactive PREQ. * or if the root sent us a proactive PREQ.
*/ */
if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr) || if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
(preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) { (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
prep.prep_flags = 0; prep.prep_flags = 0;
prep.prep_hopcount = 0; prep.prep_hopcount = 0;
prep.prep_ttl = ms->ms_ttl; prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(prep.prep_origaddr, IEEE80211_ADDR_COPY(prep.prep_origaddr, vap->iv_myaddr);
vap->iv_myaddr);
prep.prep_origseq = preq->preq_origseq; prep.prep_origseq = preq->preq_origseq;
prep.prep_targetseq = ++hs->hs_seq; prep.prep_targetseq = ++hs->hs_seq;
prep.prep_lifetime = preq->preq_lifetime; prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
IEEE80211_ADDR_COPY(prep.prep_targetaddr, IEEE80211_ADDR_COPY(prep.prep_targetaddr, rootmac);
rootmac);
prep.prep_targetseq = PREQ_TSEQ(0); prep.prep_targetseq = PREQ_TSEQ(0);
hwmp_send_prep(vap->iv_bss, vap->iv_myaddr, hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
broadcastaddr, &prep); broadcastaddr, &prep);
@ -820,7 +825,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
* We have a valid route to this node. * We have a valid route to this node.
*/ */
if (rt != NULL && if (rt != NULL &&
!IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) { (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
hr = IEEE80211_MESH_ROUTE_PRIV(rt, hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route); struct ieee80211_hwmp_route);
@ -829,7 +834,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
if (preq->preq_ttl > 1 && if (preq->preq_ttl > 1 &&
preq->preq_hopcount < hs->hs_maxhops) { preq->preq_hopcount < hs->hs_maxhops) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"forwarding PREQ from %s", "forward PREQ from %s",
ether_sprintf(preq->preq_origaddr)); ether_sprintf(preq->preq_origaddr));
/* /*
* Propagate the original PREQ. * Propagate the original PREQ.
@ -880,8 +885,16 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
*/ */
} else if (preq->preq_ttl > 1 && } else if (preq->preq_ttl > 1 &&
preq->preq_hopcount < hs->hs_maxhops) { preq->preq_hopcount < hs->hs_maxhops) {
if (rt == NULL) if (rt == NULL) {
rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0)); rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
ni, "unable to add PREQ path to %s",
ether_sprintf(PREQ_TADDR(0)));
vap->iv_stats.is_mesh_rtaddfailed++;
return;
}
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route); struct ieee80211_hwmp_route);
rt->rt_metric = preq->preq_metric; rt->rt_metric = preq->preq_metric;
@ -890,7 +903,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
hr->hr_preqid = preq->preq_id; hr->hr_preqid = preq->preq_id;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"forwarding PREQ from %s", "forward PREQ from %s",
ether_sprintf(preq->preq_origaddr)); ether_sprintf(preq->preq_origaddr));
ppreq.preq_hopcount += 1; ppreq.preq_hopcount += 1;
ppreq.preq_ttl -= 1; ppreq.preq_ttl -= 1;
@ -968,7 +981,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211_meshprep_ie pprep; /* propagated PREP */ struct ieee80211_meshprep_ie pprep; /* propagated PREP */
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"propagating PREP from %s", "propagate PREP from %s",
ether_sprintf(prep->prep_origaddr)); ether_sprintf(prep->prep_origaddr));
memcpy(&pprep, prep, sizeof(pprep)); memcpy(&pprep, prep, sizeof(pprep));
@ -986,10 +999,18 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
*/ */
if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) { if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
rt = ieee80211_mesh_rt_add(vap, prep->prep_origaddr); rt = ieee80211_mesh_rt_add(vap, prep->prep_origaddr);
if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
ni, "unable to add PREP path to %s",
ether_sprintf(prep->prep_origaddr));
vap->iv_stats.is_mesh_rtaddfailed++;
return;
}
IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
rt->rt_nhops = prep->prep_hopcount; rt->rt_nhops = prep->prep_hopcount;
rt->rt_lifetime = prep->prep_lifetime; rt->rt_lifetime = prep->prep_lifetime;
rt->rt_metric = prep->prep_metric; rt->rt_metric = prep->prep_metric;
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
return; return;
} }
return; return;
@ -1002,7 +1023,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
* If we do, check if this path reply contains a * If we do, check if this path reply contains a
* better route. * better route.
*/ */
if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
useprep = 1; useprep = 1;
else if (prep->prep_hopcount < rt->rt_nhops || else if (prep->prep_hopcount < rt->rt_nhops ||
prep->prep_metric < rt->rt_metric) prep->prep_metric < rt->rt_metric)
@ -1012,6 +1033,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
rt->rt_nhops = prep->prep_hopcount; rt->rt_nhops = prep->prep_hopcount;
rt->rt_lifetime = prep->prep_lifetime; rt->rt_lifetime = prep->prep_lifetime;
rt->rt_metric = prep->prep_metric; rt->rt_metric = prep->prep_metric;
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
} }
} else { } else {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
@ -1044,6 +1066,8 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
for (; m != NULL; m = next) { for (; m != NULL; m = next) {
next = m->m_nextpkt; next = m->m_nextpkt;
m->m_nextpkt = NULL; m->m_nextpkt = NULL;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"flush queued frame %p len %d", m, m->m_pkthdr.len);
ifp->if_transmit(ifp, m); ifp->if_transmit(ifp, m);
} }
} }
@ -1054,14 +1078,7 @@ hwmp_send_prep(struct ieee80211_node *ni,
const uint8_t da[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN],
struct ieee80211_meshprep_ie *prep) struct ieee80211_meshprep_ie *prep)
{ {
struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; /* NB: there's no PREP minimum interval. */
/*
* Enforce PREP interval.
*/
if (ratecheck(&hs->hs_lastprep, &ieee80211_hwmp_prepminint) == 0)
return EALREADY;
getmicrouptime(&hs->hs_lastprep);
/* /*
* mesh prep action frame format * mesh prep action frame format
@ -1092,7 +1109,7 @@ hwmp_peerdown(struct ieee80211_node *ni)
return; return;
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"%s", "deleting route entry"); "%s", "delete route entry");
perr.perr_mode = 0; perr.perr_mode = 0;
perr.perr_ndests = 1; perr.perr_ndests = 1;
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest); IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
@ -1144,7 +1161,7 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
*/ */
if (forward) { if (forward) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"propagating PERR from %s", ether_sprintf(wh->i_addr2)); "propagate PERR from %s", ether_sprintf(wh->i_addr2));
memcpy(&pperr, perr, sizeof(*perr)); memcpy(&pperr, perr, sizeof(*perr));
hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &pperr); hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &pperr);
} }
@ -1264,13 +1281,16 @@ hwmp_discover(struct ieee80211vap *vap,
if (rt == NULL) { if (rt == NULL) {
rt = ieee80211_mesh_rt_add(vap, dest); rt = ieee80211_mesh_rt_add(vap, dest);
if (rt == NULL) { if (rt == NULL) {
/* XXX stat+msg */ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
ni, "unable to add discovery path to %s",
ether_sprintf(dest));
vap->iv_stats.is_mesh_rtaddfailed++;
goto done; goto done;
} }
} }
hr = IEEE80211_MESH_ROUTE_PRIV(rt, hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route); struct ieee80211_hwmp_route);
if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) { if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
if (hr->hr_preqid == 0) { if (hr->hr_preqid == 0) {
hr->hr_seq = ++hs->hs_seq; hr->hr_seq = ++hs->hs_seq;
hr->hr_preqid = ++hs->hs_preqid; hr->hr_preqid = ++hs->hs_preqid;
@ -1281,7 +1301,9 @@ hwmp_discover(struct ieee80211vap *vap,
/* XXX check preq retries */ /* XXX check preq retries */
sendpreq = 1; sendpreq = 1;
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
"%s", "initiating path discovery"); "start path discovery (src %s)",
m == NULL ? "<none>" : ether_sprintf(
mtod(m, struct ether_header *)->ether_shost));
/* /*
* Try to discover the path for this node. * Try to discover the path for this node.
*/ */
@ -1306,16 +1328,16 @@ hwmp_discover(struct ieee80211vap *vap,
hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
broadcastaddr, &preq); broadcastaddr, &preq);
} }
if (!IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
ni = ieee80211_find_txnode(vap, rt->rt_nexthop); ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
} else { } else {
ni = ieee80211_find_txnode(vap, dest); ni = ieee80211_find_txnode(vap, dest);
/* NB: if null then we leak mbuf */
KASSERT(ni != NULL, ("leak mcast frame"));
return ni; return ni;
} }
done: done:
if (ni == NULL && m != NULL) { if (ni == NULL && m != NULL) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
dest, NULL, "%s", "no valid path to this node");
if (sendpreq) { if (sendpreq) {
struct ieee80211com *ic = vap->iv_ic; struct ieee80211com *ic = vap->iv_ic;
/* /*
@ -1323,13 +1345,18 @@ hwmp_discover(struct ieee80211vap *vap,
* completes. If discovery never completes the * completes. If discovery never completes the
* frame will be flushed by way of the aging timer. * frame will be flushed by way of the aging timer.
*/ */
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
"%s", "queue frame until path found");
m->m_pkthdr.rcvif = (void *)(uintptr_t) m->m_pkthdr.rcvif = (void *)(uintptr_t)
ieee80211_mac_hash(ic, dest); ieee80211_mac_hash(ic, dest);
/* XXX age chosen randomly */ /* XXX age chosen randomly */
ieee80211_ageq_append(&ic->ic_stageq, m, ieee80211_ageq_append(&ic->ic_stageq, m,
IEEE80211_INACT_WAIT); IEEE80211_INACT_WAIT);
} else } else {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
dest, NULL, "%s", "no valid path to this node");
m_freem(m); m_freem(m);
}
} }
return ni; return ni;
} }

View File

@ -233,22 +233,17 @@ ieee80211_deliver_data(struct ieee80211vap *vap,
struct mbuf * struct mbuf *
ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen) ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
{ {
#ifdef IEEE80211_SUPPORT_MESH
union {
struct ieee80211_qosframe_addr4 wh4;
uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
sizeof(struct ieee80211_meshcntl_ae11)];
} whu;
#define wh whu.wh4
#else
struct ieee80211_qosframe_addr4 wh; struct ieee80211_qosframe_addr4 wh;
#endif
struct ether_header *eh; struct ether_header *eh;
struct llc *llc; struct llc *llc;
KASSERT(hdrlen <= sizeof(wh),
("hdrlen %d > max %zd", hdrlen, sizeof(wh)));
if (m->m_len < hdrlen + sizeof(*llc) && if (m->m_len < hdrlen + sizeof(*llc) &&
(m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) { (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
/* XXX stat, msg */ vap->iv_stats.is_rx_tooshort++;
/* XXX msg */
return NULL; return NULL;
} }
memcpy(&wh, mtod(m, caddr_t), hdrlen); memcpy(&wh, mtod(m, caddr_t), hdrlen);
@ -295,7 +290,6 @@ ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh)); eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
} }
return m; return m;
#undef wh
} }
/* /*

View File

@ -235,9 +235,13 @@ struct ieee80211_stats {
uint32_t is_hwmp_wrongseq; /* wrong hwmp seq no. */ uint32_t is_hwmp_wrongseq; /* wrong hwmp seq no. */
uint32_t is_hwmp_rootreqs; /* root PREQs sent */ uint32_t is_hwmp_rootreqs; /* root PREQs sent */
uint32_t is_hwmp_rootrann; /* root RANNs sent */ uint32_t is_hwmp_rootrann; /* root RANNs sent */
uint32_t is_rx_badalign; /* dropped 'cuz misaligned */
uint32_t is_spare[15]; uint32_t is_mesh_badae; /* dropped 'cuz invalid AE */
uint32_t is_mesh_rtaddfailed; /* route add failed */
uint32_t is_mesh_notproxy; /* dropped 'cuz not proxying */
uint32_t is_rx_badalign; /* dropped 'cuz misaligned */
uint32_t is_spare[12];
}; };
/* /*
@ -328,6 +332,16 @@ enum {
IEEE80211_MESH_RTCMD_DELETE = 3, /* delete an entry from the table */ IEEE80211_MESH_RTCMD_DELETE = 3, /* delete an entry from the table */
}; };
struct ieee80211req_mesh_route {
uint8_t imr_dest[IEEE80211_ADDR_LEN];
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
uint16_t imr_nhops;
uint16_t imr_pad;
uint32_t imr_metric;
uint32_t imr_lifetime;
uint32_t imr_lastmseq;
};
/* /*
* HWMP root modes * HWMP root modes
*/ */

View File

@ -62,10 +62,12 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_input.h> #include <net80211/ieee80211_input.h>
#include <net80211/ieee80211_mesh.h> #include <net80211/ieee80211_mesh.h>
static void mesh_rt_flush_invalid(struct ieee80211vap *);
static int mesh_select_proto_path(struct ieee80211vap *, const char *); static int mesh_select_proto_path(struct ieee80211vap *, const char *);
static int mesh_select_proto_metric(struct ieee80211vap *, const char *); static int mesh_select_proto_metric(struct ieee80211vap *, const char *);
static void mesh_vattach(struct ieee80211vap *); static void mesh_vattach(struct ieee80211vap *);
static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void mesh_rt_cleanup_cb(void *);
static void mesh_linkchange(struct ieee80211_node *, static void mesh_linkchange(struct ieee80211_node *,
enum ieee80211_mesh_mlstate); enum ieee80211_mesh_mlstate);
static void mesh_checkid(void *, struct ieee80211_node *); static void mesh_checkid(void *, struct ieee80211_node *);
@ -138,6 +140,7 @@ static struct ieee80211_mesh_proto_path mesh_proto_paths[4];
static struct ieee80211_mesh_proto_metric mesh_proto_metrics[4]; static struct ieee80211_mesh_proto_metric mesh_proto_metrics[4];
#define MESH_RT_LOCK(ms) mtx_lock(&(ms)->ms_rt_lock) #define MESH_RT_LOCK(ms) mtx_lock(&(ms)->ms_rt_lock)
#define MESH_RT_LOCK_ASSERT(ms) mtx_assert(&(ms)->ms_rt_lock, MA_OWNED)
#define MESH_RT_UNLOCK(ms) mtx_unlock(&(ms)->ms_rt_lock) #define MESH_RT_UNLOCK(ms) mtx_unlock(&(ms)->ms_rt_lock)
MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table"); MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
@ -145,6 +148,44 @@ MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
/* /*
* Helper functions to manipulate the Mesh routing table. * Helper functions to manipulate the Mesh routing table.
*/ */
static struct ieee80211_mesh_route *
mesh_rt_find_locked(struct ieee80211_mesh_state *ms,
const uint8_t dest[IEEE80211_ADDR_LEN])
{
struct ieee80211_mesh_route *rt;
MESH_RT_LOCK_ASSERT(ms);
TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
if (IEEE80211_ADDR_EQ(dest, rt->rt_dest))
return rt;
}
return NULL;
}
static struct ieee80211_mesh_route *
mesh_rt_add_locked(struct ieee80211_mesh_state *ms,
const uint8_t dest[IEEE80211_ADDR_LEN])
{
struct ieee80211_mesh_route *rt;
KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
("%s: adding broadcast to the routing table", __func__));
MESH_RT_LOCK_ASSERT(ms);
rt = malloc(ALIGN(sizeof(struct ieee80211_mesh_route)) +
ms->ms_ppath->mpp_privlen, M_80211_MESH_RT, M_NOWAIT | M_ZERO);
if (rt != NULL) {
IEEE80211_ADDR_COPY(rt->rt_dest, dest);
rt->rt_priv = (void *)ALIGN(&rt[1]);
getmicrouptime(&rt->rt_crtime);
TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
}
return rt;
}
struct ieee80211_mesh_route * struct ieee80211_mesh_route *
ieee80211_mesh_rt_find(struct ieee80211vap *vap, ieee80211_mesh_rt_find(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN]) const uint8_t dest[IEEE80211_ADDR_LEN])
@ -153,14 +194,9 @@ ieee80211_mesh_rt_find(struct ieee80211vap *vap,
struct ieee80211_mesh_route *rt; struct ieee80211_mesh_route *rt;
MESH_RT_LOCK(ms); MESH_RT_LOCK(ms);
TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) { rt = mesh_rt_find_locked(ms, dest);
if (IEEE80211_ADDR_EQ(dest, rt->rt_dest)) {
MESH_RT_UNLOCK(ms);
return rt;
}
}
MESH_RT_UNLOCK(ms); MESH_RT_UNLOCK(ms);
return NULL; return rt;
} }
struct ieee80211_mesh_route * struct ieee80211_mesh_route *
@ -174,20 +210,65 @@ ieee80211_mesh_rt_add(struct ieee80211vap *vap,
("%s: duplicate entry in the routing table", __func__)); ("%s: duplicate entry in the routing table", __func__));
KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest), KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
("%s: adding self to the routing table", __func__)); ("%s: adding self to the routing table", __func__));
KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
("%s: adding broadcast to the routing table", __func__));
rt = malloc(sizeof(struct ieee80211_mesh_route), M_80211_MESH_RT,
M_NOWAIT | M_ZERO);
IEEE80211_ADDR_COPY(rt->rt_dest, dest);
rt->rt_priv = malloc(ms->ms_ppath->mpp_privlen, M_80211_MESH_RT,
M_NOWAIT | M_ZERO);
MESH_RT_LOCK(ms); MESH_RT_LOCK(ms);
TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next); rt = mesh_rt_add_locked(ms, dest);
MESH_RT_UNLOCK(ms); MESH_RT_UNLOCK(ms);
return rt; return rt;
} }
/*
* Add a proxy route (as needed) for the specified destination.
*/
void
ieee80211_mesh_proxy_check(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN])
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt;
MESH_RT_LOCK(ms);
rt = mesh_rt_find_locked(ms, dest);
if (rt == NULL) {
rt = mesh_rt_add_locked(ms, dest);
if (rt == NULL) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
"%s", "unable to add proxy entry");
vap->iv_stats.is_mesh_rtaddfailed++;
} else {
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
| IEEE80211_MESHRT_FLAGS_PROXY;
}
/* XXX assert PROXY? */
} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
struct ieee80211com *ic = vap->iv_ic;
/*
* Fix existing entry created by received frames from
* stations that have some memory of dest. We also
* flush any frames held on the staging queue; delivering
* them is too much trouble right now.
*/
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
"%s", "fix proxy entry");
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
| IEEE80211_MESHRT_FLAGS_PROXY;
/* XXX belongs in hwmp */
ieee80211_ageq_drain_node(&ic->ic_stageq,
(void *)(uintptr_t) ieee80211_mac_hash(ic, dest));
/* XXX stat? */
}
MESH_RT_UNLOCK(ms);
}
static __inline void
mesh_rt_del(struct ieee80211_mesh_state *ms, struct ieee80211_mesh_route *rt)
{
TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
free(rt, M_80211_MESH_RT);
}
void void
ieee80211_mesh_rt_del(struct ieee80211vap *vap, ieee80211_mesh_rt_del(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN]) const uint8_t dest[IEEE80211_ADDR_LEN])
@ -198,9 +279,7 @@ ieee80211_mesh_rt_del(struct ieee80211vap *vap,
MESH_RT_LOCK(ms); MESH_RT_LOCK(ms);
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) { TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) { if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) {
TAILQ_REMOVE(&ms->ms_routes, rt, rt_next); mesh_rt_del(ms, rt);
free(rt->rt_priv, M_80211_MESH_RT);
free(rt, M_80211_MESH_RT);
MESH_RT_UNLOCK(ms); MESH_RT_UNLOCK(ms);
return; return;
} }
@ -217,10 +296,32 @@ ieee80211_mesh_rt_flush(struct ieee80211vap *vap)
if (ms == NULL) if (ms == NULL)
return; return;
MESH_RT_LOCK(ms); MESH_RT_LOCK(ms);
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next)
mesh_rt_del(ms, rt);
MESH_RT_UNLOCK(ms);
}
/*
* Flush expired routing entries, i.e. those in invalid state for
* some time.
*/
static void
mesh_rt_flush_invalid(struct ieee80211vap *vap)
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt, *next;
struct timeval tv, delta;
if (ms == NULL)
return;
getmicrouptime(&tv);
MESH_RT_LOCK(ms);
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) { TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
TAILQ_REMOVE(&ms->ms_routes, rt, rt_next); delta = tv;
free(rt->rt_priv, M_80211_MESH_RT); timevalsub(&delta, &rt->rt_crtime);
free(rt, M_80211_MESH_RT); if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 &&
timevalcmp(&delta, &ms->ms_ppath->mpp_inact, >=))
mesh_rt_del(ms, rt);
} }
MESH_RT_UNLOCK(ms); MESH_RT_UNLOCK(ms);
} }
@ -381,7 +482,7 @@ mesh_vdetach_peers(void *arg, struct ieee80211_node *ni)
IEEE80211_ACTION_MESHPEERING_CLOSE, IEEE80211_ACTION_MESHPEERING_CLOSE,
args); args);
} }
callout_stop(&ni->ni_mltimer); callout_drain(&ni->ni_mltimer);
/* XXX belongs in hwmp */ /* XXX belongs in hwmp */
ieee80211_ageq_drain_node(&ic->ic_stageq, ieee80211_ageq_drain_node(&ic->ic_stageq,
(void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr)); (void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr));
@ -392,6 +493,7 @@ mesh_vdetach(struct ieee80211vap *vap)
{ {
struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_state *ms = vap->iv_mesh;
callout_drain(&ms->ms_cleantimer);
ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers, ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers,
NULL); NULL);
ieee80211_mesh_rt_flush(vap); ieee80211_mesh_rt_flush(vap);
@ -413,7 +515,7 @@ mesh_vattach(struct ieee80211vap *vap)
M_NOWAIT | M_ZERO); M_NOWAIT | M_ZERO);
if (ms == NULL) { if (ms == NULL) {
printf("%s: couldn't alloc MBSS state\n", __func__); printf("%s: couldn't alloc MBSS state\n", __func__);
return; return;
} }
vap->iv_mesh = ms; vap->iv_mesh = ms;
ms->ms_seq = 0; ms->ms_seq = 0;
@ -421,6 +523,7 @@ mesh_vattach(struct ieee80211vap *vap)
ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL; ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL;
TAILQ_INIT(&ms->ms_routes); TAILQ_INIT(&ms->ms_routes);
mtx_init(&ms->ms_rt_lock, "MBSS", "802.11s routing table", MTX_DEF); mtx_init(&ms->ms_rt_lock, "MBSS", "802.11s routing table", MTX_DEF);
callout_init(&ms->ms_cleantimer, CALLOUT_MPSAFE);
mesh_select_proto_metric(vap, "AIRTIME"); mesh_select_proto_metric(vap, "AIRTIME");
KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL")); KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
mesh_select_proto_path(vap, "HWMP"); mesh_select_proto_path(vap, "HWMP");
@ -449,9 +552,8 @@ mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
if (ostate != IEEE80211_S_SCAN) if (ostate != IEEE80211_S_SCAN)
ieee80211_cancel_scan(vap); /* background scan */ ieee80211_cancel_scan(vap); /* background scan */
ni = vap->iv_bss; /* NB: no reference held */ ni = vap->iv_bss; /* NB: no reference held */
/* Flush the routing table */ if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
if (nstate != IEEE80211_S_INIT && ostate == IEEE80211_S_INIT) callout_drain(&ms->ms_cleantimer);
ieee80211_mesh_rt_flush(vap);
switch (nstate) { switch (nstate) {
case IEEE80211_S_INIT: case IEEE80211_S_INIT:
switch (ostate) { switch (ostate) {
@ -471,6 +573,7 @@ mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
if (ostate != IEEE80211_S_INIT) { if (ostate != IEEE80211_S_INIT) {
/* NB: optimize INIT -> INIT case */ /* NB: optimize INIT -> INIT case */
ieee80211_reset_bss(vap); ieee80211_reset_bss(vap);
ieee80211_mesh_rt_flush(vap);
} }
break; break;
case IEEE80211_S_SCAN: case IEEE80211_S_SCAN:
@ -573,17 +676,33 @@ mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
break; break;
} }
ieee80211_node_authorize(vap->iv_bss); ieee80211_node_authorize(vap->iv_bss);
callout_reset(&ms->ms_cleantimer,
msecs_to_ticks(ms->ms_ppath->mpp_inact.tv_sec * 1000 +
ms->ms_ppath->mpp_inact.tv_usec / 1000),
mesh_rt_cleanup_cb, vap);
break; break;
default: default:
break; break;
} }
/* NB: ostate not nstate */ /* NB: ostate not nstate */
ms->ms_ppath->mpp_newstate(vap, ostate, arg); ms->ms_ppath->mpp_newstate(vap, ostate, arg);
return 0; return 0;
} }
static void
mesh_rt_cleanup_cb(void *arg)
{
struct ieee80211vap *vap = arg;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
mesh_rt_flush_invalid(vap);
callout_reset(&ms->ms_cleantimer,
msecs_to_ticks(ms->ms_ppath->mpp_inact.tv_sec * 1000 +
ms->ms_ppath->mpp_inact.tv_usec / 1000),
mesh_rt_cleanup_cb, vap);
}
/* /*
* Helper function to note the Mesh Peer Link FSM change. * Helper function to note the Mesh Peer Link FSM change.
*/ */
@ -617,8 +736,16 @@ mesh_linkchange(struct ieee80211_node *ni, enum ieee80211_mesh_mlstate state)
ms->ms_neighbors--; ms->ms_neighbors--;
} }
ni->ni_mlstate = state; ni->ni_mlstate = state;
if (state == IEEE80211_NODE_MESH_HOLDING) switch (state) {
case IEEE80211_NODE_MESH_HOLDING:
ms->ms_ppath->mpp_peerdown(ni); ms->ms_ppath->mpp_peerdown(ni);
break;
case IEEE80211_NODE_MESH_ESTABLISHED:
ieee80211_mesh_discover(vap, ni->ni_macaddr, NULL);
break;
default:
break;
}
} }
/* /*
@ -660,8 +787,11 @@ mesh_checkpseq(struct ieee80211vap *vap,
rt = ieee80211_mesh_rt_find(vap, source); rt = ieee80211_mesh_rt_find(vap, source);
if (rt == NULL) { if (rt == NULL) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
"add mcast route, mesh seqno %d", seq);
rt = ieee80211_mesh_rt_add(vap, source); rt = ieee80211_mesh_rt_add(vap, source);
rt->rt_lastmseq = seq; if (rt != NULL)
rt->rt_lastmseq = seq;
return 0; return 0;
} }
if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) { if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
@ -684,6 +814,13 @@ mesh_find_txnode(struct ieee80211vap *vap,
rt = ieee80211_mesh_rt_find(vap, dest); rt = ieee80211_mesh_rt_find(vap, dest);
if (rt == NULL) if (rt == NULL)
return NULL; return NULL;
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
"%s: !valid or proxy, flags 0x%x", __func__, rt->rt_flags);
/* XXX stat */
return NULL;
}
return ieee80211_find_txnode(vap, rt->rt_nexthop); return ieee80211_find_txnode(vap, rt->rt_nexthop);
} }
@ -757,11 +894,6 @@ mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
} }
IEEE80211_ADDR_COPY(whcopy->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(whcopy->i_addr1, ni->ni_macaddr);
} }
IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, ni,
"fwd %s frame from %s ttl %d",
IEEE80211_IS_MULTICAST(wh->i_addr1) ? "mcast" : "ucast",
ether_sprintf(wh->i_addr3), mccopy->mc_ttl);
KASSERT(mccopy->mc_ttl > 0, ("%s called with wrong ttl", __func__)); KASSERT(mccopy->mc_ttl > 0, ("%s called with wrong ttl", __func__));
mccopy->mc_ttl--; mccopy->mc_ttl--;
@ -779,6 +911,117 @@ mesh_forward(struct ieee80211vap *vap, struct mbuf *m,
} }
} }
static struct mbuf *
mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
{
#define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
sizeof(struct ieee80211_meshcntl_ae11)];
const struct ieee80211_qosframe_addr4 *wh;
const struct ieee80211_meshcntl_ae10 *mc;
struct ether_header *eh;
struct llc *llc;
int ae;
if (m->m_len < hdrlen + sizeof(*llc) &&
(m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
"discard data frame: %s", "m_pullup failed");
vap->iv_stats.is_rx_tooshort++;
return NULL;
}
memcpy(b, mtod(m, caddr_t), hdrlen);
wh = (const struct ieee80211_qosframe_addr4 *)&b[0];
mc = (const struct ieee80211_meshcntl_ae10 *)&b[hdrlen - meshdrlen];
KASSERT(WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS ||
WHDIR(wh) == IEEE80211_FC1_DIR_DSTODS,
("bogus dir, fc 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 &&
/* NB: preserve AppleTalk frames that have a native SNAP hdr */
!(llc->llc_snap.ether_type == htons(ETHERTYPE_AARP) ||
llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) {
m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
llc = NULL;
} else {
m_adj(m, hdrlen - sizeof(*eh));
}
eh = mtod(m, struct ether_header *);
ae = mc->mc_flags & 3;
if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
if (ae == 0) {
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
} else if (ae == 1) {
IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
} else {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
(const struct ieee80211_frame *)wh, NULL,
"bad AE %d", ae);
vap->iv_stats.is_mesh_badae++;
m_freem(m);
return NULL;
}
} else {
if (ae == 0) {
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
} else if (ae == 2) {
IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
} else {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
(const struct ieee80211_frame *)wh, NULL,
"bad AE %d", ae);
vap->iv_stats.is_mesh_badae++;
m_freem(m);
return NULL;
}
}
#ifdef ALIGNED_POINTER
if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
m = ieee80211_realign(vap, m, sizeof(*eh));
if (m == NULL)
return NULL;
}
#endif /* ALIGNED_POINTER */
if (llc != NULL) {
eh = mtod(m, struct ether_header *);
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
}
return m;
#undef WDIR
}
/*
* Return non-zero if the unicast mesh data frame should be processed
* locally. Frames that are not proxy'd have our address, otherwise
* we need to consult the routing table to look for a proxy entry.
*/
static __inline int
mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
const struct ieee80211_meshcntl *mc)
{
int ae = mc->mc_flags & 3;
KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
if (ae == 2) { /* ucast w/ proxy */
const struct ieee80211_meshcntl_ae10 *mc10 =
(const struct ieee80211_meshcntl_ae10 *) mc;
struct ieee80211_mesh_route *rt =
ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
/* check for proxy route to ourself */
return (rt != NULL &&
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
} else /* ucast w/o proxy */
return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
}
static int static int
mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{ {
@ -789,7 +1032,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ifnet *ifp = vap->iv_ifp; struct ifnet *ifp = vap->iv_ifp;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
const struct ieee80211_meshcntl *mc; const struct ieee80211_meshcntl *mc;
int hdrspace, need_tap; int hdrspace, meshdrlen, need_tap;
uint8_t dir, type, subtype, qos; uint8_t dir, type, subtype, qos;
uint32_t seq; uint32_t seq;
uint8_t *addr; uint8_t *addr;
@ -904,13 +1147,14 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
} }
/* /*
* Now calculate the full extent of the headers. Note * Now calculate the full extent of the headers. Note
* ieee80211_decap will pull up anything we didn't get * mesh_decap will pull up anything we didn't get
* above when it strips the 802.11 headers. * above when it strips the 802.11 headers.
*/ */
mc = (const struct ieee80211_meshcntl *) mc = (const struct ieee80211_meshcntl *)
(mtod(m, const uint8_t *) + hdrspace); (mtod(m, const uint8_t *) + hdrspace);
hdrspace += sizeof(struct ieee80211_meshcntl) + meshdrlen = sizeof(struct ieee80211_meshcntl) +
(mc->mc_flags & 3) * IEEE80211_ADDR_LEN; (mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
hdrspace += meshdrlen;
seq = LE_READ_4(mc->mc_seq); seq = LE_READ_4(mc->mc_seq);
if (IEEE80211_IS_MULTICAST(wh->i_addr1)) if (IEEE80211_IS_MULTICAST(wh->i_addr1))
addr = wh->i_addr3; addr = wh->i_addr3;
@ -935,7 +1179,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
* for the rules. XXX tap fwd'd packets not for us? * for the rules. XXX tap fwd'd packets not for us?
*/ */
if (dir == IEEE80211_FC1_DIR_FROMDS || if (dir == IEEE80211_FC1_DIR_FROMDS ||
!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr)) { !mesh_isucastforme(vap, wh, mc)) {
mesh_forward(vap, m, mc); mesh_forward(vap, m, mc);
if (dir == IEEE80211_FC1_DIR_DSTODS) if (dir == IEEE80211_FC1_DIR_DSTODS)
goto out; goto out;
@ -970,7 +1214,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
/* /*
* Finally, strip the 802.11 header. * Finally, strip the 802.11 header.
*/ */
m = ieee80211_decap(vap, m, hdrspace); m = mesh_decap(vap, m, hdrspace, meshdrlen);
if (m == NULL) { if (m == NULL) {
/* XXX mask bit to check for both */ /* XXX mask bit to check for both */
/* don't count Null data frames as errors */ /* don't count Null data frames as errors */
@ -987,13 +1231,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
m = ieee80211_decap_amsdu(ni, m); m = ieee80211_decap_amsdu(ni, m);
if (m == NULL) if (m == NULL)
return IEEE80211_FC0_TYPE_DATA; return IEEE80211_FC0_TYPE_DATA;
} else { }
#ifdef IEEE80211_SUPPORT_SUPERG
m = ieee80211_decap_fastframe(vap, ni, m);
if (m == NULL)
return IEEE80211_FC0_TYPE_DATA;
#endif
}
ieee80211_deliver_data(vap, ni, m); ieee80211_deliver_data(vap, ni, m);
return type; return type;
case IEEE80211_FC0_TYPE_MGT: case IEEE80211_FC0_TYPE_MGT:
@ -1967,7 +2205,7 @@ mesh_peer_timeout_backoff(struct ieee80211_node *ni)
static __inline void static __inline void
mesh_peer_timeout_stop(struct ieee80211_node *ni) mesh_peer_timeout_stop(struct ieee80211_node *ni)
{ {
callout_stop(&ni->ni_mltimer); callout_drain(&ni->ni_mltimer);
} }
/* /*
@ -2401,6 +2639,7 @@ mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
return ENOMEM; return ENOMEM;
} }
ireq->i_len = len; ireq->i_len = len;
/* XXX M_WAIT? */
p = malloc(len, M_TEMP, M_NOWAIT | M_ZERO); p = malloc(len, M_TEMP, M_NOWAIT | M_ZERO);
if (p == NULL) if (p == NULL)
return ENOMEM; return ENOMEM;
@ -2418,6 +2657,7 @@ mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
imr->imr_metric = rt->rt_metric; imr->imr_metric = rt->rt_metric;
imr->imr_nhops = rt->rt_nhops; imr->imr_nhops = rt->rt_nhops;
imr->imr_lifetime = rt->rt_lifetime; imr->imr_lifetime = rt->rt_lifetime;
imr->imr_lastmseq = rt->rt_lastmseq;
off += sizeof(*imr); off += sizeof(*imr);
} }
MESH_RT_UNLOCK(ms); MESH_RT_UNLOCK(ms);
@ -2475,17 +2715,19 @@ mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
if (ireq->i_val != 0 || ireq->i_len > IEEE80211_MESHID_LEN) if (ireq->i_val != 0 || ireq->i_len > IEEE80211_MESHID_LEN)
return EINVAL; return EINVAL;
error = copyin(ireq->i_data, tmpmeshid, ireq->i_len); error = copyin(ireq->i_data, tmpmeshid, ireq->i_len);
if (error) if (error != 0)
break; break;
memset(ms->ms_id, 0, IEEE80211_NWID_LEN); memset(ms->ms_id, 0, IEEE80211_NWID_LEN);
ms->ms_idlen = ireq->i_len; ms->ms_idlen = ireq->i_len;
memcpy(ms->ms_id, tmpmeshid, ireq->i_len); memcpy(ms->ms_id, tmpmeshid, ireq->i_len);
error = ENETRESET;
break; break;
case IEEE80211_IOC_MESH_AP: case IEEE80211_IOC_MESH_AP:
if (ireq->i_val) if (ireq->i_val)
ms->ms_flags |= IEEE80211_MESHFLAGS_AP; ms->ms_flags |= IEEE80211_MESHFLAGS_AP;
else else
ms->ms_flags &= ~IEEE80211_MESHFLAGS_AP; ms->ms_flags &= ~IEEE80211_MESHFLAGS_AP;
error = ENETRESET;
break; break;
case IEEE80211_IOC_MESH_FWRD: case IEEE80211_IOC_MESH_FWRD:
if (ireq->i_val) if (ireq->i_val)
@ -2509,7 +2751,7 @@ mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
return EINVAL; return EINVAL;
error = copyin(ireq->i_data, &tmpaddr, error = copyin(ireq->i_data, &tmpaddr,
IEEE80211_ADDR_LEN); IEEE80211_ADDR_LEN);
if (!error) if (error == 0)
ieee80211_mesh_discover(vap, tmpaddr, NULL); ieee80211_mesh_discover(vap, tmpaddr, NULL);
break; break;
case IEEE80211_MESH_RTCMD_DELETE: case IEEE80211_MESH_RTCMD_DELETE:
@ -2521,13 +2763,19 @@ mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
break; break;
case IEEE80211_IOC_MESH_PR_METRIC: case IEEE80211_IOC_MESH_PR_METRIC:
error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto)); error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto));
if (!error) if (error == 0) {
return mesh_select_proto_metric(vap, tmpproto); error = mesh_select_proto_metric(vap, tmpproto);
if (error == 0)
error = ENETRESET;
}
break; break;
case IEEE80211_IOC_MESH_PR_PATH: case IEEE80211_IOC_MESH_PR_PATH:
error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto)); error = copyin(ireq->i_data, tmpproto, sizeof(tmpproto));
if (!error) if (error == 0) {
return mesh_select_proto_path(vap, tmpproto); error = mesh_select_proto_path(vap, tmpproto);
if (error == 0)
error = ENETRESET;
}
break; break;
default: default:
return ENOSYS; return ENOSYS;

View File

@ -359,8 +359,8 @@ struct ieee80211_meshcntl_ae10 {
uint8_t mc_flags; /* Address Extension 10 */ uint8_t mc_flags; /* Address Extension 10 */
uint8_t mc_ttl; /* TTL */ uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */ uint8_t mc_seq[4]; /* Sequence No. */
uint8_t mc_addr4[IEEE80211_ADDR_LEN];
uint8_t mc_addr5[IEEE80211_ADDR_LEN]; uint8_t mc_addr5[IEEE80211_ADDR_LEN];
uint8_t mc_addr6[IEEE80211_ADDR_LEN];
} __packed; } __packed;
struct ieee80211_meshcntl_ae11 { struct ieee80211_meshcntl_ae11 {
@ -372,22 +372,18 @@ struct ieee80211_meshcntl_ae11 {
uint8_t mc_addr6[IEEE80211_ADDR_LEN]; uint8_t mc_addr6[IEEE80211_ADDR_LEN];
} __packed; } __packed;
struct ieee80211req_mesh_route {
uint8_t imr_dest[IEEE80211_ADDR_LEN];
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
uint32_t imr_metric;
uint16_t imr_nhops;
uint32_t imr_lifetime;
};
#ifdef _KERNEL #ifdef _KERNEL
MALLOC_DECLARE(M_80211_MESH_RT); MALLOC_DECLARE(M_80211_MESH_RT);
struct ieee80211_mesh_route { struct ieee80211_mesh_route {
TAILQ_ENTRY(ieee80211_mesh_route) rt_next; TAILQ_ENTRY(ieee80211_mesh_route) rt_next;
struct timeval rt_crtime; /* creation time */
uint8_t rt_dest[IEEE80211_ADDR_LEN]; uint8_t rt_dest[IEEE80211_ADDR_LEN];
uint8_t rt_nexthop[IEEE80211_ADDR_LEN]; uint8_t rt_nexthop[IEEE80211_ADDR_LEN];
uint32_t rt_metric; /* path metric */ uint32_t rt_metric; /* path metric */
uint16_t rt_nhops; /* number of hops */ uint16_t rt_nhops; /* number of hops */
uint16_t rt_flags;
#define IEEE80211_MESHRT_FLAGS_VALID 0x01 /* patch discovery complete */
#define IEEE80211_MESHRT_FLAGS_PROXY 0x02 /* proxy entry */
uint32_t rt_lifetime; uint32_t rt_lifetime;
uint32_t rt_lastmseq; /* last seq# seen dest */ uint32_t rt_lastmseq; /* last seq# seen dest */
void *rt_priv; /* private data */ void *rt_priv; /* private data */
@ -411,8 +407,9 @@ struct ieee80211_mesh_proto_path {
void (*mpp_vdetach)(struct ieee80211vap *); void (*mpp_vdetach)(struct ieee80211vap *);
int (*mpp_newstate)(struct ieee80211vap *, int (*mpp_newstate)(struct ieee80211vap *,
enum ieee80211_state, int); enum ieee80211_state, int);
size_t mpp_privlen; /* size required in the routing table const size_t mpp_privlen; /* size required in the routing table
for private data */ for private data */
const struct timeval mpp_inact; /* inact. timeout for invalid routes */
}; };
/* /*
@ -454,6 +451,7 @@ struct ieee80211_mesh_state {
#define IEEE80211_MESHFLAGS_FWD 0x04 /* forward packets */ #define IEEE80211_MESHFLAGS_FWD 0x04 /* forward packets */
uint8_t ms_flags; uint8_t ms_flags;
struct mtx ms_rt_lock; struct mtx ms_rt_lock;
struct callout ms_cleantimer;
TAILQ_HEAD(, ieee80211_mesh_route) ms_routes; TAILQ_HEAD(, ieee80211_mesh_route) ms_routes;
struct ieee80211_mesh_proto_metric *ms_pmetric; struct ieee80211_mesh_proto_metric *ms_pmetric;
struct ieee80211_mesh_proto_path *ms_ppath; struct ieee80211_mesh_proto_path *ms_ppath;
@ -470,6 +468,8 @@ struct ieee80211_mesh_route *
void ieee80211_mesh_rt_del(struct ieee80211vap *, void ieee80211_mesh_rt_del(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]); const uint8_t [IEEE80211_ADDR_LEN]);
void ieee80211_mesh_rt_flush(struct ieee80211vap *); void ieee80211_mesh_rt_flush(struct ieee80211vap *);
void ieee80211_mesh_proxy_check(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
int ieee80211_mesh_register_proto_path(const int ieee80211_mesh_register_proto_path(const
struct ieee80211_mesh_proto_path *); struct ieee80211_mesh_proto_path *);
@ -493,8 +493,26 @@ void ieee80211_mesh_init_neighbor(struct ieee80211_node *,
const struct ieee80211_frame *, const struct ieee80211_frame *,
const struct ieee80211_scanparams *); const struct ieee80211_scanparams *);
/*
* Return non-zero if proxy operation is enabled.
*/
static __inline int
ieee80211_mesh_isproxyena(struct ieee80211vap *vap)
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
return (ms->ms_flags &
(IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_PORTAL)) != 0;
}
/*
* Process an outbound frame: if a path is known to the
* destination then return a reference to the next hop
* for immediate transmission. Otherwise initiate path
* discovery and, if possible queue the packet to be
* sent when path discovery completes.
*/
static __inline struct ieee80211_node * static __inline struct ieee80211_node *
ieee80211_mesh_discover(struct ieee80211vap *vap, ieee80211_mesh_discover(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m) const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
{ {
struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_state *ms = vap->iv_mesh;

View File

@ -242,19 +242,34 @@ ieee80211_start(struct ifnet *ifp)
} }
#ifdef IEEE80211_SUPPORT_MESH #ifdef IEEE80211_SUPPORT_MESH
} else { } else {
if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
/*
* Proxy station only if configured.
*/
if (!ieee80211_mesh_isproxyena(vap)) {
IEEE80211_DISCARD_MAC(vap,
IEEE80211_MSG_OUTPUT |
IEEE80211_MSG_MESH,
eh->ether_dhost, NULL,
"%s", "proxy not enabled");
vap->iv_stats.is_mesh_notproxy++;
ifp->if_oerrors++;
m_freem(m);
continue;
}
ieee80211_mesh_proxy_check(vap, eh->ether_shost);
}
ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
if (ni == NULL) { if (ni == NULL) {
/* /*
* NB: ieee80211_mesh_discover function * NB: ieee80211_mesh_discover holds/disposes
* holds/disposes frame * frame (e.g. queueing on path discovery).
* (e.g. queueing on path discovery).
*/ */
ifp->if_oerrors++; ifp->if_oerrors++;
continue; continue;
} }
} }
#endif #endif
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m->m_flags & M_PWR_SAV) == 0) { (m->m_flags & M_PWR_SAV) == 0) {
/* /*
@ -987,7 +1002,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
#ifdef IEEE80211_SUPPORT_MESH #ifdef IEEE80211_SUPPORT_MESH
struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_meshcntl_ae11 *mc; struct ieee80211_meshcntl_ae10 *mc;
#endif #endif
struct ether_header eh; struct ether_header eh;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
@ -1066,21 +1081,21 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
* w/ 4-address format and address extension mode 10 * w/ 4-address format and address extension mode 10
*/ */
is4addr = 0; /* NB: don't use, disable */ is4addr = 0; /* NB: don't use, disable */
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */
meshhdrsize = sizeof(struct ieee80211_meshcntl); meshhdrsize = sizeof(struct ieee80211_meshcntl);
/* XXX defines for AE modes */ /* XXX defines for AE modes */
/* XXX not right, need to check if from non-mesh-sta */
if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
hdrsize += IEEE80211_ADDR_LEN;
meshae = 0; meshae = 0;
} else else
meshae = 4; /* NB: pseudo */ meshae = 4; /* NB: pseudo */
} else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) { } else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
meshae = 1; meshae = 1;
meshhdrsize += 2*IEEE80211_ADDR_LEN; meshhdrsize += 1*IEEE80211_ADDR_LEN;
} else { } else {
meshae = 2; meshae = 2;
meshhdrsize += 3*IEEE80211_ADDR_LEN; meshhdrsize += 2*IEEE80211_ADDR_LEN;
} }
} else { } else {
#endif #endif
@ -1179,7 +1194,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
#ifdef IEEE80211_SUPPORT_MESH #ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_M_MBSS: case IEEE80211_M_MBSS:
/* NB: offset by hdrspace to deal with DATAPAD */ /* NB: offset by hdrspace to deal with DATAPAD */
mc = (struct ieee80211_meshcntl_ae11 *) mc = (struct ieee80211_meshcntl_ae10 *)
(mtod(m, uint8_t *) + hdrspace); (mtod(m, uint8_t *) + hdrspace);
switch (meshae) { switch (meshae) {
case 0: /* ucast, no proxy */ case 0: /* ucast, no proxy */
@ -1203,8 +1218,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
/* XXX not right, need MeshSA */ IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
mc->mc_flags = 1; mc->mc_flags = 1;
IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost); IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost);
qos = ((struct ieee80211_qosframe *) wh)->i_qos; qos = ((struct ieee80211_qosframe *) wh)->i_qos;
@ -1213,12 +1227,13 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
/* XXX not right, need MeshDA+MeshSA */ /* XXX not right, need MeshDA */
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); /* XXX assume are MeshSA */
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
mc->mc_flags = 2; mc->mc_flags = 2;
IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost);
IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost); IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost);
IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
break; break;
default: default: