Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Feb 2013 21:23:43 +0000 (UTC)
From:      Monthadar Al Jaberi <monthadar@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r246506 - head/sys/net80211
Message-ID:  <201302072123.r17LNiJI011118@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: monthadar
Date: Thu Feb  7 21:23:43 2013
New Revision: 246506
URL: http://svnweb.freebsd.org/changeset/base/246506

Log:
  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)

Modified:
  head/sys/net80211/ieee80211_hwmp.c
  head/sys/net80211/ieee80211_mesh.c
  head/sys/net80211/ieee80211_mesh.h

Modified: head/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- head/sys/net80211/ieee80211_hwmp.c	Thu Feb  7 21:23:03 2013	(r246505)
+++ head/sys/net80211/ieee80211_hwmp.c	Thu Feb  7 21:23:43 2013	(r246506)
@@ -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;
 	}
 }

Modified: head/sys/net80211/ieee80211_mesh.c
==============================================================================
--- head/sys/net80211/ieee80211_mesh.c	Thu Feb  7 21:23:03 2013	(r246505)
+++ head/sys/net80211/ieee80211_mesh.c	Thu Feb  7 21:23:43 2013	(r246506)
@@ -68,6 +68,8 @@ static int	mesh_select_proto_metric(stru
 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 ieee80
  */
 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_r
 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",
@@ -498,6 +506,48 @@ mesh_select_proto_metric(struct ieee8021
 #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, 
 	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, 
 		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 ieee
 	return 0;
 }
 
+/*
+ * Mesh Gate Announcement handling.
+ */
+static int
+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, struct mbuf *m)
+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
 		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(str
 		    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(struc
 		    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 ieee
 		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, 
 	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 
 			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)

Modified: head/sys/net80211/ieee80211_mesh.h
==============================================================================
--- head/sys/net80211/ieee80211_mesh.h	Thu Feb  7 21:23:03 2013	(r246505)
+++ head/sys/net80211/ieee80211_mesh.h	Thu Feb  7 21:23:43 2013	(r246506)
@@ -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
 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 *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302072123.r17LNiJI011118>