#include <linux/netfilter_ipv6.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
+#include <asm/bug.h>
#include <net/ip.h>
#include <net/sock.h>
}
static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
- struct raw6_sock *rp, int len)
+ struct raw6_sock *rp)
{
struct sk_buff *skb;
int err = 0;
- u16 *csum;
+ int offset;
+ int len;
+ int total_len;
u32 tmp_csum;
+ u16 csum;
if (!rp->checksum)
goto send;
if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
goto out;
- if (rp->offset + 1 < len)
- csum = (u16 *)(skb->h.raw + rp->offset);
- else {
+ offset = rp->offset;
+ total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data);
+ if (offset >= total_len - 1) {
err = -EINVAL;
+ ip6_flush_pending_frames(sk);
goto out;
}
*/
tmp_csum = skb->csum;
} else {
+ struct sk_buff *csum_skb = NULL;
tmp_csum = 0;
skb_queue_walk(&sk->sk_write_queue, skb) {
tmp_csum = csum_add(tmp_csum, skb->csum);
+
+ if (csum_skb)
+ continue;
+
+ len = skb->len - (skb->h.raw - skb->data);
+ if (offset >= len) {
+ offset -= len;
+ continue;
+ }
+
+ csum_skb = skb;
}
+
+ skb = csum_skb;
}
+ offset += skb->h.raw - skb->data;
+ if (skb_copy_bits(skb, offset, &csum, 2))
+ BUG();
+
/* in case cksum was not initialized */
- if (unlikely(*csum))
- tmp_csum = csum_sub(tmp_csum, *csum);
+ 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);
+ tmp_csum = csum_ipv6_magic(&fl->fl6_src,
+ &fl->fl6_dst,
+ total_len, fl->proto, tmp_csum);
+
+ if (tmp_csum == 0)
+ tmp_csum = -1;
+
+ csum = tmp_csum;
+ if (skb_store_bits(skb, offset, &csum, 2))
+ BUG();
- if (*csum == 0)
- *csum = -1;
send:
err = ip6_push_pending_frames(sk);
out:
struct flowi *fl, struct rt6_info *rt,
unsigned int flags)
{
- struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6hdr *iph;
struct sk_buff *skb;
unsigned int hh_len;
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
dst_output);
if (err > 0)
- err = inet->recverr ? net_xmit_errno(err) : 0;
+ err = np->recverr ? net_xmit_errno(err) : 0;
if (err)
goto error;
out:
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
}
if (msg->msg_flags&MSG_CONFIRM)
if (err)
ip6_flush_pending_frames(sk);
else if (!(msg->msg_flags & MSG_MORE))
- err = rawv6_push_pending_frames(sk, &fl, rp, len);
+ err = rawv6_push_pending_frames(sk, &fl, rp);
}
done:
ip6_dst_store(sk, dst,
ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
&np->daddr : NULL);
- if (err > 0)
- err = np->recverr ? net_xmit_errno(err) : 0;
release_sock(sk);
out:
}
struct proto rawv6_prot = {
- .name = "RAW",
+ .name = "RAWv6",
.owner = THIS_MODULE,
.close = rawv6_close,
.connect = ip6_datagram_connect,
.backlog_rcv = rawv6_rcv_skb,
.hash = raw_v6_hash,
.unhash = raw_v6_unhash,
- .slab_obj_size = sizeof(struct raw6_sock),
+ .obj_size = sizeof(struct raw6_sock),
};
#ifdef CONFIG_PROC_FS