Skip to content

Commit

Permalink
wl12xx: add auto-arp support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eliad Peller authored and Luciano Coelho committed Dec 15, 2010
1 parent b69eb80 commit c531277
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 8 deletions.
4 changes: 2 additions & 2 deletions drivers/net/wireless/wl12xx/acx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
return ret;
}

int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
{
struct wl1271_acx_arp_filter *acx;
int ret;
Expand All @@ -1057,7 +1057,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;

if (enable == true)
if (enable)
memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);

ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
Expand Down
9 changes: 7 additions & 2 deletions drivers/net/wireless/wl12xx/acx.h
Original file line number Diff line number Diff line change
Expand Up @@ -868,10 +868,15 @@ struct wl1271_acx_bet_enable {
#define ACX_IPV4_VERSION 4
#define ACX_IPV6_VERSION 6
#define ACX_IPV4_ADDR_SIZE 4

/* bitmap of enabled arp_filter features */
#define ACX_ARP_FILTER_ARP_FILTERING BIT(0)
#define ACX_ARP_FILTER_AUTO_ARP BIT(1)

struct wl1271_acx_arp_filter {
struct acx_header header;
u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
u8 enable; /* 1 to enable ARP filtering, 0 to disable */
u8 enable; /* bitmap of enabled ARP filtering features */
u8 padding[2];
u8 address[16]; /* The configured device IP address - all ARP
requests directed to this IP address will pass
Expand Down Expand Up @@ -1168,7 +1173,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
int wl1271_acx_pm_config(struct wl1271 *wl);
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
Expand Down
41 changes: 41 additions & 0 deletions drivers/net/wireless/wl12xx/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,47 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
return skb;
}

int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
{
int ret;
struct wl12xx_arp_rsp_template tmpl;
struct ieee80211_hdr_3addr *hdr;
struct arphdr *arp_hdr;

memset(&tmpl, 0, sizeof(tmpl));

/* mac80211 header */
hdr = &tmpl.hdr;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_DATA |
IEEE80211_FCTL_TODS);
memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
memset(hdr->addr3, 0xff, ETH_ALEN);

/* llc layer */
memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
tmpl.llc_type = htons(ETH_P_ARP);

/* arp header */
arp_hdr = &tmpl.arp_hdr;
arp_hdr->ar_hrd = htons(ARPHRD_ETHER);
arp_hdr->ar_pro = htons(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN;
arp_hdr->ar_pln = 4;
arp_hdr->ar_op = htons(ARPOP_REPLY);

/* arp payload */
memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
tmpl.sender_ip = ip_addr;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
&tmpl, sizeof(tmpl), 0,
wl->basic_rate);

return ret;
}

int wl1271_build_qos_null_data(struct wl1271 *wl)
{
struct ieee80211_qos_hdr template;
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/wl12xx/cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
const u8 *ie, size_t ie_len, u8 band);
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct sk_buff *skb);
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
Expand Down Expand Up @@ -124,6 +125,7 @@ enum cmd_templ {
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
CMD_TEMPL_ARP_RSP,
CMD_TEMPL_MAX = 0xff
};

Expand Down
7 changes: 7 additions & 0 deletions drivers/net/wireless/wl12xx/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
sizeof
(struct wl12xx_arp_rsp_template),
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
WL1271_CMD_TEMPL_MAX_SIZE, i,
Expand Down
24 changes: 20 additions & 4 deletions drivers/net/wireless/wl12xx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2110,10 +2110,26 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
__be32 addr = bss_conf->arp_addr_list[0];
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);

if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
ret = wl1271_acx_arp_ip_filter(wl, true, addr);
else
ret = wl1271_acx_arp_ip_filter(wl, false, addr);
if (bss_conf->arp_addr_cnt == 1 &&
bss_conf->arp_filter_enabled) {
/*
* The template should have been configured only upon
* association. however, it seems that the correct ip
* isn't being set (when sending), so we have to
* reconfigure the template upon every ip change.
*/
ret = wl1271_cmd_build_arp_rsp(wl, addr);
if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret);
goto out_sleep;
}

ret = wl1271_acx_arp_ip_filter(wl,
(ACX_ARP_FILTER_ARP_FILTERING |
ACX_ARP_FILTER_AUTO_ARP),
addr);
} else
ret = wl1271_acx_arp_ip_filter(wl, 0, addr);

if (ret < 0)
goto out_sleep;
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/wireless/wl12xx/wl12xx_80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define __WL12XX_80211_H__

#include <linux/if_ether.h> /* ETH_ALEN */
#include <linux/if_arp.h>

/* RATES */
#define IEEE80211_CCK_RATE_1MB 0x02
Expand Down Expand Up @@ -140,6 +141,19 @@ struct wl12xx_probe_req_template {
struct wl12xx_ie_rates ext_rates;
} __packed;

struct wl12xx_arp_rsp_template {
struct ieee80211_hdr_3addr hdr;

u8 llc_hdr[sizeof(rfc1042_header)];
u16 llc_type;

struct arphdr arp_hdr;
u8 sender_hw[ETH_ALEN];
u32 sender_ip;
u8 target_hw[ETH_ALEN];
u32 target_ip;
} __packed;


struct wl12xx_probe_resp_template {
struct ieee80211_header header;
Expand Down

0 comments on commit c531277

Please sign in to comment.