int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; ret = wl1271_ap_init_deauth_template(wl, wlvif); if (ret < 0) return ret; ret = wl1271_ap_init_null_template(wl, vif); if (ret < 0) return ret; ret = wl1271_ap_init_qos_null_template(wl, vif); if (ret < 0) return ret; /* * when operating as AP we want to receive external beacons for * configuring ERP protection. */ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); if (ret < 0) return ret; return 0; }
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_qos_hdr *qosnull; int ret; u32 rate; qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); if (!qosnull) { ret = -ENOMEM; goto out; } qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC | IEEE80211_FCTL_FROMDS); /* qosnull->addr1 is filled by FW */ memcpy(qosnull->addr2, vif->addr, ETH_ALEN); memcpy(qosnull->addr3, vif->addr, ETH_ALEN); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_QOS_NULL_DATA, qosnull, sizeof(*qosnull), 0, rate); out: kfree(qosnull); return ret; }
static void wlcore_started_vifs_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); bool active = false; int *count = (int *)data; /* * count active interfaces according to interface type. * checking only bss_conf.idle is bad for some cases, e.g. * we don't want to count sta in p2p_find as active interface. */ switch (wlvif->bss_type) { case BSS_TYPE_STA_BSS: if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) active = true; break; case BSS_TYPE_AP_BSS: if (wlvif->wl->active_sta_count > 0) active = true; break; default: break; } if (active) (*count)++; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); /* * Rearm the tx watchdog just before idling scan. This * prevents just-finished scans from triggering the watchdog */ wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } wlcore_cmd_regdomain_config_locked(wl); ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; /* disable the keep-alive feature */ ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); if (ret < 0) return ret; return 0; }
static void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, struct ieee80211_tx_rate *rate) { u8 fw_rate = wl->fw_status_2->counters.tx_last_rate; if (fw_rate > CONF_HW_RATE_INDEX_MAX) { wl1271_error("last Tx rate invalid: %d", fw_rate); rate->idx = 0; rate->flags = 0; return; } if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { rate->idx = fw_rate; rate->flags = 0; } else { rate->flags = IEEE80211_TX_RC_MCS; rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0; /* SGI modifier is counted as a separate rate */ if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI) (rate->idx)--; if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) (rate->idx)--; /* this also covers the 40Mhz SGI case (= MCS15) */ if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI || fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) rate->flags |= IEEE80211_TX_RC_SHORT_GI; if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || wlvif->channel_type == NL80211_CHAN_HT40PLUS) { /* adjustment needed for range 0-7 */ rate->idx -= 8; rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; } } } }
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret, i; /* disable all keep-alive templates */ for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_acx_keep_alive_config(wl, wlvif, i, ACX_KEEP_ALIVE_TPL_INVALID); if (ret < 0) return ret; } /* disable the keep-alive feature */ ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); if (ret < 0) return ret; return 0; }
int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); /* * 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_wlvif = wlvif; 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)); wl->ops->scan_start(wl, wlvif, req); return 0; }
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_qos_hdr template; memset(&template, 0, sizeof(template));
int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct conf_tx_ac_category *conf_ac; struct conf_tx_tid *conf_tid; bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret, i; /* * consider all existing roles before configuring psm. */ if (!wl->ap_count) { if (is_ap) { /* Configure for power always on */ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); if (ret < 0) return ret; } else if (!wl->sta_count) { /* Configure for ELP power saving */ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); if (ret < 0) return ret; } } /* Mode specific init */ if (is_ap) { ret = wl1271_ap_hw_init(wl, wlvif); if (ret < 0) return ret; ret = wl12xx_init_ap_role(wl, wlvif); if (ret < 0) return ret; } else { ret = wl1271_sta_hw_init(wl, wlvif); if (ret < 0) return ret; ret = wl12xx_init_sta_role(wl, wlvif); if (ret < 0) return ret; } wl12xx_init_phy_vif_config(wl, wlvif); /* Default TID/AC configuration */ BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { conf_ac = &wl->conf.tx.ac_conf[i]; ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, conf_ac->cw_min, conf_ac->cw_max, conf_ac->aifsn, conf_ac->tx_op_limit); if (ret < 0) return ret; conf_tid = &wl->conf.tx.tid_conf[i]; ret = wl1271_acx_tid_cfg(wl, wlvif, conf_tid->queue_id, conf_tid->channel_type, conf_tid->tsid, conf_tid->ps_scheme, conf_tid->ack_policy, conf_tid->apsd_conf[0], conf_tid->apsd_conf[1]); if (ret < 0) return ret; } /* Configure HW encryption */ ret = wl1271_acx_feature_cfg(wl, wlvif); if (ret < 0) return ret; /* Mode specific init - post mem init */ if (is_ap) ret = wl1271_ap_hw_init_post_mem(wl, vif); else ret = wl1271_sta_hw_init_post_mem(wl, vif); if (ret < 0) return ret; /* Configure initiator BA sessions policies */ ret = wl1271_set_ba_policies(wl, wlvif); if (ret < 0) return ret; return 0; }
static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_cmd_scan_params *cmd; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } /* TODO: delete split_scan_timeout conf */ /* scan on the dev role if the regular one is not started */ if (wlvif->role_id == WL12XX_INVALID_ROLE_ID) cmd->role_id = wlvif->dev_role_id; else cmd->role_id = wlvif->role_id; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->scan_type = SCAN_TYPE_SEARCH; cmd->rssi_threshold = -127; cmd->snr_threshold = 0; /* TODO: use wlvif->type instead? */ cmd->bss_type = SCAN_BSS_TYPE_ANY; cmd->ssid_from_list = 0; cmd->filter = 0; cmd->add_broadcast = 0; /* TODO: figure this ones out */ /* Send scan command in high priority */ cmd->urgency = 1; cmd->protect = 0; /* TODO: take num_probe from req if available */ cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->terminate_after = 0; /* configure channels */ WARN_ON(req->n_ssids > 1); /* TODO: support multi ssid */ wlcore_set_scan_chan_params(wl, cmd, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_SEARCH); /* * all the cycles params (except total cycles) should * remain 0 for normal scan */ cmd->total_cycles = 1; if (req->no_cck) cmd->rate = WLCORE_SCAN_RATE_6; cmd->tag = WL1271_SCAN_DEFAULT_TAG; if (req->n_ssids) { cmd->ssid_len = req->ssids[0].ssid_len; memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); } /* TODO: per-band ies? */ if (cmd->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, false); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (cmd->active[1] || cmd->dfs) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, false); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd); return ret; }
void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 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, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl, vif); } 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, vif, 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, vif); } 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, vif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl, vif); } 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, vif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl, vif); } 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)); } }
static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, enum ieee80211_band band, bool passive, u32 basic_rate) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; u16 scan_options = 0; if (!passive && wl->scan.req->n_ssids == 0) return WL1271_NOTHING_TO_SCAN; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { ret = -ENOMEM; goto out; } if (wl->conf.scan.split_scan_timeout) scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (wlvif->bss_type == BSS_TYPE_AP_BSS || test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) cmd->params.role_id = wlvif->role_id; else cmd->params.role_id = wlvif->dev_role_id; if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, cmd->channels, band, passive); if (cmd->params.n_ch == 0) { ret = WL1271_NOTHING_TO_SCAN; goto out; } cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; if (band == IEEE80211_BAND_2GHZ) cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; else cmd->params.band = WL1271_SCAN_BAND_5_GHZ; if (wl->scan.ssid_len && wl->scan.ssid) { cmd->params.ssid_len = wl->scan.ssid_len; memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } memcpy(cmd->addr, vif->addr, ETH_ALEN); ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->params.role_id, band, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; } trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, sizeof(*trigger), 0); if (ret < 0) { wl1271_error("trigger scan to failed for hw scan"); goto out; } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd); kfree(trigger); return ret; }