diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/cmd.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 143 |
1 files changed, 105 insertions, 38 deletions
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 25990bd38be6..b776d9d5efe8 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -566,7 +566,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, goto out_free; } - ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); + ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); if (ret < 0) { wl1271_error("cmd role stop dev event completion error"); goto out_free; @@ -715,6 +715,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; + /* FIXME: Change when adding DFS */ + cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ cmd->channel = wlvif->channel; if (!bss_conf->hidden_ssid) { @@ -994,7 +996,7 @@ out: } int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 ps_mode) + u8 ps_mode, u16 auto_ps_timeout) { struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; @@ -1009,6 +1011,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, ps_params->role_id = wlvif->role_id; ps_params->ps_mode = ps_mode; + ps_params->auto_ps_timeout = auto_ps_timeout; ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params), 0); @@ -1022,13 +1025,15 @@ out: return ret; } -int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, - void *buf, size_t buf_len, int index, u32 rates) +int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, + u16 template_id, void *buf, size_t buf_len, + int index, u32 rates) { struct wl1271_cmd_template_set *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); + wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", + template_id, role_id); WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); @@ -1039,6 +1044,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, goto out; } + /* during initialization wlvif is NULL */ + cmd->role_id = role_id; cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; cmd->enabled_rates = cpu_to_le32(rates); @@ -1082,7 +1089,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) ptr = skb->data; } - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_NULL_DATA, ptr, size, 0, wlvif->basic_rate); out: @@ -1105,7 +1113,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, if (!skb) goto out; - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, + ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, skb->data, skb->len, CMD_TEMPL_KLV_IDX_NULL_DATA, wlvif->basic_rate); @@ -1130,7 +1138,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (!skb) goto out; - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_PS_POLL, skb->data, skb->len, 0, wlvif->basic_rate_set); out: @@ -1138,9 +1147,10 @@ out: return ret; } -int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, +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, u8 band) + const u8 *ie, size_t ie_len) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; @@ -1158,10 +1168,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + 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, CMD_TEMPL_CFG_PROBE_REQ_5, + ret = wl1271_cmd_template_set(wl, role_id, + CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); out: @@ -1186,10 +1198,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); if (wlvif->band == IEEE80211_BAND_2GHZ) - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + 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, CMD_TEMPL_CFG_PROBE_REQ_5, + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); if (ret < 0) @@ -1199,32 +1213,34 @@ out: return skb; } -int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, - __be32 ip_addr) +int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - int ret; + int ret, extra; + u16 fc; struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct wl12xx_arp_rsp_template tmpl; + struct sk_buff *skb; + struct wl12xx_arp_rsp_template *tmpl; struct ieee80211_hdr_3addr *hdr; struct arphdr *arp_hdr; - memset(&tmpl, 0, sizeof(tmpl)); + skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + + WL1271_EXTRA_SPACE_MAX); + if (!skb) { + wl1271_error("failed to allocate buffer for arp rsp template"); + return -ENOMEM; + } - /* mac80211 header */ - hdr = &tmpl.hdr; - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_DATA | - IEEE80211_FCTL_TODS); - memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); - memcpy(hdr->addr2, vif->addr, ETH_ALEN); - memset(hdr->addr3, 0xff, ETH_ALEN); + skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); + + tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); + memset(tmpl, 0, sizeof(tmpl)); /* llc layer */ - memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); - tmpl.llc_type = cpu_to_be16(ETH_P_ARP); + memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); + tmpl->llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ - arp_hdr = &tmpl.arp_hdr; + arp_hdr = &tmpl->arp_hdr; 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; @@ -1232,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ - memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); - tmpl.sender_ip = ip_addr; + memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); + tmpl->sender_ip = wlvif->ip_addr; - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, - &tmpl, sizeof(tmpl), 0, - wlvif->basic_rate); + /* encryption space */ + switch (wlvif->encryption_type) { + case KEY_TKIP: + extra = WL1271_EXTRA_SPACE_TKIP; + break; + case KEY_AES: + extra = WL1271_EXTRA_SPACE_AES; + break; + case KEY_NONE: + case KEY_WEP: + case KEY_GEM: + extra = 0; + break; + default: + wl1271_warning("Unknown encryption type: %d", + wlvif->encryption_type); + ret = -EINVAL; + goto out; + } + + if (extra) { + u8 *space = skb_push(skb, extra); + memset(space, 0, extra); + } + + /* QoS header - BE */ + if (wlvif->sta.qos) + memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); + /* mac80211 header */ + hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(hdr)); + fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; + if (wlvif->sta.qos) + fc |= IEEE80211_STYPE_QOS_DATA; + else + fc |= IEEE80211_STYPE_DATA; + if (wlvif->encryption_type != KEY_NONE) + fc |= IEEE80211_FCTL_PROTECTED; + + hdr->frame_control = cpu_to_le16(fc); + memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); + memcpy(hdr->addr2, vif->addr, ETH_ALEN); + memset(hdr->addr3, 0xff, ETH_ALEN); + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, + skb->data, skb->len, 0, + wlvif->basic_rate); +out: + dev_kfree_skb(skb); return ret; } @@ -1260,7 +1322,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) /* FIXME: not sure what priority to use here */ template.qos_ctrl = cpu_to_le16(0); - return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, + return wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_QOS_NULL_DATA, &template, sizeof(template), 0, wlvif->basic_rate); } @@ -1744,6 +1807,7 @@ out: } int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch) { struct wl12xx_cmd_channel_switch *cmd; @@ -1757,10 +1821,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl, goto out; } + cmd->role_id = wlvif->role_id; cmd->channel = ch_switch->channel->hw_value; cmd->switch_time = ch_switch->count; - cmd->tx_suspend = ch_switch->block_tx; - cmd->flush = 0; /* this value is ignored by the FW */ + cmd->stop_tx = ch_switch->block_tx; + + /* FIXME: control from mac80211 in the future */ + cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); if (ret < 0) { |