From 55ef770f4de3825b9f62b8bd20ebda492dca2e9c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Feb 2014 15:04:46 -0800 Subject: [PATCH] mac80211: implement HS2.0 gratuitous ARP/unsolicited NA dropping Taking the gratuitous ARP/unsolicited NA detection code from mwifiex (but fixing it up to not have read-after-skb-end bugs), implement the ability for userspace to request the behaviour required by HS2.0 to drop gratuitous ARP and unsolicited NA frames when proxy ARP service is enabled on the AP. Since this behaviour is only mandatory for HS2.0 and may not always be desired, make it optional - modify cfg80211/nl80211 for that. Signed-off-by: Johannes Berg Git-commit: be9efdecf8ecdcc6d2221845482e7359b33a603b Git-repo : git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git Change-Id: I1e4083a2327c121073226aa6b75bb6b5b97cec00 CRs-fixed: 621827 [akholaif@codeaurora.org: only picked up the declaration and definition of cfg80211_is_gratuitous_arp_unsolicited_na()] Signed-off-by: Ahmad Kholaif --- include/net/cfg80211.h | 9 +++++++ net/wireless/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ecaef21d003..f0fb34c2538 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3730,6 +3730,15 @@ void cfg80211_ft_event(struct net_device *netdev, * @gfp: context flags */ void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp); +/** + * cfg80211_is_gratuitous_arp_unsolicited_na - packet is grat. ARP/unsol. NA + * @skb: the input packet, must be an ethernet frame already + * + * Return: %true if the packet is a gratuitous ARP or unsolicited NA packet. + * This is used to drop packets that shouldn't occur because the AP implements + * a proxy service. + */ +bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb); /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/net/wireless/util.c b/net/wireless/util.c index b89fb9451d9..1284632fc6f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "core.h" struct ieee80211_rate * @@ -1131,3 +1133,54 @@ EXPORT_SYMBOL(rfc1042_header); const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); + +bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb) +{ + const struct ethhdr *eth = (void *)skb->data; + const struct { + struct arphdr hdr; + u8 ar_sha[ETH_ALEN]; + u8 ar_sip[4]; + u8 ar_tha[ETH_ALEN]; + u8 ar_tip[4]; + } __packed *arp; + const struct ipv6hdr *ipv6; + const struct icmp6hdr *icmpv6; + + switch (eth->h_proto) { + case cpu_to_be16(ETH_P_ARP): + /* can't say - but will probably be dropped later anyway */ + if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*arp))) + return false; + + arp = (void *)(eth + 1); + + if ((arp->hdr.ar_op == cpu_to_be16(ARPOP_REPLY) || + arp->hdr.ar_op == cpu_to_be16(ARPOP_REQUEST)) && + !memcmp(arp->ar_sip, arp->ar_tip, sizeof(arp->ar_sip))) + return true; + break; + case cpu_to_be16(ETH_P_IPV6): + /* can't say - but will probably be dropped later anyway */ + if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*ipv6) + + sizeof(*icmpv6))) + return false; + + ipv6 = (void *)(eth + 1); + icmpv6 = (void *)(ipv6 + 1); + + if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT && + !memcmp(&ipv6->saddr, &ipv6->daddr, sizeof(ipv6->saddr))) + return true; + break; + default: + /* + * no need to support other protocols, proxy service isn't + * specified for any others + */ + break; + } + + return false; +} +EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na);