ipv6: handle -EFAULT from skb_copy_bits
[pandora-kernel.git] / net / ipv6 / raw.c
index 9287f3e..ce501a7 100644 (file)
@@ -576,8 +576,11 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
        }
 
        offset += skb_transport_offset(skb);
-       if (skb_copy_bits(skb, offset, &csum, 2))
-               BUG();
+       err = skb_copy_bits(skb, offset, &csum, 2);
+       if (err < 0) {
+               ip6_flush_pending_frames(sk);
+               goto out;
+       }
 
        /* in case cksum was not initialized */
        if (unlikely(csum))
@@ -724,6 +727,7 @@ static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
 static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                   struct msghdr *msg, size_t len)
 {
+       struct ipv6_txoptions *opt_to_free = NULL;
        struct ipv6_txoptions opt_space;
        struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
        struct in6_addr *daddr, *final_p, final;
@@ -830,8 +834,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                if (!(opt->opt_nflen|opt->opt_flen))
                        opt = NULL;
        }
-       if (opt == NULL)
-               opt = np->opt;
+       if (!opt) {
+               opt = txopt_get(np);
+               opt_to_free = opt;
+       }
        if (flowlabel)
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
        opt = ipv6_fixup_options(&opt_space, opt);
@@ -896,6 +902,7 @@ done:
        dst_release(dst);
 out:
        fl6_sock_release(flowlabel);
+       txopt_put(opt_to_free);
        return err<0?err:len;
 do_confirm:
        dst_confirm(dst);