#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in6.h>
+#include <linux/if_arp.h>
#include <linux/if_vlan.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
return skb;
}
+/**
+ * is_spoofed_arp - check for invalid ARP packet
+ *
+ * @skb: skbuff containing an Ethernet packet, with network header pointing
+ * just past the Ethernet and optional 802.1Q header.
+ * @key: flow key extracted from @skb by flow_extract()
+ *
+ * Returns true if @skb is an invalid Ethernet+IPv4 ARP packet: one with screwy
+ * or truncated header fields or one whose inner and outer Ethernet address
+ * differ.
+ */
+static bool is_spoofed_arp(struct sk_buff *skb, const struct odp_flow_key *key)
+{
+ struct arp_eth_header *arp;
+
+ if (key->dl_type != htons(ETH_P_ARP))
+ return false;
+
+ if (skb_network_offset(skb) + sizeof(struct arp_eth_header) > skb->len)
+ return true;
+
+ arp = (struct arp_eth_header *)skb_network_header(skb);
+ return (arp->ar_hrd != htons(ARPHRD_ETHER) ||
+ arp->ar_pro != htons(ETH_P_IP) ||
+ arp->ar_hln != ETH_ALEN ||
+ arp->ar_pln != 4 ||
+ compare_ether_addr(arp->ar_sha, eth_hdr(skb)->h_source));
+}
+
static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
{
struct dp_port *p;
case ODPAT_POP_PRIORITY:
skb->priority = priority;
break;
+
+ case ODPAT_DROP_SPOOFED_ARP:
+ if (unlikely(is_spoofed_arp(skb, key)))
+ goto exit;
+ break;
}
if (!skb)
return -ENOMEM;
}
+exit:
if (prev_port != -1)
do_output(dp, skb, prev_port);
else