]> err.no Git - linux-2.6/blobdiff - net/ipv6/ip6_input.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6] / net / ipv6 / ip6_input.c
index 09a3201e408aa9fd32d78d15d525db49968462d4..17eb48b8e329af87498a1482dd0cfc64dad83789 100644 (file)
@@ -102,6 +102,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        if (hdr->version != 6)
                goto err;
 
+       /*
+        * RFC4291 2.5.3
+        * A packet received on an interface with a destination address
+        * of loopback must be dropped.
+        */
+       if (!(dev->flags & IFF_LOOPBACK) &&
+           ipv6_addr_loopback(&hdr->daddr))
+               goto err;
+
        skb->transport_header = skb->network_header + sizeof(*hdr);
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
@@ -262,21 +271,23 @@ int ip6_mc_input(struct sk_buff *skb)
                         * is for MLD (0x0000).
                         */
                        if ((ptr[2] | ptr[3]) == 0) {
+                               deliver = 0;
+
                                if (!ipv6_ext_hdr(nexthdr)) {
                                        /* BUG */
-                                       goto discard;
+                                       goto out;
                                }
                                offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
                                                          &nexthdr);
                                if (offset < 0)
-                                       goto discard;
+                                       goto out;
 
                                if (nexthdr != IPPROTO_ICMPV6)
-                                       goto discard;
+                                       goto out;
 
                                if (!pskb_may_pull(skb, (skb_network_header(skb) +
                                                   offset + 1 - skb->data)))
-                                       goto discard;
+                                       goto out;
 
                                icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
 
@@ -285,12 +296,9 @@ int ip6_mc_input(struct sk_buff *skb)
                                case ICMPV6_MGM_REPORT:
                                case ICMPV6_MGM_REDUCTION:
                                case ICMPV6_MLD2_REPORT:
+                                       deliver = 1;
                                        break;
-                               default:
-                                       /* Bogus */
-                                       goto discard;
                                }
-                               deliver = 1;
                                goto out;
                        }
                        /* unknown RA - process it normally */
@@ -308,15 +316,14 @@ int ip6_mc_input(struct sk_buff *skb)
                        ip6_mr_input(skb2);
                }
        }
-#endif
 out:
-       if (likely(deliver)) {
+#endif
+       if (likely(deliver))
                ip6_input(skb);
-               return 0;
+       else {
+               /* discard */
+               kfree_skb(skb);
        }
-discard:
-       /* discard */
-       kfree_skb(skb);
 
        return 0;
 }