int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); if (wl->scan.state != WL1271_SCAN_STATE_IDLE) return -EBUSY; wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; if (ssid_len && ssid) { wl->scan.ssid_len = ssid_len; memcpy(wl->scan.ssid, ssid, ssid_len); } else { wl->scan.ssid_len = 0; } wl->scan_vif = vif; wl->scan.req = req; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.failed = true; ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); wl1271_scan_stm(wl, vif); return 0; }
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { /* * cfg80211 should guarantee that we don't get more channels * than what we have registered. */ BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); if (wl->scan.state != WL1271_SCAN_STATE_IDLE) return -EBUSY; wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; if (ssid_len && ssid) { wl->scan.ssid_len = ssid_len; memcpy(wl->scan.ssid, ssid, ssid_len); } else { wl->scan.ssid_len = 0; } wl->scan.req = req; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); /* we assume failure so that timeout scenarios are handled correctly */ wl->scan.failed = true; ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); wl1271_scan_stm(wl); return 0; }
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { if (wl->scan.state != WL1271_SCAN_STATE_IDLE) return -EBUSY; wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; if (ssid_len && ssid) { wl->scan.ssid_len = ssid_len; memcpy(wl->scan.ssid, ssid, ssid_len); } else { wl->scan.ssid_len = 0; } wl->scan.req = req; wl->scan.scanned_ch = kzalloc(req->n_channels * sizeof(*wl->scan.scanned_ch), GFP_KERNEL); wl1271_scan_stm(wl); return 0; }
void wl1271_scan_stm(struct wl1271 *wl) { int ret = 0; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_DONE: wl->scan.failed = false; cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); break; default: wl1271_error("invalid scan state"); break; } if (ret < 0) { cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); } }
void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) { wl1271_scan_stm(wl, wlvif); }
int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_scan_request *req) { wl1271_scan_stm(wl, wlvif); return 0; }
void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret = 0; enum ieee80211_band band; u32 rate, mask; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: band = IEEE80211_BAND_2GHZ; mask = wlvif->bitrate_masks[band]; if (wl->scan.req->no_cck) { mask &= ~CONF_TX_CCK_RATES; if (!mask) mask = CONF_TX_RATE_MASK_BASIC_P2P; } rate = wl1271_tx_min_rate_get(wl, mask); ret = wl1271_scan_send(wl, wlvif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: band = IEEE80211_BAND_2GHZ; mask = wlvif->bitrate_masks[band]; if (wl->scan.req->no_cck) { mask &= ~CONF_TX_CCK_RATES; if (!mask) mask = CONF_TX_RATE_MASK_BASIC_P2P; } rate = wl1271_tx_min_rate_get(wl, mask); ret = wl1271_scan_send(wl, wlvif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: band = IEEE80211_BAND_5GHZ; rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); ret = wl1271_scan_send(wl, wlvif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: band = IEEE80211_BAND_5GHZ; rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); ret = wl1271_scan_send(wl, wlvif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_DONE: wl->scan.failed = false; cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); break; default: wl1271_error("invalid scan state"); break; } if (ret < 0) { cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); } }
void wl1271_scan_stm(struct wl1271 *wl) { int ret; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl1271_11a_enabled()) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_DONE: mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; wl->scan.state = WL1271_SCAN_STATE_IDLE; break; default: wl1271_error("invalid scan state"); break; } }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; bool beacon_loss = false; wl1271_event_mbox_dump(mbox); vector = le32_to_cpu(mbox->events_vector); vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); wl1271_scan_stm(wl); } /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { if (mbox->soft_gemini_sense_info) ieee80211_disable_dyn_ps(wl->vif); else ieee80211_enable_dyn_ps(wl->vif); } /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. * * As there's possibility that the driver disables PSM before receiving * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ if (vector & BSS_LOSE_EVENT_ID) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } if (vector & PS_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); if (wl->vif) wl1271_event_rssi_trigger(wl, mbox); } if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); return 0; }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool disconnect_sta = false; unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); vector = le32_to_cpu(mbox->events_vector); vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); wl1271_scan_stm(wl); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); wl1271_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); if (wl->sched_scanning) { ieee80211_sched_scan_stopped(wl->hw); wl->sched_scanning = false; } } if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) wl12xx_event_soft_gemini_sense(wl, mbox->soft_gemini_sense_info); if (vector & CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { int timeout = 0; if (mbox->change_auto_mode_timeout) timeout = 500; ieee80211_set_dyn_ps_timeout(wl->vif, timeout); } /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. * * As there's possibility that the driver disables PSM before receiving * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); if (wl->vif) wl1271_event_rssi_trigger(wl, mbox); } if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " "ba_allowed = 0x%x", mbox->rx_ba_allowed); wl->ba_allowed = !!mbox->rx_ba_allowed; if (wl->vif && !wl->ba_allowed) wl1271_stop_ba_event(wl); } if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " "channel_switch_status = 0x%x", mbox->channel_switch_status); /* * That event uses for two cases: * 1) channel switch complete with channel_switch_status=0 * 2) fixing beacon actual TSF with channel_switch_status=1 * calling chswitch_done only for the first option */ if (!mbox->channel_switch_status && test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) && (wl->vif)) ieee80211_chswitch_done(wl->vif, true); } if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); } if (vector & DISCONNECT_EVENT_COMPLETE_ID) wl1271_debug(DEBUG_EVENT, "disconnect event"); /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. */ if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); disconnect_sta = true; } if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); disconnect_sta = true; } if (is_ap && disconnect_sta) { u32 num_packets = wl->conf.tx.max_tx_retries; struct ieee80211_sta *sta; const u8 *addr; int h; for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); h < AP_MAX_LINKS; h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { if (!wl1271_is_active_sta(wl, h)) continue; addr = wl->links[h].addr; rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, addr); if (sta) { wl1271_debug(DEBUG_EVENT, "remove sta %d", h); ieee80211_report_low_ack(sta, num_packets); } rcu_read_unlock(); } } if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); return 0; }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool disconnect_sta = false; unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); vector = le32_to_cpu(mbox->events_vector); vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); wl1271_scan_stm(wl); } /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { if (mbox->soft_gemini_sense_info) ieee80211_disable_dyn_ps(wl->vif); else ieee80211_enable_dyn_ps(wl->vif); } /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. * * As there's possibility that the driver disables PSM before receiving * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); if (wl->vif) wl1271_event_rssi_trigger(wl, mbox); } if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); } /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. In STA mode we * report connection loss. */ if (vector & MAX_TX_RETRY_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); if (is_ap) { sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); disconnect_sta = true; } else { beacon_loss = true; } } if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); disconnect_sta = true; } if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); if (is_ap && disconnect_sta) { u32 num_packets = wl->conf.tx.max_tx_retries; struct ieee80211_sta *sta; const u8 *addr; int h; for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); h < AP_MAX_LINKS; h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { if (!wl1271_is_active_sta(wl, h)) continue; addr = wl->links[h].addr; rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, addr); if (sta) { wl1271_debug(DEBUG_EVENT, "remove sta %d", h); #if 0 ieee80211_report_low_ack(sta, num_packets); #endif } rcu_read_unlock(); } } return 0; }