Loading MAINTAINERS +3 −3 Original line number Diff line number Diff line Loading @@ -6742,12 +6742,12 @@ S: Maintained F: drivers/net/wireless/wl1251/* WL1271 WIRELESS DRIVER M: Luciano Coelho <luciano.coelho@nokia.com> M: Luciano Coelho <coelho@ti.com> L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org W: http://wireless.kernel.org/en/users/Drivers/wl12xx T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git S: Maintained F: drivers/net/wireless/wl12xx/wl1271* F: drivers/net/wireless/wl12xx/ F: include/linux/wl12xx.h WL3501 WIRELESS PCMCIA CARD DRIVER Loading drivers/net/wireless/wl12xx/acx.c +151 −9 Original line number Diff line number Diff line Loading @@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } int wl1271_acx_rate_policies(struct wl1271 *wl) int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; struct acx_sta_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; int idx = 0; int ret = 0; Loading Loading @@ -794,6 +794,38 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) return ret; } int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx) { struct acx_ap_rate_policy *acx; int ret = 0; wl1271_debug(DEBUG_ACX, "acx ap rate policy"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); acx->rate_policy.short_retry_limit = c->short_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.aflags = c->aflags; acx->rate_policy_idx = cpu_to_le32(idx); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of ap rate policy failed: %d", ret); goto out; } out: kfree(acx); return ret; } int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) { Loading Loading @@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct wl1271_acx_ht_capabilities *acx; u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); Loading @@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, /* Allow HT Operation ? */ if (allow_ht_operation) { acx->ht_capabilites = ht_capabilites = WL1271_ACX_FW_CAP_HT_OPERATION; if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; /* get data from A-MPDU parameters field */ Loading @@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, acx->ampdu_min_spacing = ht_cap->ampdu_density; memcpy(acx->mac_address, mac_address, ETH_ALEN); } else { /* HT operations are not allowed */ acx->ht_capabilites = 0; } acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); Loading Loading @@ -1309,6 +1342,91 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, return ret; } /* Configure BA session initiator/receiver parameters setting in the FW. */ int wl1271_acx_set_ba_session(struct wl1271 *wl, enum ieee80211_back_parties direction, u8 tid_index, u8 policy) { struct wl1271_acx_ba_session_policy *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* ANY role */ acx->role_id = 0xff; acx->tid = tid_index; acx->enable = policy; acx->ba_direction = direction; switch (direction) { case WLAN_BACK_INITIATOR: acx->win_size = wl->conf.ht.tx_ba_win_size; acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; break; case WLAN_BACK_RECIPIENT: acx->win_size = RX_BA_WIN_SIZE; acx->inactivity_timeout = 0; break; default: wl1271_error("Incorrect acx command id=%x\n", direction); ret = -EINVAL; goto out; } ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_POLICY_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba session setting failed: %d", ret); goto out; } out: kfree(acx); return ret; } /* setup BA session receiver setting in the FW. */ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable) { struct wl1271_acx_ba_receiver_setup *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* Single link for now */ acx->link_id = 1; acx->tid = tid_index; acx->enable = enable; acx->win_size = 0; acx->ssn = ssn; ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba receiver session failed: %d", ret); goto out; } out: kfree(acx); return ret; } int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) { struct wl1271_acx_fw_tsf_information *tsf_info; Loading @@ -1334,3 +1452,27 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) kfree(tsf_info); return ret; } int wl1271_acx_max_tx_retry(struct wl1271 *wl) { struct wl1271_acx_max_tx_retry *acx = NULL; int ret; wl1271_debug(DEBUG_ACX, "acx max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx max tx retry failed: %d", ret); goto out; } out: kfree(acx); return ret; } drivers/net/wireless/wl12xx/acx.h +87 −4 Original line number Diff line number Diff line Loading @@ -747,13 +747,23 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 #define ACX_TX_RATE_POLICY_CNT 2 struct acx_rate_policy { struct acx_sta_rate_policy { struct acx_header header; __le32 rate_class_cnt; struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; } __packed; #define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_BCST_RATE 5 struct acx_ap_rate_policy { struct acx_header header; __le32 rate_policy_idx; struct acx_rate_class rate_policy; } __packed; struct acx_ac_cfg { struct acx_header header; u8 ac; Loading Loading @@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information { u8 padding[3]; } __packed; #define RX_BA_WIN_SIZE 8 struct wl1271_acx_ba_session_policy { struct acx_header header; /* * Specifies role Id, Range 0-7, 0xFF means ANY role. * Future use. For now this field is irrelevant */ u8 role_id; /* * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. * Not applicable if Role Id is set to ANY. */ u8 link_id; u8 tid; u8 enable; /* Windows size in number of packets */ u16 win_size; /* * As initiator inactivity timeout in time units(TU) of 1024us. * As receiver reserved */ u16 inactivity_timeout; /* Initiator = 1/Receiver = 0 */ u8 ba_direction; u8 padding[3]; } __packed; struct wl1271_acx_ba_receiver_setup { struct acx_header header; /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ u8 link_id; u8 tid; u8 enable; u8 padding[1]; /* Windows size in number of packets */ u16 win_size; /* BA session starting sequence number. RANGE 0-FFF */ u16 ssn; } __packed; struct wl1271_acx_fw_tsf_information { struct acx_header header; Loading @@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; struct wl1271_acx_max_tx_retry { struct acx_header header; /* * the number of frames transmission failures before * issuing the aging event. */ __le16 max_tx_retry; u8 padding_1[2]; } __packed; enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, Loading Loading @@ -1113,12 +1187,13 @@ enum { ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, ACX_BA_SESSION_POLICY_CFG = 0x0055, ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_MAX_TX_FAILURE = 0x0072, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, Loading Loading @@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); int wl1271_acx_rate_policies(struct wl1271 *wl); int wl1271_acx_sta_rate_policies(struct wl1271 *wl); int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx); int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, Loading @@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, bool allow_ht_operation); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); int wl1271_acx_set_ba_session(struct wl1271 *wl, enum ieee80211_back_parties direction, u8 tid_index, u8 policy); int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_max_tx_retry(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ drivers/net/wireless/wl12xx/boot.c +29 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "boot.h" #include "io.h" #include "event.h" #include "rx.h" static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { [PART_DOWN] = { Loading Loading @@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } static void wl1271_parse_fw_ver(struct wl1271 *wl) { int ret; ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], &wl->chip.fw_ver[4]); if (ret != 5) { wl1271_warning("fw version incorrect value"); memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); return; } } static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; Loading @@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), false); strncpy(wl->chip.fw_ver, static_data.fw_version, sizeof(wl->chip.fw_ver)); strncpy(wl->chip.fw_ver_str, static_data.fw_version, sizeof(wl->chip.fw_ver_str)); /* make sure the string is NULL-terminated */ wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; wl1271_parse_fw_ver(wl); } static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, Loading Loading @@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { if (wl->nvs->general_params.dual_mode_select) /* for now 11a is unsupported in AP mode */ if (wl->bss_type != BSS_TYPE_AP_BSS && wl->nvs->general_params.dual_mode_select) wl->enable_11a = true; } Loading Loading @@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); Loading Loading @@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_boot_enable_interrupts(wl); /* set the wl1271 default filters */ wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; wl1271_set_default_filters(wl); wl1271_event_mbox_config(wl); Loading drivers/net/wireless/wl12xx/cmd.c +296 −12 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ #include "wl12xx_80211.h" #include "cmd.h" #include "event.h" #include "tx.h" #define WL1271_CMD_FAST_POLL_COUNT 50 Loading Loading @@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) { u32 events_vector, event; unsigned long timeout; Loading @@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) do { if (time_after(jiffies, timeout)) { ieee80211_queue_work(wl->hw, &wl->recovery_work); wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", (int)mask); return -ETIMEDOUT; } Loading @@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) { int ret; ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); if (ret != 0) { ieee80211_queue_work(wl->hw, &wl->recovery_work); return ret; } return 0; } int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) { struct wl1271_cmd_join *join; Loading Loading @@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; cmd->enabled_rates = cpu_to_le32(rates); cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; cmd->index = index; if (buf) Loading Loading @@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) /* llc layer */ memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); tmpl.llc_type = htons(ETH_P_ARP); tmpl.llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl.arp_hdr; arp_hdr->ar_hrd = htons(ARPHRD_ETHER); arp_hdr->ar_pro = htons(ETH_P_IP); arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(ARPOP_REPLY); arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); Loading Loading @@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) wl->basic_rate); } int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) { struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); Loading @@ -731,11 +746,42 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) return ret; } int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) { struct wl1271_cmd_set_ap_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->hlid = WL1271_AP_BROADCAST_HLID; cmd->key_id = id; cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; cmd->key_action = cpu_to_le16(KEY_SET_ID); cmd->key_type = KEY_WEP; ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); goto out; } out: kfree(cmd); return ret; } int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16) { struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); Loading Loading @@ -788,6 +834,67 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, return ret; } int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16) { struct wl1271_cmd_set_ap_keys *cmd; int ret = 0; u8 lid_type; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; if (hlid == WL1271_AP_BROADCAST_HLID) { if (key_type == KEY_WEP) lid_type = WEP_DEFAULT_LID_TYPE; else lid_type = BROADCAST_LID_TYPE; } else { lid_type = UNICAST_LID_TYPE; } wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" " hlid: %d", (int)action, (int)id, (int)lid_type, (int)key_type, (int)hlid); cmd->lid_key_type = lid_type; cmd->hlid = hlid; cmd->key_action = cpu_to_le16(action); cmd->key_size = key_size; cmd->key_type = key_type; cmd->key_id = id; cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); if (key_type == KEY_TKIP) { /* * We get the key in the following form: * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) * but the target is expecting: * TKIP - RX MIC - TX MIC */ memcpy(cmd->key, key, 16); memcpy(cmd->key + 16, key + 24, 8); memcpy(cmd->key + 24, key + 16, 8); } else { memcpy(cmd->key, key, key_size); } wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set ap keys"); goto out; } out: kfree(cmd); return ret; } int wl1271_cmd_disconnect(struct wl1271 *wl) { struct wl1271_cmd_disconnect *cmd; Loading Loading @@ -850,3 +957,180 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl) out: return ret; } int wl1271_cmd_start_bss(struct wl1271 *wl) { struct wl1271_cmd_bss_start *cmd; struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; int ret; wl1271_debug(DEBUG_CMD, "cmd start bss"); /* * FIXME: We currently do not support hidden SSID. The real SSID * should be fetched from mac80211 first. */ if (wl->ssid_len == 0) { wl1271_warning("Hidden SSID currently not supported for AP"); ret = -EINVAL; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); cmd->beacon_interval = cpu_to_le16(wl->beacon_int); cmd->dtim_interval = bss_conf->dtim_period; cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; cmd->channel = wl->channel; cmd->ssid_len = wl->ssid_len; cmd->ssid_type = SSID_TYPE_PUBLIC; memcpy(cmd->ssid, wl->ssid, wl->ssid_len); switch (wl->band) { case IEEE80211_BAND_2GHZ: cmd->band = RADIO_BAND_2_4GHZ; break; case IEEE80211_BAND_5GHZ: cmd->band = RADIO_BAND_5GHZ; break; default: wl1271_warning("bss start - unknown band: %d", (int)wl->band); cmd->band = RADIO_BAND_2_4GHZ; break; } ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd start bss"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_stop_bss(struct wl1271 *wl) { struct wl1271_cmd_bss_start *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd stop bss"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->bss_index = WL1271_AP_BSS_INDEX; ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd stop bss"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { struct wl1271_cmd_add_sta *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } /* currently we don't support UAPSD */ cmd->sp_len = 0; memcpy(cmd->addr, sta->addr, ETH_ALEN); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->aid = sta->aid; cmd->hlid = hlid; /* * FIXME: Does STA support QOS? We need to propagate this info from * hostapd. Currently not that important since this is only used for * sending the correct flavor of null-data packet in response to a * trigger. */ cmd->wmm = 0; cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta->supp_rates[wl->band])); wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd add sta"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) { struct wl1271_cmd_remove_sta *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->hlid = hlid; /* We never send a deauth, mac80211 is in charge of this */ cmd->reason_opcode = 0; cmd->send_deauth_flag = 0; ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd remove sta"); goto out_free; } /* * We are ok with a timeout here. The event is sometimes not sent * due to a firmware bug. */ wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID); out_free: kfree(cmd); out: return ret; } Loading
MAINTAINERS +3 −3 Original line number Diff line number Diff line Loading @@ -6742,12 +6742,12 @@ S: Maintained F: drivers/net/wireless/wl1251/* WL1271 WIRELESS DRIVER M: Luciano Coelho <luciano.coelho@nokia.com> M: Luciano Coelho <coelho@ti.com> L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org W: http://wireless.kernel.org/en/users/Drivers/wl12xx T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git S: Maintained F: drivers/net/wireless/wl12xx/wl1271* F: drivers/net/wireless/wl12xx/ F: include/linux/wl12xx.h WL3501 WIRELESS PCMCIA CARD DRIVER Loading
drivers/net/wireless/wl12xx/acx.c +151 −9 Original line number Diff line number Diff line Loading @@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } int wl1271_acx_rate_policies(struct wl1271 *wl) int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; struct acx_sta_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; int idx = 0; int ret = 0; Loading Loading @@ -794,6 +794,38 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) return ret; } int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx) { struct acx_ap_rate_policy *acx; int ret = 0; wl1271_debug(DEBUG_ACX, "acx ap rate policy"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); acx->rate_policy.short_retry_limit = c->short_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.aflags = c->aflags; acx->rate_policy_idx = cpu_to_le32(idx); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of ap rate policy failed: %d", ret); goto out; } out: kfree(acx); return ret; } int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) { Loading Loading @@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct wl1271_acx_ht_capabilities *acx; u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); Loading @@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, /* Allow HT Operation ? */ if (allow_ht_operation) { acx->ht_capabilites = ht_capabilites = WL1271_ACX_FW_CAP_HT_OPERATION; if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) acx->ht_capabilites |= ht_capabilites |= WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; /* get data from A-MPDU parameters field */ Loading @@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, acx->ampdu_min_spacing = ht_cap->ampdu_density; memcpy(acx->mac_address, mac_address, ETH_ALEN); } else { /* HT operations are not allowed */ acx->ht_capabilites = 0; } acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); Loading Loading @@ -1309,6 +1342,91 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, return ret; } /* Configure BA session initiator/receiver parameters setting in the FW. */ int wl1271_acx_set_ba_session(struct wl1271 *wl, enum ieee80211_back_parties direction, u8 tid_index, u8 policy) { struct wl1271_acx_ba_session_policy *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* ANY role */ acx->role_id = 0xff; acx->tid = tid_index; acx->enable = policy; acx->ba_direction = direction; switch (direction) { case WLAN_BACK_INITIATOR: acx->win_size = wl->conf.ht.tx_ba_win_size; acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; break; case WLAN_BACK_RECIPIENT: acx->win_size = RX_BA_WIN_SIZE; acx->inactivity_timeout = 0; break; default: wl1271_error("Incorrect acx command id=%x\n", direction); ret = -EINVAL; goto out; } ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_POLICY_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba session setting failed: %d", ret); goto out; } out: kfree(acx); return ret; } /* setup BA session receiver setting in the FW. */ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable) { struct wl1271_acx_ba_receiver_setup *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* Single link for now */ acx->link_id = 1; acx->tid = tid_index; acx->enable = enable; acx->win_size = 0; acx->ssn = ssn; ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba receiver session failed: %d", ret); goto out; } out: kfree(acx); return ret; } int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) { struct wl1271_acx_fw_tsf_information *tsf_info; Loading @@ -1334,3 +1452,27 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) kfree(tsf_info); return ret; } int wl1271_acx_max_tx_retry(struct wl1271 *wl) { struct wl1271_acx_max_tx_retry *acx = NULL; int ret; wl1271_debug(DEBUG_ACX, "acx max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx max tx retry failed: %d", ret); goto out; } out: kfree(acx); return ret; }
drivers/net/wireless/wl12xx/acx.h +87 −4 Original line number Diff line number Diff line Loading @@ -747,13 +747,23 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 #define ACX_TX_RATE_POLICY_CNT 2 struct acx_rate_policy { struct acx_sta_rate_policy { struct acx_header header; __le32 rate_class_cnt; struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; } __packed; #define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_BCST_RATE 5 struct acx_ap_rate_policy { struct acx_header header; __le32 rate_policy_idx; struct acx_rate_class rate_policy; } __packed; struct acx_ac_cfg { struct acx_header header; u8 ac; Loading Loading @@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information { u8 padding[3]; } __packed; #define RX_BA_WIN_SIZE 8 struct wl1271_acx_ba_session_policy { struct acx_header header; /* * Specifies role Id, Range 0-7, 0xFF means ANY role. * Future use. For now this field is irrelevant */ u8 role_id; /* * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. * Not applicable if Role Id is set to ANY. */ u8 link_id; u8 tid; u8 enable; /* Windows size in number of packets */ u16 win_size; /* * As initiator inactivity timeout in time units(TU) of 1024us. * As receiver reserved */ u16 inactivity_timeout; /* Initiator = 1/Receiver = 0 */ u8 ba_direction; u8 padding[3]; } __packed; struct wl1271_acx_ba_receiver_setup { struct acx_header header; /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ u8 link_id; u8 tid; u8 enable; u8 padding[1]; /* Windows size in number of packets */ u16 win_size; /* BA session starting sequence number. RANGE 0-FFF */ u16 ssn; } __packed; struct wl1271_acx_fw_tsf_information { struct acx_header header; Loading @@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; struct wl1271_acx_max_tx_retry { struct acx_header header; /* * the number of frames transmission failures before * issuing the aging event. */ __le16 max_tx_retry; u8 padding_1[2]; } __packed; enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, Loading Loading @@ -1113,12 +1187,13 @@ enum { ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, ACX_BA_SESSION_POLICY_CFG = 0x0055, ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_MAX_TX_FAILURE = 0x0072, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, Loading Loading @@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); int wl1271_acx_rate_policies(struct wl1271 *wl); int wl1271_acx_sta_rate_policies(struct wl1271 *wl); int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx); int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, Loading @@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, bool allow_ht_operation); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); int wl1271_acx_set_ba_session(struct wl1271 *wl, enum ieee80211_back_parties direction, u8 tid_index, u8 policy); int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_max_tx_retry(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */
drivers/net/wireless/wl12xx/boot.c +29 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "boot.h" #include "io.h" #include "event.h" #include "rx.h" static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { [PART_DOWN] = { Loading Loading @@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } static void wl1271_parse_fw_ver(struct wl1271 *wl) { int ret; ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], &wl->chip.fw_ver[4]); if (ret != 5) { wl1271_warning("fw version incorrect value"); memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); return; } } static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; Loading @@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), false); strncpy(wl->chip.fw_ver, static_data.fw_version, sizeof(wl->chip.fw_ver)); strncpy(wl->chip.fw_ver_str, static_data.fw_version, sizeof(wl->chip.fw_ver_str)); /* make sure the string is NULL-terminated */ wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; wl1271_parse_fw_ver(wl); } static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, Loading Loading @@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { if (wl->nvs->general_params.dual_mode_select) /* for now 11a is unsupported in AP mode */ if (wl->bss_type != BSS_TYPE_AP_BSS && wl->nvs->general_params.dual_mode_select) wl->enable_11a = true; } Loading Loading @@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); Loading Loading @@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_boot_enable_interrupts(wl); /* set the wl1271 default filters */ wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; wl1271_set_default_filters(wl); wl1271_event_mbox_config(wl); Loading
drivers/net/wireless/wl12xx/cmd.c +296 −12 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ #include "wl12xx_80211.h" #include "cmd.h" #include "event.h" #include "tx.h" #define WL1271_CMD_FAST_POLL_COUNT 50 Loading Loading @@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) { u32 events_vector, event; unsigned long timeout; Loading @@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) do { if (time_after(jiffies, timeout)) { ieee80211_queue_work(wl->hw, &wl->recovery_work); wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", (int)mask); return -ETIMEDOUT; } Loading @@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) { int ret; ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); if (ret != 0) { ieee80211_queue_work(wl->hw, &wl->recovery_work); return ret; } return 0; } int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) { struct wl1271_cmd_join *join; Loading Loading @@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; cmd->enabled_rates = cpu_to_le32(rates); cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; cmd->index = index; if (buf) Loading Loading @@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) /* llc layer */ memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); tmpl.llc_type = htons(ETH_P_ARP); tmpl.llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl.arp_hdr; arp_hdr->ar_hrd = htons(ARPHRD_ETHER); arp_hdr->ar_pro = htons(ETH_P_IP); arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(ARPOP_REPLY); arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); Loading Loading @@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) wl->basic_rate); } int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) { struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); Loading @@ -731,11 +746,42 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) return ret; } int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) { struct wl1271_cmd_set_ap_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->hlid = WL1271_AP_BROADCAST_HLID; cmd->key_id = id; cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; cmd->key_action = cpu_to_le16(KEY_SET_ID); cmd->key_type = KEY_WEP; ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); goto out; } out: kfree(cmd); return ret; } int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16) { struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); Loading Loading @@ -788,6 +834,67 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, return ret; } int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16) { struct wl1271_cmd_set_ap_keys *cmd; int ret = 0; u8 lid_type; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; if (hlid == WL1271_AP_BROADCAST_HLID) { if (key_type == KEY_WEP) lid_type = WEP_DEFAULT_LID_TYPE; else lid_type = BROADCAST_LID_TYPE; } else { lid_type = UNICAST_LID_TYPE; } wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" " hlid: %d", (int)action, (int)id, (int)lid_type, (int)key_type, (int)hlid); cmd->lid_key_type = lid_type; cmd->hlid = hlid; cmd->key_action = cpu_to_le16(action); cmd->key_size = key_size; cmd->key_type = key_type; cmd->key_id = id; cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); if (key_type == KEY_TKIP) { /* * We get the key in the following form: * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) * but the target is expecting: * TKIP - RX MIC - TX MIC */ memcpy(cmd->key, key, 16); memcpy(cmd->key + 16, key + 24, 8); memcpy(cmd->key + 24, key + 16, 8); } else { memcpy(cmd->key, key, key_size); } wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set ap keys"); goto out; } out: kfree(cmd); return ret; } int wl1271_cmd_disconnect(struct wl1271 *wl) { struct wl1271_cmd_disconnect *cmd; Loading Loading @@ -850,3 +957,180 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl) out: return ret; } int wl1271_cmd_start_bss(struct wl1271 *wl) { struct wl1271_cmd_bss_start *cmd; struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; int ret; wl1271_debug(DEBUG_CMD, "cmd start bss"); /* * FIXME: We currently do not support hidden SSID. The real SSID * should be fetched from mac80211 first. */ if (wl->ssid_len == 0) { wl1271_warning("Hidden SSID currently not supported for AP"); ret = -EINVAL; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); cmd->beacon_interval = cpu_to_le16(wl->beacon_int); cmd->dtim_interval = bss_conf->dtim_period; cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; cmd->channel = wl->channel; cmd->ssid_len = wl->ssid_len; cmd->ssid_type = SSID_TYPE_PUBLIC; memcpy(cmd->ssid, wl->ssid, wl->ssid_len); switch (wl->band) { case IEEE80211_BAND_2GHZ: cmd->band = RADIO_BAND_2_4GHZ; break; case IEEE80211_BAND_5GHZ: cmd->band = RADIO_BAND_5GHZ; break; default: wl1271_warning("bss start - unknown band: %d", (int)wl->band); cmd->band = RADIO_BAND_2_4GHZ; break; } ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd start bss"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_stop_bss(struct wl1271 *wl) { struct wl1271_cmd_bss_start *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd stop bss"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->bss_index = WL1271_AP_BSS_INDEX; ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd stop bss"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { struct wl1271_cmd_add_sta *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } /* currently we don't support UAPSD */ cmd->sp_len = 0; memcpy(cmd->addr, sta->addr, ETH_ALEN); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->aid = sta->aid; cmd->hlid = hlid; /* * FIXME: Does STA support QOS? We need to propagate this info from * hostapd. Currently not that important since this is only used for * sending the correct flavor of null-data packet in response to a * trigger. */ cmd->wmm = 0; cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta->supp_rates[wl->band])); wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd add sta"); goto out_free; } out_free: kfree(cmd); out: return ret; } int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) { struct wl1271_cmd_remove_sta *cmd; int ret; wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->hlid = hlid; /* We never send a deauth, mac80211 is in charge of this */ cmd->reason_opcode = 0; cmd->send_deauth_flag = 0; ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd remove sta"); goto out_free; } /* * We are ok with a timeout here. The event is sometimes not sent * due to a firmware bug. */ wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID); out_free: kfree(cmd); out: return ret; }