[Bluetooth] Fix compat ioctl for BNEP, CMTP and HIDP
[powerpc.git] / net / ipv6 / ip6_output.c
index c14ea1e..6671691 100644 (file)
@@ -308,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
        return 0;
 }
 
+static int ip6_forward_proxy_check(struct sk_buff *skb)
+{
+       struct ipv6hdr *hdr = skb->nh.ipv6h;
+       u8 nexthdr = hdr->nexthdr;
+       int offset;
+
+       if (ipv6_ext_hdr(nexthdr)) {
+               offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr);
+               if (offset < 0)
+                       return 0;
+       } else
+               offset = sizeof(struct ipv6hdr);
+
+       if (nexthdr == IPPROTO_ICMPV6) {
+               struct icmp6hdr *icmp6;
+
+               if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data))
+                       return 0;
+
+               icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset);
+
+               switch (icmp6->icmp6_type) {
+               case NDISC_ROUTER_SOLICITATION:
+               case NDISC_ROUTER_ADVERTISEMENT:
+               case NDISC_NEIGHBOUR_SOLICITATION:
+               case NDISC_NEIGHBOUR_ADVERTISEMENT:
+               case NDISC_REDIRECT:
+                       /* For reaction involving unicast neighbor discovery
+                        * message destined to the proxied address, pass it to
+                        * input function.
+                        */
+                       return 1;
+               default:
+                       break;
+               }
+       }
+
+       /*
+        * The proxying router can't forward traffic sent to a link-local
+        * address, so signal the sender and discard the packet. This
+        * behavior is clarified by the MIPv6 specification.
+        */
+       if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
+               dst_link_failure(skb);
+               return -1;
+       }
+
+       return 0;
+}
+
 static inline int ip6_forward_finish(struct sk_buff *skb)
 {
        return dst_output(skb);
@@ -362,6 +412,18 @@ int ip6_forward(struct sk_buff *skb)
                return -ETIMEDOUT;
        }
 
+       /* XXX: idev->cnf.proxy_ndp? */
+       if (ipv6_devconf.proxy_ndp &&
+           pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
+               int proxied = ip6_forward_proxy_check(skb);
+               if (proxied > 0)
+                       return ip6_input(skb);
+               else if (proxied < 0) {
+                       IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+                       goto drop;
+               }
+       }
+
        if (!xfrm6_route_forward(skb)) {
                IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
                goto drop;