aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2012-02-02 05:22:09 -0500
committerLuciano Coelho <coelho@ti.com>2012-02-15 01:38:34 -0500
commit5ec8a448e0e978103bc5ca7136084b5e2b36989e (patch)
tree9b171398637871b562608a656bed6092999a96d1 /drivers/net/wireless/wl12xx
parent20ae7e5e4b13937da6882bf84b080eb31feb9a7b (diff)
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: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c88
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h3
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c1
-rw-r--r--drivers/net/wireless/wl12xx/init.c6
-rw-r--r--drivers/net/wireless/wl12xx/main.c31
-rw-r--r--drivers/net/wireless/wl12xx/tx.c11
-rw-r--r--drivers/net/wireless/wl12xx/tx.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h6
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h2
9 files changed, 117 insertions, 35 deletions
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index bf3c37bd1f12..b776d9d5efe8 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1213,32 +1213,34 @@ out:
1213 return skb; 1213 return skb;
1214} 1214}
1215 1215
1216int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1216int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
1217 __be32 ip_addr)
1218{ 1217{
1219 int ret; 1218 int ret, extra;
1219 u16 fc;
1220 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 1220 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
1221 struct wl12xx_arp_rsp_template tmpl; 1221 struct sk_buff *skb;
1222 struct wl12xx_arp_rsp_template *tmpl;
1222 struct ieee80211_hdr_3addr *hdr; 1223 struct ieee80211_hdr_3addr *hdr;
1223 struct arphdr *arp_hdr; 1224 struct arphdr *arp_hdr;
1224 1225
1225 memset(&tmpl, 0, sizeof(tmpl)); 1226 skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) +
1227 WL1271_EXTRA_SPACE_MAX);
1228 if (!skb) {
1229 wl1271_error("failed to allocate buffer for arp rsp template");
1230 return -ENOMEM;
1231 }
1226 1232
1227 /* mac80211 header */ 1233 skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
1228 hdr = &tmpl.hdr; 1234
1229 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 1235 tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
1230 IEEE80211_STYPE_DATA | 1236 memset(tmpl, 0, sizeof(tmpl));
1231 IEEE80211_FCTL_TODS);
1232 memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
1233 memcpy(hdr->addr2, vif->addr, ETH_ALEN);
1234 memset(hdr->addr3, 0xff, ETH_ALEN);
1235 1237
1236 /* llc layer */ 1238 /* llc layer */
1237 memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); 1239 memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
1238 tmpl.llc_type = cpu_to_be16(ETH_P_ARP); 1240 tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
1239 1241
1240 /* arp header */ 1242 /* arp header */
1241 arp_hdr = &tmpl.arp_hdr; 1243 arp_hdr = &tmpl->arp_hdr;
1242 arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); 1244 arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
1243 arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); 1245 arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
1244 arp_hdr->ar_hln = ETH_ALEN; 1246 arp_hdr->ar_hln = ETH_ALEN;
@@ -1246,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1246 arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); 1248 arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
1247 1249
1248 /* arp payload */ 1250 /* arp payload */
1249 memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); 1251 memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
1250 tmpl.sender_ip = ip_addr; 1252 tmpl->sender_ip = wlvif->ip_addr;
1253
1254 /* encryption space */
1255 switch (wlvif->encryption_type) {
1256 case KEY_TKIP:
1257 extra = WL1271_EXTRA_SPACE_TKIP;
1258 break;
1259 case KEY_AES:
1260 extra = WL1271_EXTRA_SPACE_AES;
1261 break;
1262 case KEY_NONE:
1263 case KEY_WEP:
1264 case KEY_GEM:
1265 extra = 0;
1266 break;
1267 default:
1268 wl1271_warning("Unknown encryption type: %d",
1269 wlvif->encryption_type);
1270 ret = -EINVAL;
1271 goto out;
1272 }
1273
1274 if (extra) {
1275 u8 *space = skb_push(skb, extra);
1276 memset(space, 0, extra);
1277 }
1278
1279 /* QoS header - BE */
1280 if (wlvif->sta.qos)
1281 memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16));
1282
1283 /* mac80211 header */
1284 hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
1285 memset(hdr, 0, sizeof(hdr));
1286 fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
1287 if (wlvif->sta.qos)
1288 fc |= IEEE80211_STYPE_QOS_DATA;
1289 else
1290 fc |= IEEE80211_STYPE_DATA;
1291 if (wlvif->encryption_type != KEY_NONE)
1292 fc |= IEEE80211_FCTL_PROTECTED;
1293
1294 hdr->frame_control = cpu_to_le16(fc);
1295 memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
1296 memcpy(hdr->addr2, vif->addr, ETH_ALEN);
1297 memset(hdr->addr3, 0xff, ETH_ALEN);
1251 1298
1252 ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, 1299 ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
1253 &tmpl, sizeof(tmpl), 0, 1300 skb->data, skb->len, 0,
1254 wlvif->basic_rate); 1301 wlvif->basic_rate);
1255 1302out:
1303 dev_kfree_skb(skb);
1256 return ret; 1304 return ret;
1257} 1305}
1258 1306
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 83a2a2edb261..de217d92516b 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -67,8 +67,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
67struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, 67struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
68 struct wl12xx_vif *wlvif, 68 struct wl12xx_vif *wlvif,
69 struct sk_buff *skb); 69 struct sk_buff *skb);
70int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, 70int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
71 __be32 ip_addr);
72int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); 71int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
73int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, 72int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
74 struct wl12xx_vif *wlvif); 73 struct wl12xx_vif *wlvif);
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 1c2623850eae..f063c704ebcf 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -579,6 +579,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
579 VIF_STATE_PRINT_INT(sta.basic_rate_idx); 579 VIF_STATE_PRINT_INT(sta.basic_rate_idx);
580 VIF_STATE_PRINT_INT(sta.ap_rate_idx); 580 VIF_STATE_PRINT_INT(sta.ap_rate_idx);
581 VIF_STATE_PRINT_INT(sta.p2p_rate_idx); 581 VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
582 VIF_STATE_PRINT_INT(sta.qos);
582 } else { 583 } else {
583 VIF_STATE_PRINT_INT(ap.global_hlid); 584 VIF_STATE_PRINT_INT(ap.global_hlid);
584 VIF_STATE_PRINT_INT(ap.bcast_hlid); 585 VIF_STATE_PRINT_INT(ap.bcast_hlid);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index fcf2b128f9a4..acc03799fc66 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -37,6 +37,7 @@
37int wl1271_init_templates_config(struct wl1271 *wl) 37int wl1271_init_templates_config(struct wl1271 *wl)
38{ 38{
39 int ret, i; 39 int ret, i;
40 size_t max_size;
40 41
41 /* send empty templates for fw memory reservation */ 42 /* send empty templates for fw memory reservation */
42 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, 43 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
@@ -89,10 +90,11 @@ int wl1271_init_templates_config(struct wl1271 *wl)
89 if (ret < 0) 90 if (ret < 0)
90 return ret; 91 return ret;
91 92
93 max_size = sizeof(struct wl12xx_arp_rsp_template) +
94 WL1271_EXTRA_SPACE_MAX;
92 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, 95 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
93 CMD_TEMPL_ARP_RSP, NULL, 96 CMD_TEMPL_ARP_RSP, NULL,
94 sizeof 97 max_size,
95 (struct wl12xx_arp_rsp_template),
96 0, WL1271_RATE_AUTOMATIC); 98 0, WL1271_RATE_AUTOMATIC);
97 if (ret < 0) 99 if (ret < 0)
98 return ret; 100 return ret;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index b828149a1655..a84fe28873ea 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2324,6 +2324,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2324 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) 2324 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
2325 wl1271_info("JOIN while associated."); 2325 wl1271_info("JOIN while associated.");
2326 2326
2327 /* clear encryption type */
2328 wlvif->encryption_type = KEY_NONE;
2329
2327 if (set_assoc) 2330 if (set_assoc)
2328 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); 2331 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
2329 2332
@@ -2981,6 +2984,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2981 wl1271_error("Could not add or replace key"); 2984 wl1271_error("Could not add or replace key");
2982 goto out_sleep; 2985 goto out_sleep;
2983 } 2986 }
2987
2988 /*
2989 * reconfiguring arp response if the unicast (or common)
2990 * encryption key type was changed
2991 */
2992 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
2993 (sta || key_type == KEY_WEP) &&
2994 wlvif->encryption_type != key_type) {
2995 wlvif->encryption_type = key_type;
2996 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
2997 if (ret < 0) {
2998 wl1271_warning("build arp rsp failed: %d", ret);
2999 goto out_sleep;
3000 }
3001 }
2984 break; 3002 break;
2985 3003
2986 case DISABLE_KEY: 3004 case DISABLE_KEY:
@@ -3822,19 +3840,22 @@ sta_not_found:
3822 if (ret < 0) 3840 if (ret < 0)
3823 goto out; 3841 goto out;
3824 3842
3825 if (changed & BSS_CHANGED_ARP_FILTER) { 3843 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3844 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3826 __be32 addr = bss_conf->arp_addr_list[0]; 3845 __be32 addr = bss_conf->arp_addr_list[0];
3846 wlvif->sta.qos = bss_conf->qos;
3827 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); 3847 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3828 3848
3829 if (bss_conf->arp_addr_cnt == 1 && 3849 if (bss_conf->arp_addr_cnt == 1 &&
3830 bss_conf->arp_filter_enabled) { 3850 bss_conf->arp_filter_enabled) {
3851 wlvif->ip_addr = addr;
3831 /* 3852 /*
3832 * The template should have been configured only upon 3853 * The template should have been configured only upon
3833 * association. however, it seems that the correct ip 3854 * association. however, it seems that the correct ip
3834 * isn't being set (when sending), so we have to 3855 * isn't being set (when sending), so we have to
3835 * reconfigure the template upon every ip change. 3856 * reconfigure the template upon every ip change.
3836 */ 3857 */
3837 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr); 3858 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3838 if (ret < 0) { 3859 if (ret < 0) {
3839 wl1271_warning("build arp rsp failed: %d", ret); 3860 wl1271_warning("build arp rsp failed: %d", ret);
3840 goto out; 3861 goto out;
@@ -3843,8 +3864,10 @@ sta_not_found:
3843 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 3864 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3844 ACX_ARP_FILTER_ARP_FILTERING, 3865 ACX_ARP_FILTER_ARP_FILTERING,
3845 addr); 3866 addr);
3846 } else 3867 } else {
3868 wlvif->ip_addr = 0;
3847 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); 3869 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
3870 }
3848 3871
3849 if (ret < 0) 3872 if (ret < 0)
3850 goto out; 3873 goto out;
@@ -5007,7 +5030,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
5007 }; 5030 };
5008 5031
5009 /* The tx descriptor buffer and the TKIP space. */ 5032 /* The tx descriptor buffer and the TKIP space. */
5010 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + 5033 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
5011 sizeof(struct wl1271_tx_hw_descr); 5034 sizeof(struct wl1271_tx_hw_descr);
5012 5035
5013 /* unit us */ 5036 /* unit us */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 1f5cc2af5bc6..6446e4d3e8f9 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
386 386
387 if (info->control.hw_key && 387 if (info->control.hw_key &&
388 info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 388 info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
389 extra = WL1271_TKIP_IV_SPACE; 389 extra = WL1271_EXTRA_SPACE_TKIP;
390 390
391 if (info->control.hw_key) { 391 if (info->control.hw_key) {
392 bool is_wep; 392 bool is_wep;
@@ -861,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
861 if (info->control.hw_key && 861 if (info->control.hw_key &&
862 info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 862 info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
863 int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 863 int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
864 memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); 864 memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
865 skb_pull(skb, WL1271_TKIP_IV_SPACE); 865 hdrlen);
866 skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
866 } 867 }
867 868
868 wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 869 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 info->control.hw_key->cipher == 1005 info->control.hw_key->cipher ==
1005 WLAN_CIPHER_SUITE_TKIP) { 1006 WLAN_CIPHER_SUITE_TKIP) {
1006 int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1007 int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1007 memmove(skb->data + WL1271_TKIP_IV_SPACE, 1008 memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
1008 skb->data, hdrlen); 1009 skb->data, hdrlen);
1009 skb_pull(skb, WL1271_TKIP_IV_SPACE); 1010 skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
1010 } 1011 }
1011 1012
1012 info->status.rates[0].idx = -1; 1013 info->status.rates[0].idx = -1;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 7ceb3ceaa648..e3977b55a710 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -52,7 +52,9 @@
52#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf 52#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
53 53
54#define WL1271_TX_ALIGN_TO 4 54#define WL1271_TX_ALIGN_TO 4
55#define WL1271_TKIP_IV_SPACE 4 55#define WL1271_EXTRA_SPACE_TKIP 4
56#define WL1271_EXTRA_SPACE_AES 8
57#define WL1271_EXTRA_SPACE_MAX 8
56 58
57/* Used for management frames and dummy packets */ 59/* Used for management frames and dummy packets */
58#define WL1271_TID_MGMT 7 60#define WL1271_TID_MGMT 7
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 61c58c13fa90..81af416d17da 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -507,6 +507,8 @@ struct wl12xx_vif {
507 u8 basic_rate_idx; 507 u8 basic_rate_idx;
508 u8 ap_rate_idx; 508 u8 ap_rate_idx;
509 u8 p2p_rate_idx; 509 u8 p2p_rate_idx;
510
511 bool qos;
510 } sta; 512 } sta;
511 struct { 513 struct {
512 u8 global_hlid; 514 u8 global_hlid;
@@ -573,6 +575,10 @@ struct wl12xx_vif {
573 int rssi_thold; 575 int rssi_thold;
574 int last_rssi_event; 576 int last_rssi_event;
575 577
578 /* save the current encryption type for auto-arp config */
579 u8 encryption_type;
580 __be32 ip_addr;
581
576 /* RX BA constraint value */ 582 /* RX BA constraint value */
577 bool ba_support; 583 bool ba_support;
578 bool ba_allowed; 584 bool ba_allowed;
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 8f0ffaf62309..22b0bc98d7b5 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template {
117} __packed; 117} __packed;
118 118
119struct wl12xx_arp_rsp_template { 119struct wl12xx_arp_rsp_template {
120 struct ieee80211_hdr_3addr hdr; 120 /* not including ieee80211 header */
121 121
122 u8 llc_hdr[sizeof(rfc1042_header)]; 122 u8 llc_hdr[sizeof(rfc1042_header)];
123 __be16 llc_type; 123 __be16 llc_type;