Commit 5ec8a448 authored by Eliad Peller's avatar Eliad Peller Committed by Luciano Coelho

wl12xx: consider encryption and QoS in auto arp template

When configuring the arp response template,
and encryption is enabled, we should add some
space and set the protected flag bit in the fc.

In order to track the encryption type, set
wlvif->encryption_type when setting an encryption key,
and reconfigure the arp response. Clear this field on
wl1271_join, as keys have to be re-configured
anyway after a join command.

Similarly, track whether QoS is configured.
Signed-off-by: default avatarEliad Peller <eliad@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 20ae7e5e
...@@ -1213,32 +1213,34 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, ...@@ -1213,32 +1213,34 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
return skb; return skb;
} }
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
__be32 ip_addr)
{ {
int ret; int ret, extra;
u16 fc;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 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 ieee80211_hdr_3addr *hdr;
struct arphdr *arp_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 */ skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
hdr = &tmpl.hdr;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
IEEE80211_STYPE_DATA | memset(tmpl, 0, sizeof(tmpl));
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);
/* llc layer */ /* llc layer */
memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
tmpl.llc_type = cpu_to_be16(ETH_P_ARP); tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
/* arp header */ /* arp header */
arp_hdr = &tmpl.arp_hdr; arp_hdr = &tmpl->arp_hdr;
arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_hln = ETH_ALEN;
...@@ -1246,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1246,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_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
/* arp payload */ /* arp payload */
memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
tmpl.sender_ip = ip_addr; tmpl->sender_ip = wlvif->ip_addr;
/* 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, ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
&tmpl, sizeof(tmpl), 0, skb->data, skb->len, 0,
wlvif->basic_rate); wlvif->basic_rate);
out:
dev_kfree_skb(skb);
return ret; return ret;
} }
......
...@@ -67,8 +67,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -67,8 +67,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct wl12xx_vif *wlvif, struct wl12xx_vif *wlvif,
struct sk_buff *skb); struct sk_buff *skb);
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
__be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif);
......
...@@ -579,6 +579,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, ...@@ -579,6 +579,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(sta.basic_rate_idx); VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx); VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx); VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
VIF_STATE_PRINT_INT(sta.qos);
} else { } else {
VIF_STATE_PRINT_INT(ap.global_hlid); VIF_STATE_PRINT_INT(ap.global_hlid);
VIF_STATE_PRINT_INT(ap.bcast_hlid); VIF_STATE_PRINT_INT(ap.bcast_hlid);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
int wl1271_init_templates_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl)
{ {
int ret, i; int ret, i;
size_t max_size;
/* send empty templates for fw memory reservation */ /* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
...@@ -89,10 +90,11 @@ int wl1271_init_templates_config(struct wl1271 *wl) ...@@ -89,10 +90,11 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
max_size = sizeof(struct wl12xx_arp_rsp_template) +
WL1271_EXTRA_SPACE_MAX;
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_ARP_RSP, NULL, CMD_TEMPL_ARP_RSP, NULL,
sizeof max_size,
(struct wl12xx_arp_rsp_template),
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -2324,6 +2324,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -2324,6 +2324,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
wl1271_info("JOIN while associated."); wl1271_info("JOIN while associated.");
/* clear encryption type */
wlvif->encryption_type = KEY_NONE;
if (set_assoc) if (set_assoc)
set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
...@@ -2981,6 +2984,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2981,6 +2984,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_error("Could not add or replace key"); wl1271_error("Could not add or replace key");
goto out_sleep; goto out_sleep;
} }
/*
* reconfiguring arp response if the unicast (or common)
* encryption key type was changed
*/
if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
(sta || key_type == KEY_WEP) &&
wlvif->encryption_type != key_type) {
wlvif->encryption_type = key_type;
ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret);
goto out_sleep;
}
}
break; break;
case DISABLE_KEY: case DISABLE_KEY:
...@@ -3822,19 +3840,22 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3822,19 +3840,22 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out; goto out;
if (changed & BSS_CHANGED_ARP_FILTER) { if ((changed & BSS_CHANGED_ARP_FILTER) ||
(!is_ibss && (changed & BSS_CHANGED_QOS))) {
__be32 addr = bss_conf->arp_addr_list[0]; __be32 addr = bss_conf->arp_addr_list[0];
wlvif->sta.qos = bss_conf->qos;
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
if (bss_conf->arp_addr_cnt == 1 && if (bss_conf->arp_addr_cnt == 1 &&
bss_conf->arp_filter_enabled) { bss_conf->arp_filter_enabled) {
wlvif->ip_addr = addr;
/* /*
* The template should have been configured only upon * The template should have been configured only upon
* association. however, it seems that the correct ip * association. however, it seems that the correct ip
* isn't being set (when sending), so we have to * isn't being set (when sending), so we have to
* reconfigure the template upon every ip change. * reconfigure the template upon every ip change.
*/ */
ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr); ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
if (ret < 0) { if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret); wl1271_warning("build arp rsp failed: %d", ret);
goto out; goto out;
...@@ -3843,8 +3864,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3843,8 +3864,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_acx_arp_ip_filter(wl, wlvif, ret = wl1271_acx_arp_ip_filter(wl, wlvif,
ACX_ARP_FILTER_ARP_FILTERING, ACX_ARP_FILTER_ARP_FILTERING,
addr); addr);
} else } else {
wlvif->ip_addr = 0;
ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
}
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -5007,7 +5030,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -5007,7 +5030,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
}; };
/* The tx descriptor buffer and the TKIP space. */ /* The tx descriptor buffer and the TKIP space. */
wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
sizeof(struct wl1271_tx_hw_descr); sizeof(struct wl1271_tx_hw_descr);
/* unit us */ /* unit us */
......
...@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
extra = WL1271_TKIP_IV_SPACE; extra = WL1271_EXTRA_SPACE_TKIP;
if (info->control.hw_key) { if (info->control.hw_key) {
bool is_wep; bool is_wep;
...@@ -861,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -861,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb); int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
skb_pull(skb, WL1271_TKIP_IV_SPACE); hdrlen);
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
} }
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
...@@ -1004,9 +1005,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -1004,9 +1005,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info->control.hw_key->cipher == info->control.hw_key->cipher ==
WLAN_CIPHER_SUITE_TKIP) { WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb); int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_TKIP_IV_SPACE, memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
skb->data, hdrlen); skb->data, hdrlen);
skb_pull(skb, WL1271_TKIP_IV_SPACE); skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
} }
info->status.rates[0].idx = -1; info->status.rates[0].idx = -1;
......
...@@ -52,7 +52,9 @@ ...@@ -52,7 +52,9 @@
#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
#define WL1271_TX_ALIGN_TO 4 #define WL1271_TX_ALIGN_TO 4
#define WL1271_TKIP_IV_SPACE 4 #define WL1271_EXTRA_SPACE_TKIP 4
#define WL1271_EXTRA_SPACE_AES 8
#define WL1271_EXTRA_SPACE_MAX 8
/* Used for management frames and dummy packets */ /* Used for management frames and dummy packets */
#define WL1271_TID_MGMT 7 #define WL1271_TID_MGMT 7
......
...@@ -507,6 +507,8 @@ struct wl12xx_vif { ...@@ -507,6 +507,8 @@ struct wl12xx_vif {
u8 basic_rate_idx; u8 basic_rate_idx;
u8 ap_rate_idx; u8 ap_rate_idx;
u8 p2p_rate_idx; u8 p2p_rate_idx;
bool qos;
} sta; } sta;
struct { struct {
u8 global_hlid; u8 global_hlid;
...@@ -573,6 +575,10 @@ struct wl12xx_vif { ...@@ -573,6 +575,10 @@ struct wl12xx_vif {
int rssi_thold; int rssi_thold;
int last_rssi_event; int last_rssi_event;
/* save the current encryption type for auto-arp config */
u8 encryption_type;
__be32 ip_addr;
/* RX BA constraint value */ /* RX BA constraint value */
bool ba_support; bool ba_support;
bool ba_allowed; bool ba_allowed;
......
...@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template { ...@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template {
} __packed; } __packed;
struct wl12xx_arp_rsp_template { struct wl12xx_arp_rsp_template {
struct ieee80211_hdr_3addr hdr; /* not including ieee80211 header */
u8 llc_hdr[sizeof(rfc1042_header)]; u8 llc_hdr[sizeof(rfc1042_header)];
__be16 llc_type; __be16 llc_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment