Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fc169bb authored by Johannes Berg's avatar Johannes Berg Committed by Yuanyuan Liu
Browse files

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: default avatarJohannes Berg <johannes.berg@intel.com>
Git-commit: be9efdecf8ecdcc6d2221845482e7359b33a603b
Git-repo : git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git


Change-Id: I1e4083a2327c121073226aa6b75bb6b5b97cec00
CRs-fixed: 1079453
[akholaif@codeaurora.org: only picked up the declaration
 and definition of cfg80211_is_gratuitous_arp_unsolicited_na()]
Signed-off-by: default avatarAhmad Kholaif <akholaif@codeaurora.org>
parent c996d9cb
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -6186,6 +6186,16 @@ void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
/* ethtool helper */
void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);

/**
 * 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. */

/* wiphy_printk helpers, similar to dev_printk */
+53 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <linux/if_vlan.h>
#include <linux/mpls.h>
#include <linux/gcd.h>
#include <net/ndisc.h>
#include <linux/if_arp.h>
#include "core.h"
#include "rdev-ops.h"

@@ -1871,3 +1873,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);