Staging: batman-adv: add gateway IPv6 support by filtering DHCPv6 messages
authorMarek Lindner <lindner_marek@yahoo.de>
Sun, 21 Nov 2010 23:56:05 +0000 (00:56 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 29 Nov 2010 19:09:14 +0000 (11:09 -0800)
Some additional checks will be needed in case of extension headers
like the fragmentation or hop-by-hop (for jumbo frames for example)
headers or ipsec stuff. But this patch should do for most people
for now, the rest can be added with a later one.

Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Acked-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/batman-adv/gateway_client.c

index fde1d8a952fdf880543027a39c86f0af0496ea10..0065ffb8d96d64b7cce1ed3d00567a652d5a83f1 100644 (file)
@@ -24,6 +24,7 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
@@ -403,6 +404,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 {
        struct ethhdr *ethhdr;
        struct iphdr *iphdr;
+       struct ipv6hdr *ipv6hdr;
        struct udphdr *udphdr;
        unsigned int header_len = 0;
 
@@ -424,17 +426,32 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
        }
 
        /* check for ip header */
-       if (ntohs(ethhdr->h_proto) != ETH_P_IP)
-               return 0;
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
+                       return 0;
+               iphdr = (struct iphdr *)(skb->data + header_len);
+               header_len += iphdr->ihl * 4;
 
-       if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
-               return 0;
-       iphdr = (struct iphdr *)(skb->data + header_len);
-       header_len += iphdr->ihl * 4;
+               /* check for udp header */
+               if (iphdr->protocol != IPPROTO_UDP)
+                       return 0;
+
+               break;
+       case ETH_P_IPV6:
+               if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
+                       return 0;
+               ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
+               header_len += sizeof(struct ipv6hdr);
 
-       /* check for udp header */
-       if (iphdr->protocol != IPPROTO_UDP)
+               /* check for udp header */
+               if (ipv6hdr->nexthdr != IPPROTO_UDP)
+                       return 0;
+
+               break;
+       default:
                return 0;
+       }
 
        if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
                return 0;
@@ -442,7 +459,12 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
        header_len += sizeof(struct udphdr);
 
        /* check for bootp port */
-       if (ntohs(udphdr->dest) != 67)
+       if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
+            (ntohs(udphdr->dest) != 67))
+               return 0;
+
+       if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
+           (ntohs(udphdr->dest) != 547))
                return 0;
 
        if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)