static void mesh_plink_timer(unsigned long data) { struct sta_info *sta; __le16 llid, plid, reason; struct ieee80211_sub_if_data *sdata; /* * This STA is valid because sta_info_destroy() will * del_timer_sync() this timer after having made sure * it cannot be readded (by deleting the plink.) */ sta = (struct sta_info *) data; if (sta->sdata->local->quiescing) { sta->plink_timer_was_running = true; return; } spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; spin_unlock_bh(&sta->lock); return; } mpl_dbg("Mesh plink timer for %pM fired on state %d\n", sta->sta.addr, sta->plink_state); reason = 0; llid = sta->llid; plid = sta->plid; sdata = sta->sdata; switch (sta->plink_state) { case PLINK_OPN_RCVD: case PLINK_OPN_SNT: /* retry timer */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", sta->sta.addr, sta->plink_retries, sta->plink_timeout); get_random_bytes(&rand, sizeof(u32)); sta->plink_timeout = sta->plink_timeout + rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid, 0, 0); break; } reason = cpu_to_le16(MESH_MAX_RETRIES); /* fall through on else */ case PLINK_CNF_RCVD: /* confirm timer */ if (!reason) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); sta->plink_state = PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; case PLINK_HOLDING: /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->lock); break; default: spin_unlock_bh(&sta->lock); break; } }
static void mesh_plink_timer(unsigned long data) { struct sta_info *sta; __le16 llid, plid, reason; struct ieee80211_sub_if_data *sdata; /* */ sta = (struct sta_info *) data; if (sta->sdata->local->quiescing) { sta->plink_timer_was_running = true; return; } spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; spin_unlock_bh(&sta->lock); return; } mpl_dbg("Mesh plink timer for %pM fired on state %d\n", sta->sta.addr, sta->plink_state); reason = 0; llid = sta->llid; plid = sta->plid; sdata = sta->sdata; switch (sta->plink_state) { case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_OPN_SNT: /* */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", sta->sta.addr, sta->plink_retries, sta->plink_timeout); get_random_bytes(&rand, sizeof(u32)); sta->plink_timeout = sta->plink_timeout + rand % sta->plink_timeout; ++sta->plink_retries; mod_plink_timer(sta, sta->plink_timeout); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, sta->sta.addr, llid, 0, 0); break; } reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES); /* */ case NL80211_PLINK_CNF_RCVD: /* */ if (!reason) reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, llid, plid, reason); break; case NL80211_PLINK_HOLDING: /* */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->lock); break; default: spin_unlock_bh(&sta->lock); break; } }