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);
* 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);
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 */
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;
}