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(¶ms, 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, - ¶ms); + + IEEE80211_NODE_STAT(ni, tx_mgmt); + + return ic->ic_raw_xmit(ni, m, ¶ms); } #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>