Date: Thu, 7 May 2009 20:39:23 +0000 (UTC) From: Rui Paulo <rpaulo@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r191901 - projects/mesh11s/sys/net80211 Message-ID: <200905072039.n47KdNgr067584@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rpaulo Date: Thu May 7 20:39:23 2009 New Revision: 191901 URL: http://svn.freebsd.org/changeset/base/191901 Log: Checkpoint mesh peer link handling. Sponsored by: The FreeBSD Foundation Modified: projects/mesh11s/sys/net80211/ieee80211_mesh.c projects/mesh11s/sys/net80211/ieee80211_node.c projects/mesh11s/sys/net80211/ieee80211_node.h projects/mesh11s/sys/net80211/ieee80211_output.c Modified: projects/mesh11s/sys/net80211/ieee80211_mesh.c ============================================================================== --- projects/mesh11s/sys/net80211/ieee80211_mesh.c Thu May 7 20:28:06 2009 (r191900) +++ projects/mesh11s/sys/net80211/ieee80211_mesh.c Thu May 7 20:39:23 2009 (r191901) @@ -69,6 +69,32 @@ static int mesh_input(struct ieee80211_n static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, int, int, uint32_t); static void mesh_recv_action(struct ieee80211_node *, struct mbuf *); +static void mesh_peer_timeout(void *); + +int ieee80211_mesh_retrytimeout = 40; /* 40 miliseconds */ +#define RETRY_TIMEOUT msecs_to_ticks(ieee80211_mesh_retrytimeout) +int ieee80211_mesh_maxretries = 60; +#define MESH_SET_TIMEOUT(xni) \ +do { \ + xni->ni_mtimerboff = RETRY_TIMEOUT; \ + callout_reset(&xni->ni_mtimer, RETRY_TIMEOUT, mesh_peer_timeout, xni); \ +} while (0) +/* + * Same as above but backoffs timer statisically 50%. + * XXX: wrong arc4random usage. + */ +#define MESH_SET_TIMEOUT_BACKOFF(xni) \ +do { \ + xni->ni_mtimerboff = xni->ni_mtimerboff + \ + ((arc4random() & 0xff) % xni->ni_mtimerboff); \ + callout_reset(&xni->ni_mtimer, RETRY_TIMEOUT, mesh_peer_timeout, xni); \ +} while (0) + +/* unalligned little endian access */ +#define LE_READ_2(p) \ + ((uint16_t) \ + ((((const uint8_t *)(p))[0] ) | \ + (((const uint8_t *)(p))[1] << 8))) void ieee80211_mesh_attach(struct ieee80211com *ic) @@ -383,31 +409,14 @@ mesh_recv_mgmt(struct ieee80211_node *ni if ((scan.capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) == 0 && !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr) && IEEE80211_ADDR_EQ(wh->i_addr3, zerobssid)) { + uint16_t args[4]; /* * Create a new entry in the neighbor table. */ ni = ieee80211_add_neighbor(vap, wh, &scan); - } else { /* - * Record tsf for potential resync. + * Try to peer with this node. */ - memcpy(ni->ni_tstamp.data, scan.tstamp, - sizeof(ni->ni_tstamp)); - } - if (ni != NULL) { - IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); - ni->ni_noise = noise; - ni->ni_rstamp = rstamp; - } - - /* - * If it's a beacon for our mesh and we haven't already - * peered with this node, send him a mgmt frame with - * peer link IE. - */ - if (ni->ni_peerstate == IEEE80211_NODE_MESH_IDLE) { - uint16_t args[4]; - get_random_bytes(&ni->ni_plid, 2); ni->ni_peerstate = IEEE80211_NODE_MESH_OPENSNT; IEEE80211_NOTE(vap, @@ -418,8 +427,15 @@ mesh_recv_mgmt(struct ieee80211_node *ni ieee80211_send_action(ni, IEEE80211_ACTION_CAT_MESHPEERING, IEEE80211_ACTION_MESHPEERING_OPEN, args); - /* XXX setup timeout1 */ + ni->ni_mrcount = 0; + MESH_SET_TIMEOUT(ni); } + if (ni != NULL) { + IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); + ni->ni_noise = noise; + ni->ni_rstamp = rstamp; + } + break; } case IEEE80211_FC0_SUBTYPE_PROBE_REQ: @@ -441,13 +457,12 @@ mesh_recv_mgmt(struct ieee80211_node *ni vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return; } - /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates - * [tlv] Mesh ID + * [tlv] mesh id */ ssid = meshid = rates = xrates = NULL; sfrm = frm; @@ -522,6 +537,7 @@ mesh_recv_mgmt(struct ieee80211_node *ni break; } } + static void mesh_recv_action(struct ieee80211_node *ni, struct mbuf *m0) { @@ -540,7 +556,15 @@ mesh_recv_action(struct ieee80211_node * frm += sizeof(ia); efrm = mtod(m0, uint8_t *) + m0->m_len; - /* XXX explain frame format */ + /* + * We received an action for an unknown neighbor. + * XXX: wait for it to beacon or create ieee80211_node? + */ + if (ni == vap->iv_bss) { + return; + } + + meshid = NULL; meshpeer = NULL; meshconf = NULL; @@ -555,6 +579,9 @@ mesh_recv_action(struct ieee80211_node * break; case IEEE80211_ELEMID_MESHPEER: meshpeer = (struct ieee80211_meshpeer_ie *) frm; + meshpeer->peer_llinkid = LE_READ_2(&meshpeer->peer_llinkid); + meshpeer->peer_linkid = LE_READ_2(&meshpeer->peer_linkid); + meshpeer->peer_rcode = LE_READ_2(&meshpeer->peer_rcode); break; } frm += frm[1] + 2; @@ -570,15 +597,19 @@ mesh_recv_action(struct ieee80211_node * vap->iv_stats.is_rx_mgtdiscard++; return; } + switch (ia->ia_category) { + /* + * Mesh Peer Link Management Finite State Machine handling. + */ case IEEE80211_ACTION_CAT_MESHPEERING: switch (ia->ia_action) { case IEEE80211_ACTION_MESHPEERING_OPEN: IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni, - "%s", "recv PEER OPEN"); + "recv PEER OPEN, lid 0x%x", meshpeer->peer_llinkid); switch (ni->ni_peerstate) { - case IEEE80211_NODE_MESH_IDLE: + case IEEE80211_NODE_MESH_IDLE: ni->ni_peerstate = IEEE80211_NODE_MESH_OPENRCV; IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, @@ -591,7 +622,7 @@ mesh_recv_action(struct ieee80211_node * ieee80211_send_action(ni, IEEE80211_ACTION_CAT_MESHPEERING, IEEE80211_ACTION_MESHPEERING_OPEN, args); - /* ... and confirm the link. */ + /* ...and confirm the link. */ args[0] = ni->ni_plid; args[1] = ni->ni_llid; ieee80211_send_action(ni, @@ -610,6 +641,7 @@ mesh_recv_action(struct ieee80211_node * break; case IEEE80211_NODE_MESH_OPENSNT: ni->ni_peerstate = IEEE80211_NODE_MESH_OPENRCV; + ni->ni_llid = meshpeer->peer_llinkid; IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, ni, "peer link: switching to state %d", @@ -635,12 +667,28 @@ mesh_recv_action(struct ieee80211_node * IEEE80211_ACTION_MESHPEERING_CONFIRM, args); /* clear timeoutC */ break; + case IEEE80211_NODE_MESH_ESTABLISHED: + args[0] = ni->ni_plid; + args[1] = ni->ni_llid; + ieee80211_send_action(ni, + IEEE80211_ACTION_CAT_MESHPEERING, + IEEE80211_ACTION_MESHPEERING_CONFIRM, args); + break; + case IEEE80211_NODE_MESH_HOLDING: + args[0] = ni->ni_llid; + args[1] = ni->ni_plid; + args[2] = IEEE80211_REASON_MESH_MAX_RETRIES; + ieee80211_send_action(ni, + IEEE80211_ACTION_CAT_MESHPEERING, + IEEE80211_ACTION_MESHPEERING_CLOSE, args); + break; } break; case IEEE80211_ACTION_MESHPEERING_CONFIRM: IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni, - "%s", "recv PEER CONFIRM"); + "recv PEER CONFIRM, local id 0x%x, peer id 0x%x", + meshpeer->peer_llinkid, meshpeer->peer_linkid); switch (ni->ni_peerstate) { case IEEE80211_NODE_MESH_OPENRCV: ni->ni_peerstate = IEEE80211_NODE_MESH_ESTABLISHED; @@ -648,7 +696,6 @@ mesh_recv_action(struct ieee80211_node * IEEE80211_MSG_MESH, ni, "peer link: switching to state %d", ni->ni_peerstate); - /* clear timeoutR */ break; case IEEE80211_NODE_MESH_OPENSNT: ni->ni_peerstate = IEEE80211_NODE_MESH_CONFIRMRECV; @@ -657,14 +704,37 @@ mesh_recv_action(struct ieee80211_node * ni, "peer link: switching to state %d", ni->ni_peerstate); break; + case IEEE80211_NODE_MESH_HOLDING: + args[0] = ni->ni_llid; + args[1] = ni->ni_plid; + args[2] = IEEE80211_REASON_MESH_MAX_RETRIES; + ieee80211_send_action(ni, + IEEE80211_ACTION_CAT_MESHPEERING, + IEEE80211_ACTION_MESHPEERING_CLOSE, args); + break; default: - IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, wh, NULL, "received confirm in invalid " "state %d", ni->ni_peerstate); vap->iv_stats.is_rx_mgtdiscard++; } + break; + case IEEE80211_ACTION_MESHPEERING_CLOSE: + IEEE80211_NOTE(vap, + IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni, + "%s", "recv PEER CLOSE"); + switch (ni->ni_peerstate) { + case IEEE80211_NODE_MESH_OPENRCV: + ni->ni_peerstate = IEEE80211_NODE_MESH_HOLDING; + MESH_SET_TIMEOUT(ni); + break; + case IEEE80211_NODE_MESH_OPENSNT: + break; + case IEEE80211_NODE_MESH_HOLDING: + break; + } + break; } break; default: @@ -675,6 +745,50 @@ mesh_recv_action(struct ieee80211_node * } /* + * Mesh Peer Link Management FSM timeout handling. + */ +static void +mesh_peer_timeout(void *arg) +{ + struct ieee80211_node *ni = (struct ieee80211_node *)arg; + struct ieee80211vap *vap = ni->ni_vap; + uint16_t args[4]; + + IEEE80211_NOTE(vap, + IEEE80211_MSG_MESH, + ni, "mesh link timeout, state %d, retry counter %d", + ni->ni_peerstate, ni->ni_mrcount); + + switch (ni->ni_peerstate) { + case IEEE80211_NODE_MESH_OPENSNT: + case IEEE80211_NODE_MESH_OPENRCV: + if (ni->ni_mrcount == ieee80211_mesh_maxretries) { + args[0] = ni->ni_plid; + args[2] = IEEE80211_REASON_MESH_MAX_RETRIES; + ieee80211_send_action(ni, + IEEE80211_ACTION_CAT_MESHPEERING, + IEEE80211_ACTION_MESHPEERING_CLOSE, args); + ni->ni_mrcount = 0; + ni->ni_peerstate = IEEE80211_NODE_MESH_HOLDING; + MESH_SET_TIMEOUT(ni); + } else { + args[0] = ni->ni_plid; + ieee80211_send_action(ni, + IEEE80211_ACTION_CAT_MESHPEERING, + IEEE80211_ACTION_MESHPEERING_OPEN, args); + ni->ni_mrcount++; + MESH_SET_TIMEOUT_BACKOFF(ni); + } + break; + case IEEE80211_NODE_MESH_CONFIRMRECV: + + break; + case IEEE80211_NODE_MESH_HOLDING: + break; + } +} + +/* * Parse a MESH ID ie on station join. */ void Modified: projects/mesh11s/sys/net80211/ieee80211_node.c ============================================================================== --- projects/mesh11s/sys/net80211/ieee80211_node.c Thu May 7 20:28:06 2009 (r191900) +++ projects/mesh11s/sys/net80211/ieee80211_node.c Thu May 7 20:39:23 2009 (r191901) @@ -1384,6 +1384,8 @@ ieee80211_init_neighbor(struct ieee80211 const struct ieee80211_frame *wh, const struct ieee80211_scanparams *sp) { + struct ieee80211vap *vap = ni->ni_vap; + ni->ni_esslen = sp->ssid[1]; memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); @@ -1395,6 +1397,11 @@ ieee80211_init_neighbor(struct ieee80211 ni->ni_fhindex = sp->fhindex; ni->ni_erp = sp->erp; ni->ni_timoff = sp->timoff; + if (vap->iv_opmode == IEEE80211_M_MBSS) { + ni->ni_meshidlen = sp->meshid[1]; + memcpy(ni->ni_meshid, sp->meshid + 2, sp->meshid[1]); + callout_init(&ni->ni_mtimer, CALLOUT_MPSAFE); + } if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) { ieee80211_ies_expand(&ni->ni_ies); Modified: projects/mesh11s/sys/net80211/ieee80211_node.h ============================================================================== --- projects/mesh11s/sys/net80211/ieee80211_node.h Thu May 7 20:28:06 2009 (r191900) +++ projects/mesh11s/sys/net80211/ieee80211_node.h Thu May 7 20:39:23 2009 (r191901) @@ -185,6 +185,9 @@ struct ieee80211_node { int8_t ni_peerstate; /* Mesh Peering state */ uint16_t ni_llid; /* local link ID */ uint16_t ni_plid; /* peer link ID */ + struct callout ni_mtimer; /* mesh timer */ + uint8_t ni_mrcount; /* mesh retry counter */ + uint8_t ni_mtimerboff; /* mesh timer backoff value */ /* 11n state */ uint16_t ni_htcap; /* HT capabilities */ Modified: projects/mesh11s/sys/net80211/ieee80211_output.c ============================================================================== --- projects/mesh11s/sys/net80211/ieee80211_output.c Thu May 7 20:28:06 2009 (r191900) +++ projects/mesh11s/sys/net80211/ieee80211_output.c Thu May 7 20:39:23 2009 (r191901) @@ -663,6 +663,17 @@ ieee80211_send_action(struct ieee80211_n case IEEE80211_ACTION_CAT_MESHPEERING: rs = ieee80211_get_suprates(ic, ic->ic_curchan); switch (action) { + /* + * mesh peer open action frame format: + * [1] action + * [1] category + * [2] capabilities + * [tlv] rates + * [tlv] xrates + * [tlv] mesh id + * [tlv] mesh conf + * [tlv] mesh peer link mgmt + */ case IEEE80211_ACTION_MESHPEERING_OPEN: IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni, @@ -675,6 +686,19 @@ ieee80211_send_action(struct ieee80211_n frm = ieee80211_add_meshpeer(frm, IEEE80211_MESH_PEER_LINK_OPEN, args[0], 0, 0); break; + /* + * mesh peer confirm action frame format: + * [1] action + * [1] category + * [2] capabilities + * [2] status code + * [2] association id (0) + * [tlv] rates + * [tlv] xrates + * [tlv] mesh id + * [tlv] mesh conf + * [tlv] mesh peer link mgmt + */ case IEEE80211_ACTION_MESHPEERING_CONFIRM: IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni, @@ -691,6 +715,14 @@ ieee80211_send_action(struct ieee80211_n IEEE80211_MESH_PEER_LINK_CONFIRM, args[0], args[1], 0); break; + /* + * mesh peer close action frame format: + * [1] action + * [1] category + * [2] reason code + * [tlv] mesh id + * [tlv] mesh peer link mgmt + */ case IEEE80211_ACTION_MESHPEERING_CLOSE: IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905072039.n47KdNgr067584>