|
@@ -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) {
|