]> err.no Git - linux-2.6/blobdiff - net/ipv6/datagram.c
ipv6: Fix duplicate initialization of rawv6_prot.destroy
[linux-2.6] / net / ipv6 / datagram.c
index f429290c2c3780ade4ebb03d88c1c551552fbf82..0f0f94a40335e7a24a68181f1791d164d49cd3e2 100644 (file)
@@ -123,11 +123,11 @@ ipv4_connected:
                                goto out;
                        }
                        sk->sk_bound_dev_if = usin->sin6_scope_id;
-                       if (!sk->sk_bound_dev_if &&
-                           (addr_type & IPV6_ADDR_MULTICAST))
-                               fl.oif = np->mcast_oif;
                }
 
+               if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST))
+                       sk->sk_bound_dev_if = np->mcast_oif;
+
                /* Connect to link-local address requires an interface */
                if (!sk->sk_bound_dev_if) {
                        err = -EINVAL;
@@ -177,8 +177,12 @@ ipv4_connected:
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
-               goto out;
+       if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
+               if (err == -EREMOTE)
+                       err = ip6_dst_blackhole(sk, &dst, &fl);
+               if (err < 0)
+                       goto out;
+       }
 
        /* source address lookup done in ip6_dst_lookup */
 
@@ -209,7 +213,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
                     __be16 port, u32 info, u8 *payload)
 {
        struct ipv6_pinfo *np  = inet6_sk(sk);
-       struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
+       struct icmp6hdr *icmph = icmp6_hdr(skb);
        struct sock_exterr_skb *serr;
 
        if (!np->recverr)
@@ -231,8 +235,8 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
                                  skb_network_header(skb);
        serr->port = port;
 
-       skb->h.raw = payload;
        __skb_pull(skb, payload - skb->data);
+       skb_reset_transport_header(skb);
 
        if (sock_queue_err_skb(sk, skb))
                kfree_skb(skb);
@@ -268,8 +272,8 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
        serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
        serr->port = fl->fl_ip_dport;
 
-       skb->h.raw = skb->tail;
-       __skb_pull(skb, skb->tail - skb->data);
+       __skb_pull(skb, skb_tail_pointer(skb) - skb->data);
+       skb_reset_transport_header(skb);
 
        if (sock_queue_err_skb(sk, skb))
                kfree_skb(skb);
@@ -492,7 +496,8 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
        return 0;
 }
 
-int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
+int datagram_send_ctl(struct net *net,
+                     struct msghdr *msg, struct flowi *fl,
                      struct ipv6_txoptions *opt,
                      int *hlimit, int *tclass)
 {
@@ -505,7 +510,6 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
 
        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
                int addr_type;
-               struct net_device *dev = NULL;
 
                if (!CMSG_OK(msg, cmsg)) {
                        err = -EINVAL;
@@ -518,6 +522,9 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                switch (cmsg->cmsg_type) {
                case IPV6_PKTINFO:
                case IPV6_2292PKTINFO:
+                   {
+                       struct net_device *dev = NULL;
+
                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
                                err = -EINVAL;
                                goto exit_f;
@@ -531,31 +538,32 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                                fl->oif = src_info->ipi6_ifindex;
                        }
 
-                       addr_type = ipv6_addr_type(&src_info->ipi6_addr);
+                       addr_type = __ipv6_addr_type(&src_info->ipi6_addr);
 
-                       if (addr_type == IPV6_ADDR_ANY)
-                               break;
+                       if (fl->oif) {
+                               dev = dev_get_by_index(net, fl->oif);
+                               if (!dev)
+                                       return -ENODEV;
+                       } else if (addr_type & IPV6_ADDR_LINKLOCAL)
+                               return -EINVAL;
 
-                       if (addr_type & IPV6_ADDR_LINKLOCAL) {
-                               if (!src_info->ipi6_ifindex)
-                                       return -EINVAL;
-                               else {
-                                       dev = dev_get_by_index(src_info->ipi6_ifindex);
-                                       if (!dev)
-                                               return -ENODEV;
-                               }
-                       }
-                       if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
-                               if (dev)
-                                       dev_put(dev);
-                               err = -EINVAL;
-                               goto exit_f;
+                       if (addr_type != IPV6_ADDR_ANY) {
+                               int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
+                               if (!ipv6_chk_addr(net, &src_info->ipi6_addr,
+                                                  strict ? dev : NULL, 0))
+                                       err = -EINVAL;
+                               else
+                                       ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
                        }
+
                        if (dev)
                                dev_put(dev);
 
-                       ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
+                       if (err)
+                               goto exit_f;
+
                        break;
+                   }
 
                case IPV6_FLOWINFO:
                        if (cmsg->cmsg_len < CMSG_LEN(4)) {
@@ -653,11 +661,10 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
 
                        switch (rthdr->type) {
-                       case IPV6_SRCRT_TYPE_0:
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
                        case IPV6_SRCRT_TYPE_2:
-#endif
                                break;
+#endif
                        default:
                                err = -EINVAL;
                                goto exit_f;
@@ -698,6 +705,11 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        }
 
                        *hlimit = *(int *)CMSG_DATA(cmsg);
+                       if (*hlimit < -1 || *hlimit > 0xff) {
+                               err = -EINVAL;
+                               goto exit_f;
+                       }
+
                        break;
 
                case IPV6_TCLASS:
@@ -723,7 +735,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                                       cmsg->cmsg_type);
                        err = -EINVAL;
                        break;
-               };
+               }
        }
 
 exit_f: