Mesh update: add base Mesh Gate functionality.

A Mesh Gate should transmit a Mesh Action frame containing
ieee80211_meshgann_ie as its only information element periodically
every ieee80211_mesh_gateint ms. Unless the mesh gate is also configure
as a ROOT, then these frames should not be send.
This is according to 802.11 2012 standard;

* Introduce new SYSCTL net.wlan.mesh.gateint, with 10s default;
* Add two new functions mesh_gatemode_setup and mesh_gatemode_cb. This
  is similar to how HWMP setups up a callout;
* Add two new action handlers mesh_recv_action_meshgate and
  mesh_send_action_meshgate;
* Added ieee80211_add_meshgate to ieee80211_mesh.h;
* Modified mesh_send_action to look similar to hwmp_send_action. This is
  because we need to send out broadcast management frames.
* Introduced a new flag for mesh state IEEE80211_MESHFLAGS_ROOT. This flag
  is now set by HWMP code when a mesh STA is configured as a ROOT. This
  is then checked by mesh_gatemode_cb before scheduling a new callout;
* Added to new field to ieee80211_mesh_state:
    + struct callout                  ms_gatetimer
    + ieee80211_mesh_seq              ms_gateseq;

Approved by:	adrian (mentor)
This commit is contained in:
Monthadar Al Jaberi 2013-02-07 21:23:43 +00:00
parent 8904a305ae
commit ed0b544066
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246506
3 changed files with 196 additions and 10 deletions

View File

@ -805,19 +805,23 @@ static void
hwmp_rootmode_setup(struct ieee80211vap *vap)
{
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
switch (hs->hs_rootmode) {
case IEEE80211_HWMP_ROOTMODE_DISABLED:
callout_drain(&hs->hs_roottimer);
ms->ms_flags &= ~IEEE80211_MESHFLAGS_ROOT;
break;
case IEEE80211_HWMP_ROOTMODE_NORMAL:
case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
hwmp_rootmode_cb, vap);
ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
break;
case IEEE80211_HWMP_ROOTMODE_RANN:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
hwmp_rootmode_rann_cb, vap);
ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
break;
}
}

View File

@ -68,6 +68,8 @@ static int mesh_select_proto_metric(struct ieee80211vap *, const char *);
static void mesh_vattach(struct ieee80211vap *);
static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void mesh_rt_cleanup_cb(void *);
static void mesh_gatemode_setup(struct ieee80211vap *);
static void mesh_gatemode_cb(void *);
static void mesh_linkchange(struct ieee80211_node *,
enum ieee80211_mesh_mlstate);
static void mesh_checkid(void *, struct ieee80211_node *);
@ -99,6 +101,10 @@ uint32_t mesh_airtime_calc(struct ieee80211_node *);
*/
static SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0,
"IEEE 802.11s parameters");
static int ieee80211_mesh_gateint = -1;
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, gateint, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_gateint, 0, ieee80211_sysctl_msecs_ticks, "I",
"mesh gate interval (ms)");
static int ieee80211_mesh_retrytimeout = -1;
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, retrytimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_retrytimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
@ -133,11 +139,13 @@ static ieee80211_recv_action_func mesh_recv_action_meshpeering_open;
static ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm;
static ieee80211_recv_action_func mesh_recv_action_meshpeering_close;
static ieee80211_recv_action_func mesh_recv_action_meshlmetric;
static ieee80211_recv_action_func mesh_recv_action_meshgate;
static ieee80211_send_action_func mesh_send_action_meshpeering_open;
static ieee80211_send_action_func mesh_send_action_meshpeering_confirm;
static ieee80211_send_action_func mesh_send_action_meshpeering_close;
static ieee80211_send_action_func mesh_send_action_meshlmetric;
static ieee80211_send_action_func mesh_send_action_meshgate;
static const struct ieee80211_mesh_proto_metric mesh_metric_airtime = {
.mpm_descr = "AIRTIME",
@ -497,6 +505,48 @@ mesh_select_proto_metric(struct ieee80211vap *vap, const char *name)
}
#undef N
static void
mesh_gatemode_setup(struct ieee80211vap *vap)
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
/*
* NB: When a mesh gate is running as a ROOT it shall
* not send out periodic GANNs but instead mark the
* mesh gate flag for the corresponding proactive PREQ
* and RANN frames.
*/
if (ms->ms_flags & IEEE80211_MESHFLAGS_ROOT ||
(ms->ms_flags & IEEE80211_MESHFLAGS_GATE) == 0) {
callout_drain(&ms->ms_gatetimer);
return ;
}
callout_reset(&ms->ms_gatetimer, ieee80211_mesh_gateint,
mesh_gatemode_cb, vap);
}
static void
mesh_gatemode_cb(void *arg)
{
struct ieee80211vap *vap = (struct ieee80211vap *)arg;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_meshgann_ie gann;
IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, vap->iv_bss,
"%s", "send broadcast GANN");
gann.gann_flags = 0; /* Reserved */
gann.gann_hopcount = 0;
gann.gann_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(gann.gann_addr, vap->iv_myaddr);
gann.gann_seq = ms->ms_gateseq++;
gann.gann_interval = ieee80211_mesh_gateint;
ieee80211_send_action(vap->iv_bss, IEEE80211_ACTION_CAT_MESH,
IEEE80211_ACTION_MESH_GANN, &gann);
mesh_gatemode_setup(vap);
}
static void
ieee80211_mesh_init(void)
{
@ -507,6 +557,7 @@ ieee80211_mesh_init(void)
/*
* Setup mesh parameters that depends on the clock frequency.
*/
ieee80211_mesh_gateint = msecs_to_ticks(10000);
ieee80211_mesh_retrytimeout = msecs_to_ticks(40);
ieee80211_mesh_holdingtimeout = msecs_to_ticks(40);
ieee80211_mesh_confirmtimeout = msecs_to_ticks(40);
@ -526,6 +577,8 @@ ieee80211_mesh_init(void)
mesh_recv_action_meshpeering_close);
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
IEEE80211_ACTION_MESH_LMETRIC, mesh_recv_action_meshlmetric);
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
IEEE80211_ACTION_MESH_GANN, mesh_recv_action_meshgate);
ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_OPEN,
@ -539,6 +592,9 @@ ieee80211_mesh_init(void)
ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
IEEE80211_ACTION_MESH_LMETRIC,
mesh_send_action_meshlmetric);
ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
IEEE80211_ACTION_MESH_GANN,
mesh_send_action_meshgate);
/*
* Register Airtime Link Metric.
@ -617,6 +673,8 @@ mesh_vattach(struct ieee80211vap *vap)
TAILQ_INIT(&ms->ms_routes);
mtx_init(&ms->ms_rt_lock, "MBSS", "802.11s routing table", MTX_DEF);
callout_init(&ms->ms_cleantimer, CALLOUT_MPSAFE);
callout_init(&ms->ms_gatetimer, CALLOUT_MPSAFE);
ms->ms_gateseq = 0;
mesh_select_proto_metric(vap, "AIRTIME");
KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
mesh_select_proto_path(vap, "HWMP");
@ -645,8 +703,10 @@ mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
if (ostate != IEEE80211_S_SCAN)
ieee80211_cancel_scan(vap); /* background scan */
ni = vap->iv_bss; /* NB: no reference held */
if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) {
callout_drain(&ms->ms_cleantimer);
callout_drain(&ms->ms_gatetimer);
}
switch (nstate) {
case IEEE80211_S_INIT:
switch (ostate) {
@ -771,6 +831,7 @@ mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
ieee80211_node_authorize(vap->iv_bss);
callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
mesh_rt_cleanup_cb, vap);
mesh_gatemode_setup(vap);
break;
default:
break;
@ -2300,19 +2361,77 @@ mesh_recv_action_meshlmetric(struct ieee80211_node *ni,
return 0;
}
/*
* Mesh Gate Announcement handling.
*/
static int
mesh_send_action(struct ieee80211_node *ni, struct mbuf *m)
mesh_recv_action_meshgate(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_mesh_route *rt_gate;
const struct ieee80211_meshgann_ie *ie =
(const struct ieee80211_meshgann_ie *)
(frm+2); /* action + code */
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, ie->gann_addr,
"%s", "received GANN from meshgate");
rt_gate = ieee80211_mesh_rt_find(vap, ie->gann_addr);
if (rt_gate != NULL &&
rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
rt_gate->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
return 0;
}
static int
mesh_send_action(struct ieee80211_node *ni,
const uint8_t sa[IEEE80211_ADDR_LEN],
const uint8_t da[IEEE80211_ADDR_LEN],
struct mbuf *m)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_bpf_params params;
struct ieee80211_frame *wh;
KASSERT(ni != NULL, ("null node"));
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
"block %s frame in CAC state", "Mesh action");
vap->iv_stats.is_tx_badstate++;
ieee80211_free_node(ni);
m_freem(m);
return EIO; /* XXX */
}
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
if (m == NULL) {
ieee80211_free_node(ni);
return ENOMEM;
}
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
IEEE80211_NONQOS_TID, sa, da, sa);
m->m_flags |= M_ENCAP; /* mark encapsulated */
memset(&params, 0, sizeof(params));
params.ibp_pri = WME_AC_VO;
params.ibp_rate0 = ni->ni_txparms->mgmtrate;
/* XXX ucast/mcast */
params.ibp_try0 = ni->ni_txparms->maxretry;
if (IEEE80211_IS_MULTICAST(da))
params.ibp_try0 = 1;
else
params.ibp_try0 = ni->ni_txparms->maxretry;
params.ibp_power = ni->ni_txpower;
return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
&params);
IEEE80211_NODE_STAT(ni, tx_mgmt);
return ic->ic_raw_xmit(ni, m, &params);
}
#define ADDSHORT(frm, v) do { \
@ -2380,7 +2499,7 @@ mesh_send_action_meshpeering_open(struct ieee80211_node *ni,
frm = ieee80211_add_meshpeer(frm, IEEE80211_ACTION_MESHPEERING_OPEN,
args[0], 0, 0);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return mesh_send_action(ni, m);
return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@ -2448,7 +2567,7 @@ mesh_send_action_meshpeering_confirm(struct ieee80211_node *ni,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args[0], args[1], 0);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return mesh_send_action(ni, m);
return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@ -2497,7 +2616,7 @@ mesh_send_action_meshpeering_close(struct ieee80211_node *ni,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args[0], args[1], args[2]);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return mesh_send_action(ni, m);
return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@ -2545,7 +2664,46 @@ mesh_send_action_meshlmetric(struct ieee80211_node *ni,
frm = ieee80211_add_meshlmetric(frm,
ie->lm_flags, ie->lm_metric);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return mesh_send_action(ni, m);
return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
return ENOMEM;
}
}
static int
mesh_send_action_meshgate(struct ieee80211_node *ni,
int category, int action, void *arg0)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_meshgann_ie *ie = arg0;
struct mbuf *m;
uint8_t *frm;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
ieee80211_ref_node(ni);
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
sizeof(uint16_t) + /* action+category */
IEEE80211_MESHGANN_BASE_SZ
);
if (m != NULL) {
/*
* mesh link metric
* [1] category
* [1] action
* [tlv] mesh gate annoucement
*/
*frm++ = category;
*frm++ = action;
frm = ieee80211_add_meshgate(frm, ie);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return mesh_send_action(ni, vap->iv_myaddr, broadcastaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@ -2909,6 +3067,24 @@ ieee80211_add_meshlmetric(uint8_t *frm, uint8_t flags, uint32_t metric)
ADDWORD(frm, metric);
return frm;
}
/*
* Add a Mesh Gate Announcement IE to a frame.
*/
uint8_t *
ieee80211_add_meshgate(uint8_t *frm, struct ieee80211_meshgann_ie *ie)
{
*frm++ = IEEE80211_ELEMID_MESHGANN; /* ie */
*frm++ = IEEE80211_MESHGANN_BASE_SZ; /* len */
*frm++ = ie->gann_flags;
*frm++ = ie->gann_hopcount;
*frm++ = ie->gann_ttl;
IEEE80211_ADDR_COPY(frm, ie->gann_addr);
frm += 6;
ADDWORD(frm, ie->gann_seq);
ADDSHORT(frm, ie->gann_interval);
return frm;
}
#undef ADDSHORT
#undef ADDWORD
@ -3113,6 +3289,7 @@ mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
ms->ms_flags |= IEEE80211_MESHFLAGS_FWD;
else
ms->ms_flags &= ~IEEE80211_MESHFLAGS_FWD;
mesh_gatemode_setup(vap);
break;
case IEEE80211_IOC_MESH_GATE:
if (ireq->i_val)

View File

@ -502,9 +502,12 @@ struct ieee80211_mesh_state {
#define IEEE80211_MESHFLAGS_AP 0x01 /* accept peers */
#define IEEE80211_MESHFLAGS_GATE 0x02 /* mesh gate role */
#define IEEE80211_MESHFLAGS_FWD 0x04 /* forward packets */
#define IEEE80211_MESHFLAGS_ROOT 0x08 /* configured as root */
uint8_t ms_flags;
struct mtx ms_rt_lock;
struct callout ms_cleantimer;
struct callout ms_gatetimer;
ieee80211_mesh_seq ms_gateseq;
TAILQ_HEAD(, ieee80211_mesh_route) ms_routes;
struct ieee80211_mesh_proto_metric *ms_pmetric;
struct ieee80211_mesh_proto_path *ms_ppath;
@ -537,6 +540,8 @@ uint8_t * ieee80211_add_meshconf(uint8_t *, struct ieee80211vap *);
uint8_t * ieee80211_add_meshpeer(uint8_t *, uint8_t, uint16_t, uint16_t,
uint16_t);
uint8_t * ieee80211_add_meshlmetric(uint8_t *, uint8_t, uint32_t);
uint8_t * ieee80211_add_meshgate(uint8_t *,
struct ieee80211_meshgann_ie *);
void ieee80211_mesh_node_init(struct ieee80211vap *,
struct ieee80211_node *);