@@ -368,8 +368,7 @@ static void icmp_push_reply(struct sock *sk,
struct sk_buff *skb;
if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param,
- icmp_param->data_len+icmp_param->head_len,
- icmp_param->head_len,
+ icmp_param->data_len, icmp_param->head_len,
ipc, rt, MSG_DONTWAIT) < 0) {
__ICMP_INC_STATS(sock_net(sk), ICMP_MIB_OUTERRORS);
ip_flush_pending_frames(sk);
@@ -974,6 +974,11 @@ static int __ip_append_data(struct sock *sk,
bool paged, extra_uref = false;
u32 tskey = 0;
+ if (skb_queue_empty(&sk->sk_write_queue))
+ length += transhdrlen;
+ else
+ transhdrlen = 0;
+
skb = skb_peek_tail(queue);
exthdrlen = !skb ? rt->dst.header_len : 0;
@@ -1353,8 +1358,6 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4,
err = ip_setup_cork(sk, &inet->cork.base, ipc, rtp);
if (err)
return err;
- } else {
- transhdrlen = 0;
}
return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base,
@@ -819,7 +819,8 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
pfh.wcheck = 0;
pfh.family = AF_INET;
- err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
+ err = ip_append_data(sk, &fl4, ping_getfrag, &pfh,
+ len - sizeof(struct icmphdr),
sizeof(struct icmphdr), &ipc, &rt,
msg->msg_flags);
if (err)
@@ -1042,7 +1042,6 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name);
struct flowi4 fl4_stack;
struct flowi4 *fl4;
- int ulen = len;
struct ipcm_cookie ipc;
struct rtable *rt = NULL;
int free = 0;
@@ -1084,7 +1083,6 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
release_sock(sk);
}
- ulen += sizeof(struct udphdr);
/*
* Get and verify the address.
@@ -1238,7 +1236,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (!corkreq) {
struct inet_cork cork;
- skb = ip_make_skb(sk, fl4, getfrag, msg, ulen,
+ skb = ip_make_skb(sk, fl4, getfrag, msg, len,
sizeof(struct udphdr), &ipc, &rt,
&cork, msg->msg_flags);
err = PTR_ERR(skb);
@@ -1268,8 +1266,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
up->pending = AF_INET;
do_append_data:
- up->len += ulen;
- err = ip_append_data(sk, fl4, getfrag, msg, ulen,
+ up->len += sizeof(struct udphdr) + len;
+ err = ip_append_data(sk, fl4, getfrag, msg, len,
sizeof(struct udphdr), &ipc, &rt,
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
if (err)
@@ -614,8 +614,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
idev = __in6_dev_get(skb->dev);
if (ip6_append_data(sk, icmpv6_getfrag, &msg,
- len + sizeof(struct icmp6hdr),
- sizeof(struct icmp6hdr),
+ len, sizeof(struct icmp6hdr),
&ipc6, &fl6, (struct rt6_info *)dst,
MSG_DONTWAIT)) {
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
@@ -801,8 +800,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
goto out_dst_release;
if (ip6_append_data(sk, icmpv6_getfrag, &msg,
- skb->len + sizeof(struct icmp6hdr),
- sizeof(struct icmp6hdr), &ipc6, &fl6,
+ skb->len, sizeof(struct icmp6hdr), &ipc6, &fl6,
(struct rt6_info *)dst, MSG_DONTWAIT)) {
__ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
@@ -1490,6 +1490,11 @@ static int __ip6_append_data(struct sock *sk,
unsigned int wmem_alloc_delta = 0;
bool paged, extra_uref = false;
+ if (skb_queue_empty(&sk->sk_write_queue))
+ length += transhdrlen;
+ else
+ transhdrlen = 0;
+
skb = skb_peek_tail(queue);
if (!skb) {
exthdrlen = opt ? opt->opt_flen : 0;
@@ -1868,7 +1873,6 @@ int ip6_append_data(struct sock *sk,
{
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
- int exthdrlen;
int err;
if (flags&MSG_PROBE)
@@ -1884,13 +1888,11 @@ int ip6_append_data(struct sock *sk,
return err;
inet->cork.fl.u.ip6 = *fl6;
- exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
- length += exthdrlen;
- transhdrlen += exthdrlen;
- } else {
- transhdrlen = 0;
}
+ /* Add space for extensions */
+ transhdrlen += (ipc6->opt ? ipc6->opt->opt_flen : 0);
+
return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork,
&np->cork, sk_page_frag(sk), getfrag,
from, length, transhdrlen, flags, ipc6);
@@ -2095,7 +2097,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
err = __ip6_append_data(sk, &queue, cork, &v6_cork,
¤t->task_frag, getfrag, from,
- length + exthdrlen, transhdrlen + exthdrlen,
+ length, transhdrlen + exthdrlen,
flags, ipc6);
if (err) {
__ip6_flush_pending_frames(sk, &queue, cork, &v6_cork);
@@ -174,7 +174,8 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
lock_sock(sk);
- err = ip6_append_data(sk, ping_getfrag, &pfh, len,
+ err = ip6_append_data(sk, ping_getfrag, &pfh,
+ len - sizeof(struct icmp6hdr),
sizeof(struct icmp6hdr), &ipc6, &fl6, rt,
MSG_DONTWAIT);
@@ -1331,7 +1331,6 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
struct ipcm6_cookie ipc6;
int addr_len = msg->msg_namelen;
bool connected = false;
- int ulen = len;
int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE;
int err;
int is_udplite = IS_UDPLITE(sk);
@@ -1416,7 +1415,6 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
release_sock(sk);
}
- ulen += sizeof(struct udphdr);
memset(fl6, 0, sizeof(*fl6));
@@ -1567,7 +1565,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (!corkreq) {
struct sk_buff *skb;
- skb = ip6_make_skb(sk, getfrag, msg, ulen,
+ skb = ip6_make_skb(sk, getfrag, msg, len,
sizeof(struct udphdr), &ipc6,
(struct rt6_info *)dst,
msg->msg_flags, &cork);
@@ -1594,8 +1592,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
do_append_data:
if (ipc6.dontfrag < 0)
ipc6.dontfrag = np->dontfrag;
- up->len += ulen;
- err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
+ up->len += sizeof(struct udphdr) + len;
+ err = ip6_append_data(sk, getfrag, msg, len, sizeof(struct udphdr),
&ipc6, fl6, (struct rt6_info *)dst,
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
if (err)
@@ -499,7 +499,6 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
struct ipcm6_cookie ipc6;
int addr_len = msg->msg_namelen;
int transhdrlen = 4; /* zero session-id */
- int ulen;
int err;
/* Rough check on arithmetic overflow,
@@ -507,7 +506,6 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
*/
if (len > INT_MAX - transhdrlen)
return -EMSGSIZE;
- ulen = len + transhdrlen;
/* Mirror BSD error message compatibility */
if (msg->msg_flags & MSG_OOB)
@@ -629,7 +627,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
back_from_confirm:
lock_sock(sk);
err = ip6_append_data(sk, ip_generic_getfrag, msg,
- ulen, transhdrlen, &ipc6,
+ len, transhdrlen, &ipc6,
&fl6, (struct rt6_info *)dst,
msg->msg_flags);
if (err)