diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c index 6ab76d92a158..d2f63e5c383a 100644 --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -111,10 +111,20 @@ static int ieee80211_mesh_confirmtimeout = -1; SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, confirmtimeout, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_mesh_confirmtimeout, 0, ieee80211_sysctl_msecs_ticks, "I", "Confirm state timeout (msec)"); +static int ieee80211_mesh_backofftimeout = -1; +SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, backofftimeout, CTLTYPE_INT | CTLFLAG_RW, + &ieee80211_mesh_backofftimeout, 0, ieee80211_sysctl_msecs_ticks, "I", + "Backoff timeout (msec). This is to throutles peering forever when " + "not receving answer or is rejected by a neighbor"); static int ieee80211_mesh_maxretries = 2; SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_mesh_maxretries, 0, "Maximum retries during peer link establishment"); +static int ieee80211_mesh_maxholding = 2; +SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxholding, CTLTYPE_INT | CTLFLAG_RW, + &ieee80211_mesh_maxholding, 0, + "Maximum times we are allowed to transition to HOLDING state before " + "backinoff during peer link establishment"); static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -500,6 +510,7 @@ ieee80211_mesh_init(void) ieee80211_mesh_retrytimeout = msecs_to_ticks(40); ieee80211_mesh_holdingtimeout = msecs_to_ticks(40); ieee80211_mesh_confirmtimeout = msecs_to_ticks(40); + ieee80211_mesh_backofftimeout = msecs_to_ticks(5000); /* * Register action frame handlers. @@ -1696,7 +1707,6 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, } /* * Automatically peer with discovered nodes if possible. - * XXX backoff on repeated failure */ if (ni != vap->iv_bss && (ms->ms_flags & IEEE80211_MESHFLAGS_AP)) { @@ -1705,6 +1715,10 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, { uint16_t args[1]; + /* Wait for backoff callout to reset counter */ + if (ni->ni_mlhcnt >= ieee80211_mesh_maxholding) + return; + ni->ni_mlpid = mesh_generateid(vap); if (ni->ni_mlpid == 0) return; @@ -2578,6 +2592,15 @@ mesh_peer_timeout_stop(struct ieee80211_node *ni) callout_drain(&ni->ni_mltimer); } +static void +mesh_peer_backoff_cb(void *arg) +{ + struct ieee80211_node *ni = (struct ieee80211_node *)arg; + + /* After backoff timeout, try to peer automatically again. */ + ni->ni_mlhcnt = 0; +} + /* * Mesh Peer Link Management FSM timeout handling. */ @@ -2625,6 +2648,11 @@ mesh_peer_timeout_cb(void *arg) mesh_peer_timeout_setup(ni); break; case IEEE80211_NODE_MESH_HOLDING: + ni->ni_mlhcnt++; + if (ni->ni_mlhcnt >= ieee80211_mesh_maxholding) + callout_reset(&ni->ni_mlhtimer, + ieee80211_mesh_backofftimeout, + mesh_peer_backoff_cb, ni); mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE); break; } @@ -2889,6 +2917,7 @@ ieee80211_mesh_node_init(struct ieee80211vap *vap, struct ieee80211_node *ni) { ni->ni_flags |= IEEE80211_NODE_QOS; callout_init(&ni->ni_mltimer, CALLOUT_MPSAFE); + callout_init(&ni->ni_mlhtimer, CALLOUT_MPSAFE); } /* @@ -2901,6 +2930,7 @@ ieee80211_mesh_node_cleanup(struct ieee80211_node *ni) struct ieee80211_mesh_state *ms = vap->iv_mesh; callout_drain(&ni->ni_mltimer); + callout_drain(&ni->ni_mlhtimer); /* NB: short-circuit callbacks after mesh_vdetach */ if (vap->iv_mesh != NULL) ms->ms_ppath->mpp_peerdown(ni); diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 48eae2d7c6cc..bb31136892d6 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -204,6 +204,8 @@ struct ieee80211_node { struct callout ni_mltimer; /* link mesh timer */ uint8_t ni_mlrcnt; /* link mesh retry counter */ uint8_t ni_mltval; /* link mesh timer value */ + struct callout ni_mlhtimer; /* link mesh backoff timer */ + uint8_t ni_mlhcnt; /* link mesh holding counter */ /* 11n state */ uint16_t ni_htcap; /* HT capabilities */