[IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether...
[deliverable/linux.git] / net / ipv6 / raw.c
index e2b848ec98513ac9ababcc9f3d588c0fd93efc84..a082646e6f165ec24256aa0eb33e044ec74fa53f 100644 (file)
@@ -81,7 +81,8 @@ static void raw_v6_unhash(struct sock *sk)
 
 /* Grumble... icmp and ip_input want to get at this... */
 struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
-                            struct in6_addr *loc_addr, struct in6_addr *rmt_addr)
+                            struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
+                            int dif)
 {
        struct hlist_node *node;
        int is_multicast = ipv6_addr_is_multicast(loc_addr);
@@ -94,6 +95,9 @@ struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
                            !ipv6_addr_equal(&np->daddr, rmt_addr))
                                continue;
 
+                       if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
+                               continue;
+
                        if (!ipv6_addr_any(&np->rcv_saddr)) {
                                if (ipv6_addr_equal(&np->rcv_saddr, loc_addr))
                                        goto found;
@@ -137,11 +141,12 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
  *
  *     Caller owns SKB so we must make clones.
  */
-void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
+int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
        struct in6_addr *saddr;
        struct in6_addr *daddr;
        struct sock *sk;
+       int delivered = 0;
        __u8 hash;
 
        saddr = &skb->nh.ipv6h->saddr;
@@ -160,9 +165,10 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
        if (sk == NULL)
                goto out;
 
-       sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
+       sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex);
 
        while (sk) {
+               delivered = 1;
                if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
                        struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
@@ -170,10 +176,12 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                        if (clone)
                                rawv6_rcv(sk, clone);
                }
-               sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr);
+               sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
+                                    skb->dev->ifindex);
        }
 out:
        read_unlock(&raw_v6_lock);
+       return delivered;
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */
@@ -328,6 +336,8 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
 
        if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
                if (skb->ip_summed == CHECKSUM_HW) {
+                       skb_postpull_rcsum(skb, skb->nh.raw,
+                                          skb->h.raw - skb->nh.raw);
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                        if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
                                            &skb->nh.ipv6h->daddr,
This page took 0.027073 seconds and 5 git commands to generate.