void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[2]; struct spi_message m; u32 *cmd; cmd = &wl->buffer_cmd; *cmd = 0; *cmd |= WSPI_CMD_WRITE; *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; if (fixed) *cmd |= WSPI_CMD_FIXED; spi_message_init(&m); memset(t, 0, sizeof(t)); t[0].tx_buf = cmd; t[0].len = sizeof(*cmd); spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; t[1].len = len; spi_message_add_tail(&t[1], &m); spi_sync(wl->spi, &m); wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); }
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; u32 *cmd; u32 chunk_len; int i; pax_track_stack(); WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); spi_message_init(&m); memset(t, 0, sizeof(t)); cmd = &commands[0]; i = 0; while (len > 0) { chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); *cmd = 0; *cmd |= WSPI_CMD_WRITE; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; if (fixed) *cmd |= WSPI_CMD_FIXED; t[i].tx_buf = cmd; t[i].len = sizeof(*cmd); spi_message_add_tail(&t[i++], &m); t[i].tx_buf = buf; t[i].len = chunk_len; spi_message_add_tail(&t[i++], &m); wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); if (!fixed) addr += chunk_len; buf += chunk_len; len -= chunk_len; cmd++; } spi_sync(wl_to_spi(wl), &m); }
int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie, ie_len); if (!skb) { ret = -ENOMEM; goto out; } wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, role_id, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, role_id, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); return ret; }
static void wl1271_spi_reset(struct wl1271 *wl) { u8 *cmd; struct spi_transfer t; struct spi_message m; cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { wl1271_error("could not allocate cmd for spi reset"); return; } memset(&t, 0, sizeof(t)); spi_message_init(&m); memset(cmd, 0xff, WSPI_INIT_CMD_LEN); t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); spi_sync(wl_to_spi(wl), &m); wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); kfree(cmd); }
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); int ret; u32 rate; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, vif); if (!skb) goto out; wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); if (wlvif->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); if (ret < 0) wl1271_error("Unable to set ap probe request template."); out: return skb; }
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) { struct wl1271_ext_radio_parms_cmd *ext_radio_parms; struct conf_rf_settings *rf = &wl->conf.rf; int ret; if (!wl->nvs) return -ENODEV; ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); if (!ext_radio_parms) return -ENOMEM; ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, rf->tx_per_channel_power_compensation_2, CONF_TX_PWR_COMPENSATION_LEN_2); memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, rf->tx_per_channel_power_compensation_5, CONF_TX_PWR_COMPENSATION_LEN_5); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", ext_radio_parms, sizeof(*ext_radio_parms)); ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); if (ret < 0) wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); kfree(ext_radio_parms); return ret; }
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *skb) { int ret; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); if (!skb) goto out; wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); if (wl->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, wl->conf.tx.basic_rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, wl->conf.tx.basic_rate_5); if (ret < 0) wl1271_error("Unable to set ap probe request template."); out: return skb; }
int wl1271_cmd_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band) { struct sk_buff *skb; int ret; skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, ie, ie_len); if (!skb) { ret = -ENOMEM; goto out; } wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, wl->conf.tx.basic_rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, wl->conf.tx.basic_rate_5); out: dev_kfree_skb(skb); return ret; }
void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[3]; struct spi_message m; u32 *busy_buf; u32 *cmd; cmd = &wl->buffer_cmd; busy_buf = wl->buffer_busyword; *cmd = 0; *cmd |= WSPI_CMD_READ; *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; if (fixed) *cmd |= WSPI_CMD_FIXED; spi_message_init(&m); memset(t, 0, sizeof(t)); t[0].tx_buf = cmd; t[0].len = 4; spi_message_add_tail(&t[0], &m); /* Busy and non busy words read */ t[1].rx_buf = busy_buf; t[1].len = WL1271_BUSY_WORD_LEN; spi_message_add_tail(&t[1], &m); t[2].rx_buf = buf; t[2].len = len; spi_message_add_tail(&t[2], &m); spi_sync(wl->spi, &m); /* FIXME: Check busy words, removed due to SPI bug */ /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1)) wl1271_spi_read_busy(wl, buf, len); */ wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); }
static void wl1271_spi_init(struct wl1271 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; struct spi_message m; cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { wl1271_error("could not allocate cmd for spi init"); return; } memset(crc, 0, sizeof(crc)); memset(&t, 0, sizeof(t)); spi_message_init(&m); /* * Set WSPI_INIT_COMMAND * the data is being send from the MSB to LSB */ cmd[2] = 0xff; cmd[3] = 0xff; cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; cmd[0] = 0; cmd[7] = 0; cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; else cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; crc[0] = cmd[1]; crc[1] = cmd[0]; crc[2] = cmd[7]; crc[3] = cmd[6]; crc[4] = cmd[5]; cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; cmd[4] |= WSPI_INIT_CMD_END; t.tx_buf = cmd; t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); spi_sync(wl_to_spi(wl), &m); wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); kfree(cmd); }
/* Configure or disable a specific RX filter pattern */ int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, struct wl12xx_rx_filter *filter) { struct acx_rx_filter_cfg *acx; int fields_size = 0; int acx_size; int ret; WARN_ON(enable && !filter); WARN_ON(index >= WL1271_MAX_RX_FILTERS); wl1271_debug(DEBUG_ACX, "acx set rx filter idx: %d enable: %d filter: %p", index, enable, filter); if (enable) { fields_size = wl1271_rx_filter_get_fields_size(filter); wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", filter->action, filter->num_fields, fields_size); } acx_size = ALIGN(sizeof(*acx) + fields_size, 4); acx = kzalloc(acx_size, GFP_KERNEL); if (!acx) return -ENOMEM; acx->enable = enable; acx->index = index; if (enable) { acx->num_fields = filter->num_fields; acx->action = filter->action; wl1271_rx_filter_flatten_fields(filter, acx->fields); } wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size); if (ret < 0) { wl1271_warning("setting rx filter failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl128x_cmd_radio_parms(struct wl1271 *wl) { struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; struct wl128x_radio_parms_cmd *radio_parms; struct wl128x_ini_general_params *gp = &nvs->general_params; int ret, fem_idx; if (!wl->nvs) return -ENODEV; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) return -ENOMEM; radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); /* 2.4GHz parameters */ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl128x_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, &nvs->dyn_radio_params_2[fem_idx].params, sizeof(struct wl128x_ini_fem_params_2)); /* 5GHz parameters */ memcpy(&radio_parms->static_params_5, &nvs->stat_radio_params_5, sizeof(struct wl128x_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, &nvs->dyn_radio_params_5[fem_idx].params, sizeof(struct wl128x_ini_fem_params_5)); radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); if (ret < 0) wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); kfree(radio_parms); return ret; }
int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, bool sched_scan) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; u16 template_id_2_4 = wl->scan_templ_id_2_4; u16 template_id_5 = wl->scan_templ_id_5; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie_len); if (!skb) { ret = -ENOMEM; goto out; } if (ie_len) memcpy(skb_put(skb, ie_len), ie, ie_len); wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { template_id_2_4 = wl->sched_scan_templ_id_2_4; template_id_5 = wl->sched_scan_templ_id_5; } rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, role_id, template_id_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, role_id, template_id_5, skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); return ret; }
int wl1271_cmd_radio_parms(struct wl1271 *wl) { struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; struct wl1271_radio_parms_cmd *radio_parms; struct wl1271_ini_general_params *gp = &nvs->general_params; int ret; if (!wl->nvs) return -ENODEV; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) return -ENOMEM; radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; /* */ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_2)); /* */ memcpy(&radio_parms->static_params_5, &nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); if (ret < 0) wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); kfree(radio_parms); return ret; }
/* Returns the scan type to be used or a negative value on error */ static int wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, struct cfg80211_sched_scan_request *req) { struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; struct cfg80211_match_set *sets = req->match_sets; struct cfg80211_ssid *ssids = req->ssids; int ret = 0, type, i, j, n_match_ssids = 0; wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); /* count the match sets that contain SSIDs */ for (i = 0; i < req->n_match_sets; i++) if (sets[i].ssid.ssid_len > 0) n_match_ssids++; /* No filter, no ssids or only bcast ssid */ if (!n_match_ssids && (!req->n_ssids || (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { type = SCAN_SSID_FILTER_ANY; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } if (!n_match_ssids) { /* No filter, with ssids */ type = SCAN_SSID_FILTER_DISABLED; for (i = 0; i < req->n_ssids; i++) { cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, ssids[i].ssid_len); cmd->n_ssids++; } } else { type = SCAN_SSID_FILTER_LIST; /* Add all SSIDs from the filters */ for (i = 0; i < req->n_match_sets; i++) { /* ignore sets without SSIDs */ if (!sets[i].ssid.ssid_len) continue; cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, sets[i].ssid.ssid, sets[i].ssid.ssid_len); cmd->n_ssids++; } if ((req->n_ssids > 1) || (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { /* * Mark all the SSIDs passed in the SSID list as HIDDEN, * so they're used in probe requests. */ for (i = 0; i < req->n_ssids; i++) { for (j = 0; j < cmd->n_ssids; j++) if (!memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, req->ssids[i].ssid_len)) { cmd->ssids[j].type = SCAN_SSID_TYPE_HIDDEN; break; } /* Fail if SSID isn't present in the filters */ if (j == req->n_ssids) { ret = -EINVAL; goto out_free; } } } } wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("cmd sched scan ssid list failed"); goto out_free; } out_free: kfree(cmd); out: if (ret < 0) return ret; return type; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct wlcore_scan_channels *cfg_channels = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->role_id = wlvif->role_id; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; /* cycles set to 0 it means infinite (until manually stopped) */ cfg->cycles = 0; /* report APs when at least 1 is found */ cfg->report_after = 1; /* don't stop scanning automatically when something is found */ cfg->terminate = 0; cfg->tag = WL1271_SCAN_DEFAULT_TAG; /* don't filter on BSS type */ cfg->bss_type = SCAN_BSS_TYPE_ANY; /* currently NL80211 supports only a single interval */ for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->scan_plans[0].interval * MSEC_PER_SEC); cfg->ssid_len = 0; ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); if (ret < 0) goto out; cfg->filter_type = ret; wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL); if (!cfg_channels) { ret = -ENOMEM; goto out; } if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_PERIODIC)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; } wl12xx_adjust_channels(cfg, cfg_channels); if (!force_passive && cfg->active[0]) { u8 band = NL80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ies[band], ies->len[band], ies->common_ies, ies->common_ie_len, true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (!force_passive && cfg->active[1]) { u8 band = NL80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ies[band], ies->len[band], ies->common_ies, ies->common_ie_len, true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, sizeof(*cfg), 0); if (ret < 0) { wl1271_error("SCAN configuration failed"); goto out; } out: kfree(cfg_channels); kfree(cfg); return ret; }
static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, bool passive, u32 basic_rate) { struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; u16 scan_options = 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { ret = -ENOMEM; goto out; } /* No SSIDs means that we have a forced passive scan */ if (passive || wl->scan.req->n_ssids == 0) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->params.role_id = wl->role_id; 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.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; 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, wl->mac_addr, ETH_ALEN); ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len, band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; } /* disable the timeout */ trigger->timeout = 0; 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; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271_cmd_scan_params *cmd; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int ret; int filter_type; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); if (req->n_short_intervals > SCAN_MAX_SHORT_INTERVALS) { wl1271_warning("Number of short intervals requested (%d)" "exceeds limit (%d)", req->n_short_intervals, SCAN_MAX_SHORT_INTERVALS); return -EINVAL; } filter_type = wl12xx_scan_set_ssid_list(wl,req); if (filter_type < 0) return filter_type; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->role_id = wlvif->role_id; /* report APs when at least 1 is found */ //cfg->report_after = 1; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->scan_type = SCAN_TYPE_PERIODIC; cmd->rssi_threshold = c->rssi_threshold; cmd->snr_threshold = c->snr_threshold; /* don't filter on BSS type */ cmd->bss_type = SCAN_BSS_TYPE_ANY; cmd->ssid_from_list = 1; if (filter_type == SCAN_SSID_FILTER_LIST) cmd->filter = 1; cmd->add_broadcast = 0; /* TODO: figure this ones out */ cmd->urgency = 0; cmd->protect = 0; cmd->n_probe_reqs = c->num_probe_reqs; /* don't stop scanning automatically when something is found */ cmd->terminate_after = 0; /* configure channels */ wlcore_set_scan_chan_params(wl, cmd, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_PERIODIC); /* TODO: check params */ cmd->short_cycles_sec = req->short_interval; cmd->long_cycles_sec = req->long_interval; cmd->short_cycles_count = req->n_short_intervals; cmd->total_cycles = 0; /* TODO: how to set tx rate? */ cmd->tag = WL1271_SCAN_DEFAULT_TAG; /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ cmd->report_threshold = 1; cmd->terminate_on_report = 0; 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, ies->ie[band], ies->len[band], true); 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, ies->ie[band], ies->len[band], true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); wl1271_info("scan size: %d", 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; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, enum wl_rx_buf_align rx_align, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; u16 seq_num; u32 pkt_data_len; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->plt)) return -EINVAL; pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length); if (!pkt_data_len) { wl1271_error("Invalid packet arrived from HW. length %d", length); return -EINVAL; } if (rx_align == WLCORE_RX_BUF_UNALIGNED) reserved = RX_BUF_ALIGN; else if (rx_align == WLCORE_RX_BUF_PADDED) offset_to_data = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } /* discard corrupted packets */ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { hdr = (void *)(data + sizeof(*desc) + offset_to_data); wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", desc->status & WL1271_RX_DESC_STATUS_MASK, pkt_data_len); wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), min(pkt_data_len, ieee80211_hdrlen(hdr->frame_control))); return -EINVAL; } /* skb length not including rx descriptor */ skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, pkt_data_len); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wlcore_hw_set_rx_csum(wl, desc, skb); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; cfg->cycles = 0; cfg->report_after = 1; cfg->terminate = 0; cfg->tag = WL1271_SCAN_DEFAULT_TAG; cfg->bss_type = SCAN_BSS_TYPE_ANY; for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->interval); cfg->ssid_len = 0; ret = wl12xx_scan_sched_scan_ssid_list(wl, req); if (ret < 0) goto out; cfg->filter_type = ret; wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; } if (!force_passive && cfg->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->dev_role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], ies->len[band]); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (!force_passive && cfg->active[1]) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->dev_role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], ies->len[band]); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, sizeof(*cfg), 0); if (ret < 0) { wl1271_error("SCAN configuration failed"); goto out; } out: kfree(cfg); return ret; }
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; }
static int wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, struct cfg80211_sched_scan_request *req) { struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; struct cfg80211_match_set *sets = req->match_sets; struct cfg80211_ssid *ssids = req->ssids; int ret = 0, type, i, j, n_match_ssids = 0; wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); for (i = 0; i < req->n_match_sets; i++) if (sets[i].ssid.ssid_len > 0) n_match_ssids++; if (!n_match_ssids && (!req->n_ssids || (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { type = SCAN_SSID_FILTER_ANY; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } if (!n_match_ssids) { type = SCAN_SSID_FILTER_DISABLED; for (i = 0; i < req->n_ssids; i++) { cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, ssids[i].ssid_len); cmd->n_ssids++; } } else { type = SCAN_SSID_FILTER_LIST; for (i = 0; i < req->n_match_sets; i++) { if (!sets[i].ssid.ssid_len) continue; cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, sets[i].ssid.ssid, sets[i].ssid.ssid_len); cmd->n_ssids++; } if ((req->n_ssids > 1) || (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { for (i = 0; i < req->n_ssids; i++) { if (!req->ssids[i].ssid_len) continue; for (j = 0; j < cmd->n_ssids; j++) if (!memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, req->ssids[i].ssid_len)) { cmd->ssids[j].type = SCAN_SSID_TYPE_HIDDEN; break; } if (j == cmd->n_ssids) { ret = -EINVAL; goto out_free; } } } } wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("cmd sched scan ssid list failed"); goto out_free; } out_free: kfree(cmd); out: if (ret < 0) return ret; return type; }
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, u8 active_scan, u8 high_prio, u8 num_channels, u8 probe_requests) { struct wl1271_cmd_trigger_scan_to *trigger = NULL; struct wl1271_cmd_scan *params = NULL; int i, ret; u16 scan_options = 0; if (wl->scanning) return -EINVAL; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); params->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); if (!active_scan) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (high_prio) scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; params->params.scan_options = scan_options; params->params.num_channels = num_channels; params->params.num_probe_requests = probe_requests; params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); params->params.tid_trigger = 0; params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; for (i = 0; i < num_channels; i++) { params->channels[i].min_duration = cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); params->channels[i].max_duration = cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); memset(¶ms->channels[i].bssid_lsb, 0xff, 4); memset(¶ms->channels[i].bssid_msb, 0xff, 2); params->channels[i].early_termination = 0; params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; params->channels[i].channel = i + 1; } if (len && ssid) { params->params.ssid_len = len; memcpy(params->params.ssid, ssid, len); } ret = wl1271_cmd_build_probe_req(wl, ssid, len); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; } trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!trigger) { ret = -ENOMEM; goto out; } trigger->timeout = 0; ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, sizeof(*trigger)); if (ret < 0) { wl1271_error("trigger scan to failed for hw scan"); goto out; } wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); wl->scanning = true; ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); if (params->header.status != CMD_STATUS_SUCCESS) { wl1271_error("Scan command error: %d", params->header.status); wl->scanning = false; ret = -EIO; goto out; } out: kfree(params); return ret; }
int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; u32 supported_rates; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); cmd->role_id = wlvif->role_id; if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WLCORE_BAND_5GHZ; cmd->channel = wlvif->channel; cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; cmd->sta.ssid_len = wlvif->ssid_len; memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES | wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); if (wlvif->p2p) supported_rates &= ~CONF_TX_CCK_RATES; cmd->sta.local_rates = cpu_to_le32(supported_rates); cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); if (ret) goto out_free; } cmd->sta.hlid = wlvif->sta.hlid; cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; /* * We don't have the correct remote rates in this stage. the rates * will be reconfigured later, after authorization. */ cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", wlvif->role_id, cmd->sta.hlid, cmd->sta.session, wlvif->basic_rate_set, wlvif->rate_set); wl1271_dump(DEBUG_CMD, "START_STA: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role start sta"); goto err_hlid; } wlvif->sta.role_chan_type = wlvif->channel_type; goto out_free; err_hlid: /* clear links on error. */ wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); out: return ret; }
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[2]; struct spi_message m; u32 *busy_buf; u32 *cmd; u32 chunk_len; while (len > 0) { chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); cmd = &wl->buffer_cmd; busy_buf = wl->buffer_busyword; *cmd = 0; *cmd |= WSPI_CMD_READ; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; if (fixed) *cmd |= WSPI_CMD_FIXED; spi_message_init(&m); memset(t, 0, sizeof(t)); t[0].tx_buf = cmd; t[0].len = 4; t[0].cs_change = true; spi_message_add_tail(&t[0], &m); /* Busy and non busy words read */ t[1].rx_buf = busy_buf; t[1].len = WL1271_BUSY_WORD_LEN; t[1].cs_change = true; spi_message_add_tail(&t[1], &m); spi_sync(wl_to_spi(wl), &m); if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && wl1271_spi_read_busy(wl)) { memset(buf, 0, chunk_len); return; } spi_message_init(&m); memset(t, 0, sizeof(t)); t[0].rx_buf = buf; t[0].len = chunk_len; t[0].cs_change = true; spi_message_add_tail(&t[0], &m); spi_sync(wl_to_spi(wl), &m); wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); if (!fixed) addr += chunk_len; buf += chunk_len; len -= chunk_len; } }
static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, bool passive, u32 basic_rate) { struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; u16 scan_options = 0; /* skip active scans if we don't have SSIDs */ 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; } /* We always use high priority scans */ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; 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.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; 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); } ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len, band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; } /* disable the timeout */ trigger->timeout = 0; 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; }
static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum ieee80211_band band, bool passive, u32 basic_rate) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; u16 scan_options = 0; /* skip active scans if we don't have SSIDs */ 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; cmd->params.role_id = wlvif->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, false); 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; }
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf) { struct wl1271 *wl = hw->priv; const u8 *addr; int ret; u8 key_type; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); addr = sta ? sta->addr : bcast_addr; wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", key_conf->alg, key_conf->keyidx, key_conf->keylen, key_conf->flags); wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); if (is_zero_ether_addr(addr)) { ret = -EOPNOTSUPP; goto out; } mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out_unlock; switch (key_conf->alg) { case ALG_WEP: key_type = KEY_WEP; key_conf->hw_key_idx = key_conf->keyidx; break; case ALG_TKIP: key_type = KEY_TKIP; key_conf->hw_key_idx = key_conf->keyidx; break; case ALG_CCMP: key_type = KEY_AES; key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; default: wl1271_error("Unknown key algo 0x%x", key_conf->alg); ret = -EOPNOTSUPP; goto out_sleep; } switch (cmd) { case SET_KEY: ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, addr); if (ret < 0) { wl1271_error("Could not add or replace key"); goto out_sleep; } break; case DISABLE_KEY: ret = wl1271_cmd_set_key(wl, KEY_REMOVE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, addr); if (ret < 0) { wl1271_error("Could not remove key"); goto out_sleep; } break; default: wl1271_error("Unsupported key cmd 0x%x", cmd); ret = -EOPNOTSUPP; goto out_sleep; break; } out_sleep: wl1271_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); out: return ret; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; /* cycles set to 0 it means infinite (until manually stopped) */ cfg->cycles = 0; /* report APs when at least 1 is found */ cfg->report_after = 1; /* don't stop scanning automatically when something is found */ cfg->terminate = 0; cfg->tag = WL1271_SCAN_DEFAULT_TAG; /* don't filter on BSS type */ cfg->bss_type = SCAN_BSS_TYPE_ANY; /* currently NL80211 supports only a single interval */ for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->interval); if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) { cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; cfg->ssid_len = req->ssids[0].ssid_len; memcpy(cfg->ssid, req->ssids[0].ssid, req->ssids[0].ssid_len); } else { cfg->filter_type = SCAN_SSID_FILTER_ANY; cfg->ssid_len = 0; } if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; } if (!force_passive && cfg->active[0]) { ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_2GHZ], ies->len[IEEE80211_BAND_2GHZ], IEEE80211_BAND_2GHZ); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (!force_passive && cfg->active[1]) { ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[IEEE80211_BAND_5GHZ], ies->len[IEEE80211_BAND_5GHZ], IEEE80211_BAND_5GHZ); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, sizeof(*cfg), 0); if (ret < 0) { wl1271_error("SCAN configuration failed"); goto out; } out: kfree(cfg); return ret; }
int wl1271_acx_set_rx_data_filter(struct wl1271 *wl, u8 index, bool enable, struct wl12xx_rx_data_filter *filter) { struct acx_rx_data_filter_cfg *acx; int fields_size = 0; int acx_size; int ret; if (enable && !filter) { wl1271_warning("acx_set_rx_data_filter: enable but no filter"); return -EINVAL; } if (index >= WL1271_MAX_RX_FILTERS) { wl1271_warning("acx_set_rx_data_filter: invalid filter idx(%d)", index); return -EINVAL; } if (filter) { if (filter->action < FILTER_DROP || filter->action > FILTER_FW_HANDLE) { wl1271_warning("invalid filter action (%d)", filter->action); return -EINVAL; } } wl1271_debug(DEBUG_ACX, "acx set rx data filter idx: %d, enable: %d", index, enable); if (enable) { fields_size = wl1271_rx_filter_get_fields_size(filter); wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", filter->action, filter->num_fields, fields_size); } acx_size = roundup(sizeof(*acx) + fields_size, 4); acx = kzalloc(acx_size, GFP_KERNEL); if (!acx) return -ENOMEM; acx->enable = enable ? 1 : 0; acx->index = index; if (enable) { acx->num_fields = filter->num_fields; acx->action = filter->action; wl1271_rx_filter_flatten_fields(filter, acx->fields); } wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size); if (ret < 0) { wl1271_warning("setting rx data filter failed: %d", ret); goto out; } out: kfree(acx); return ret; }