patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / net / ipv6 / raw.c
index c407c7e..0e1b275 100644 (file)
@@ -283,7 +283,8 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb,
 
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
-       if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
+       if ((raw6_sk(sk)->checksum || sk->sk_filter) && 
+           skb->ip_summed != CHECKSUM_UNNECESSARY) {
                if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
                        /* FIXME: increment a raw6 drops counter here */
                        kfree_skb(skb);
@@ -408,10 +409,8 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
                ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
                sin6->sin6_flowinfo = 0;
                sin6->sin6_scope_id = 0;
-               if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
-                       struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
-                       sin6->sin6_scope_id = opt->iif;
-               }
+               if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+                       sin6->sin6_scope_id = IP6CB(skb)->iif;
        }
 
        sock_recv_timestamp(msg, sk, skb);
@@ -452,6 +451,10 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct r
        struct sk_buff *skb;
        int err = 0;
        u16 *csum;
+       u32 tmp_csum;
+
+       if (!opt->checksum)
+               goto send;
 
        if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
                goto out;
@@ -463,29 +466,32 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct r
                goto out;
        }
 
+       /* should be check HW csum miyazawa */
        if (skb_queue_len(&sk->sk_write_queue) == 1) {
                /*
                 * Only one fragment on the socket.
                 */
-               /* should be check HW csum miyazawa */
-               *csum = csum_ipv6_magic(&fl->fl6_src,
-                                       &fl->fl6_dst,
-                                       len, fl->proto, skb->csum);
+               tmp_csum = skb->csum;
        } else {
-               u32 tmp_csum = 0;
+               tmp_csum = 0;
 
                skb_queue_walk(&sk->sk_write_queue, skb) {
                        tmp_csum = csum_add(tmp_csum, skb->csum);
                }
-
-               tmp_csum = csum_ipv6_magic(&fl->fl6_src,
-                                          &fl->fl6_dst,
-                                          len, fl->proto, tmp_csum);
-               *csum = tmp_csum;
        }
+
+       /* in case cksum was not initialized */
+       if (unlikely(*csum))
+               tmp_csum = csum_sub(tmp_csum, *csum);
+
+       *csum = csum_ipv6_magic(&fl->fl6_src,
+                               &fl->fl6_dst,
+                               len, fl->proto, tmp_csum);
+
        if (*csum == 0)
                *csum = -1;
-       ip6_push_pending_frames(sk);
+send:
+       err = ip6_push_pending_frames(sk);
 out:
        return err;
 }
@@ -527,7 +533,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        if (err)
                goto error_fault;
 
-       IP6_INC_STATS(Ip6OutRequests);          
+       IP6_INC_STATS(OutRequests);             
        err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
                      dst_output);
        if (err > 0)
@@ -541,7 +547,7 @@ error_fault:
        err = -EFAULT;
        kfree_skb(skb);
 error:
-       IP6_INC_STATS(Ip6OutDiscards);
+       IP6_INC_STATS(OutDiscards);
        return err; 
 }
 static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -702,13 +708,8 @@ back_from_confirm:
 
                if (err)
                        ip6_flush_pending_frames(sk);
-               else if (!(msg->msg_flags & MSG_MORE)) {
-                       if (raw_opt->checksum) {
-                               err = rawv6_push_pending_frames(sk, &fl, raw_opt, len);
-                       } else {
-                               err = ip6_push_pending_frames(sk);
-                       }
-               }
+               else if (!(msg->msg_flags & MSG_MORE))
+                       err = rawv6_push_pending_frames(sk, &fl, raw_opt, len);
        }
 done:
        ip6_dst_store(sk, dst,
@@ -730,7 +731,7 @@ do_confirm:
 }
 
 static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, 
-                              char *optval, int optlen)
+                              char __user *optval, int optlen)
 {
        switch (optname) {
        case ICMPV6_FILTER:
@@ -747,7 +748,7 @@ static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
 }
 
 static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, 
-                              char *optval, int *optlen)
+                              char __user *optval, int __user *optlen)
 {
        int len;
 
@@ -773,7 +774,7 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
 
 
 static int rawv6_setsockopt(struct sock *sk, int level, int optname, 
-                           char *optval, int optlen)
+                           char __user *optval, int optlen)
 {
        struct raw6_opt *opt = raw6_sk(sk);
        int val;
@@ -795,7 +796,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
                                               optlen);
        };
 
-       if (get_user(val, (int *)optval))
+       if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
        switch (optname) {
@@ -820,7 +821,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
 }
 
 static int rawv6_getsockopt(struct sock *sk, int level, int optname, 
-                           char *optval, int *optlen)
+                           char __user *optval, int __user *optlen)
 {
        struct raw6_opt *opt = raw6_sk(sk);
        int val, len;
@@ -872,7 +873,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
                case SIOCOUTQ:
                {
                        int amount = atomic_read(&sk->sk_wmem_alloc);
-                       return put_user(amount, (int *)arg);
+                       return put_user(amount, (int __user *)arg);
                }
                case SIOCINQ:
                {
@@ -884,7 +885,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
                        if (skb != NULL)
                                amount = skb->tail - skb->h.raw;
                        spin_unlock_irq(&sk->sk_receive_queue.lock);
-                       return put_user(amount, (int *)arg);
+                       return put_user(amount, (int __user *)arg);
                }
 
                default: