aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2010-12-09 04:31:27 -0500
committerLuciano Coelho <luciano.coelho@nokia.com>2010-12-15 08:04:56 -0500
commitc5312772156bb5f9b2e95e4c91526d578426a069 (patch)
treee79bf5435e4b084230a02cb3ae07b6ac25d3baf3 /drivers
parentb69eb80bf7a6922fef8056d42b06124a7de31501 (diff)
wl12xx: add auto-arp support
The auto-arp feature of wl12xx allows the firmware to automatically response to arp requests asking for its ip. in order to use it, we configure the arp response template and enable the corresponding bit in wl1271_acx_arp_filter (along with passing its ip) Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/acx.c4
-rw-r--r--drivers/net/wireless/wl12xx/acx.h9
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c41
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h2
-rw-r--r--drivers/net/wireless/wl12xx/init.c7
-rw-r--r--drivers/net/wireless/wl12xx/main.c24
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h14
7 files changed, 93 insertions, 8 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7cbaeb6d2a37..cc4068d2b4a8 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1041,7 +1041,7 @@ out:
1041 return ret; 1041 return ret;
1042} 1042}
1043 1043
1044int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address) 1044int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
1045{ 1045{
1046 struct wl1271_acx_arp_filter *acx; 1046 struct wl1271_acx_arp_filter *acx;
1047 int ret; 1047 int ret;
@@ -1057,7 +1057,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
1057 acx->version = ACX_IPV4_VERSION; 1057 acx->version = ACX_IPV4_VERSION;
1058 acx->enable = enable; 1058 acx->enable = enable;
1059 1059
1060 if (enable == true) 1060 if (enable)
1061 memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); 1061 memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
1062 1062
1063 ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, 1063 ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 75a6306ff554..9cbc3f40c8dd 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -868,10 +868,15 @@ struct wl1271_acx_bet_enable {
868#define ACX_IPV4_VERSION 4 868#define ACX_IPV4_VERSION 4
869#define ACX_IPV6_VERSION 6 869#define ACX_IPV6_VERSION 6
870#define ACX_IPV4_ADDR_SIZE 4 870#define ACX_IPV4_ADDR_SIZE 4
871
872/* bitmap of enabled arp_filter features */
873#define ACX_ARP_FILTER_ARP_FILTERING BIT(0)
874#define ACX_ARP_FILTER_AUTO_ARP BIT(1)
875
871struct wl1271_acx_arp_filter { 876struct wl1271_acx_arp_filter {
872 struct acx_header header; 877 struct acx_header header;
873 u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ 878 u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
874 u8 enable; /* 1 to enable ARP filtering, 0 to disable */ 879 u8 enable; /* bitmap of enabled ARP filtering features */
875 u8 padding[2]; 880 u8 padding[2];
876 u8 address[16]; /* The configured device IP address - all ARP 881 u8 address[16]; /* The configured device IP address - all ARP
877 requests directed to this IP address will pass 882 requests directed to this IP address will pass
@@ -1168,7 +1173,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl);
1168int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); 1173int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
1169int wl1271_acx_smart_reflex(struct wl1271 *wl); 1174int wl1271_acx_smart_reflex(struct wl1271 *wl);
1170int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); 1175int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
1171int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address); 1176int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
1172int wl1271_acx_pm_config(struct wl1271 *wl); 1177int wl1271_acx_pm_config(struct wl1271 *wl);
1173int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); 1178int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
1174int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); 1179int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 8e438e27e496..0106628aa5a2 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -639,6 +639,47 @@ out:
639 return skb; 639 return skb;
640} 640}
641 641
642int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
643{
644 int ret;
645 struct wl12xx_arp_rsp_template tmpl;
646 struct ieee80211_hdr_3addr *hdr;
647 struct arphdr *arp_hdr;
648
649 memset(&tmpl, 0, sizeof(tmpl));
650
651 /* mac80211 header */
652 hdr = &tmpl.hdr;
653 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
654 IEEE80211_STYPE_DATA |
655 IEEE80211_FCTL_TODS);
656 memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
657 memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
658 memset(hdr->addr3, 0xff, ETH_ALEN);
659
660 /* llc layer */
661 memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
662 tmpl.llc_type = htons(ETH_P_ARP);
663
664 /* arp header */
665 arp_hdr = &tmpl.arp_hdr;
666 arp_hdr->ar_hrd = htons(ARPHRD_ETHER);
667 arp_hdr->ar_pro = htons(ETH_P_IP);
668 arp_hdr->ar_hln = ETH_ALEN;
669 arp_hdr->ar_pln = 4;
670 arp_hdr->ar_op = htons(ARPOP_REPLY);
671
672 /* arp payload */
673 memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
674 tmpl.sender_ip = ip_addr;
675
676 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
677 &tmpl, sizeof(tmpl), 0,
678 wl->basic_rate);
679
680 return ret;
681}
682
642int wl1271_build_qos_null_data(struct wl1271 *wl) 683int wl1271_build_qos_null_data(struct wl1271 *wl)
643{ 684{
644 struct ieee80211_qos_hdr template; 685 struct ieee80211_qos_hdr template;
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 111d112544fc..2a1d9db7ceb8 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -51,6 +51,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
51 const u8 *ie, size_t ie_len, u8 band); 51 const u8 *ie, size_t ie_len, u8 band);
52struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, 52struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
53 struct sk_buff *skb); 53 struct sk_buff *skb);
54int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
54int wl1271_build_qos_null_data(struct wl1271 *wl); 55int wl1271_build_qos_null_data(struct wl1271 *wl);
55int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); 56int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
56int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); 57int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
@@ -124,6 +125,7 @@ enum cmd_templ {
124 CMD_TEMPL_CTS, /* 125 CMD_TEMPL_CTS, /*
125 * For CTS-to-self (FastCTS) mechanism 126 * For CTS-to-self (FastCTS) mechanism
126 * for BT/WLAN coexistence (SoftGemini). */ 127 * for BT/WLAN coexistence (SoftGemini). */
128 CMD_TEMPL_ARP_RSP,
127 CMD_TEMPL_MAX = 0xff 129 CMD_TEMPL_MAX = 0xff
128}; 130};
129 131
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 7949d346aadb..0392e37f0d66 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -102,6 +102,13 @@ int wl1271_init_templates_config(struct wl1271 *wl)
102 if (ret < 0) 102 if (ret < 0)
103 return ret; 103 return ret;
104 104
105 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
106 sizeof
107 (struct wl12xx_arp_rsp_template),
108 0, WL1271_RATE_AUTOMATIC);
109 if (ret < 0)
110 return ret;
111
105 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { 112 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
106 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, 113 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
107 WL1271_CMD_TEMPL_MAX_SIZE, i, 114 WL1271_CMD_TEMPL_MAX_SIZE, i,
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 0b79c49cd877..f7d7cad730a2 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2110,10 +2110,26 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2110 __be32 addr = bss_conf->arp_addr_list[0]; 2110 __be32 addr = bss_conf->arp_addr_list[0];
2111 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); 2111 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2112 2112
2113 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) 2113 if (bss_conf->arp_addr_cnt == 1 &&
2114 ret = wl1271_acx_arp_ip_filter(wl, true, addr); 2114 bss_conf->arp_filter_enabled) {
2115 else 2115 /*
2116 ret = wl1271_acx_arp_ip_filter(wl, false, addr); 2116 * The template should have been configured only upon
2117 * association. however, it seems that the correct ip
2118 * isn't being set (when sending), so we have to
2119 * reconfigure the template upon every ip change.
2120 */
2121 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2122 if (ret < 0) {
2123 wl1271_warning("build arp rsp failed: %d", ret);
2124 goto out_sleep;
2125 }
2126
2127 ret = wl1271_acx_arp_ip_filter(wl,
2128 (ACX_ARP_FILTER_ARP_FILTERING |
2129 ACX_ARP_FILTER_AUTO_ARP),
2130 addr);
2131 } else
2132 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
2117 2133
2118 if (ret < 0) 2134 if (ret < 0)
2119 goto out_sleep; 2135 goto out_sleep;
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 184628027213..8ee0d3a8fa6e 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -2,6 +2,7 @@
2#define __WL12XX_80211_H__ 2#define __WL12XX_80211_H__
3 3
4#include <linux/if_ether.h> /* ETH_ALEN */ 4#include <linux/if_ether.h> /* ETH_ALEN */
5#include <linux/if_arp.h>
5 6
6/* RATES */ 7/* RATES */
7#define IEEE80211_CCK_RATE_1MB 0x02 8#define IEEE80211_CCK_RATE_1MB 0x02
@@ -140,6 +141,19 @@ struct wl12xx_probe_req_template {
140 struct wl12xx_ie_rates ext_rates; 141 struct wl12xx_ie_rates ext_rates;
141} __packed; 142} __packed;
142 143
144struct wl12xx_arp_rsp_template {
145 struct ieee80211_hdr_3addr hdr;
146
147 u8 llc_hdr[sizeof(rfc1042_header)];
148 u16 llc_type;
149
150 struct arphdr arp_hdr;
151 u8 sender_hw[ETH_ALEN];
152 u32 sender_ip;
153 u8 target_hw[ETH_ALEN];
154 u32 target_ip;
155} __packed;
156
143 157
144struct wl12xx_probe_resp_template { 158struct wl12xx_probe_resp_template {
145 struct ieee80211_header header; 159 struct ieee80211_header header;