@@ -211,15 +211,13 @@ int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
__u8 tos);
void ip_init(void);
-int ip_append_data(struct sock *sk, struct flowi4 *fl4,
- int getfrag(void *from, char *to, int offset, int len,
- int odd, struct sk_buff *skb),
- void *from, int len, int protolen,
- struct ipcm_cookie *ipc,
- struct rtable **rt,
- unsigned int flags);
-int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd,
- struct sk_buff *skb);
+typedef int (*ip_getfrag_t)(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb);
+int ip_append_data(struct sock *sk, struct flowi4 *fl4, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int protolen,
+ struct ipcm_cookie *ipc, struct rtable **rt);
+int ip_generic_getfrag(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb);
ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
int offset, size_t size, int flags);
struct sk_buff *__ip_make_skb(struct sock *sk, struct flowi4 *fl4,
@@ -228,12 +226,10 @@ struct sk_buff *__ip_make_skb(struct sock *sk, struct flowi4 *fl4,
int ip_send_skb(struct net *net, struct sk_buff *skb);
int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4);
void ip_flush_pending_frames(struct sock *sk);
-struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, int length, int transhdrlen,
+struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4, struct msghdr *msg,
+ ip_getfrag_t getfrag, int transhdrlen,
struct ipcm_cookie *ipc, struct rtable **rtp,
- struct inet_cork *cork, unsigned int flags);
+ struct inet_cork *cork);
int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl);
@@ -1094,12 +1094,13 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
-int ip6_append_data(struct sock *sk,
- int getfrag(void *from, char *to, int offset, int len,
- int odd, struct sk_buff *skb),
- void *from, size_t length, int transhdrlen,
+typedef int (*ip_getfrag_t)(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb);
+
+int ip6_append_data(struct sock *sk, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int transhdrlen,
struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
- struct rt6_info *rt, unsigned int flags);
+ struct rt6_info *rt);
int ip6_push_pending_frames(struct sock *sk);
@@ -1110,12 +1111,9 @@ int ip6_send_skb(struct sk_buff *skb);
struct sk_buff *__ip6_make_skb(struct sock *sk, struct sk_buff_head *queue,
struct inet_cork_full *cork,
struct inet6_cork *v6_cork);
-struct sk_buff *ip6_make_skb(struct sock *sk,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, size_t length, int transhdrlen,
- struct ipcm6_cookie *ipc6,
- struct rt6_info *rt, unsigned int flags,
+struct sk_buff *ip6_make_skb(struct sock *sk, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int transhdrlen,
+ struct ipcm6_cookie *ipc6, struct rt6_info *rt,
struct inet_cork_full *cork);
static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
@@ -52,7 +52,6 @@ extern struct pingv6_ops pingv6_ops;
struct pingfakehdr {
struct icmphdr icmph;
- struct msghdr *msg;
sa_family_t family;
__wsum wcheck;
};
@@ -65,8 +64,8 @@ int ping_init_sock(struct sock *sk);
void ping_close(struct sock *sk, long timeout);
int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len);
void ping_err(struct sk_buff *skb, int offset, u32 info);
-int ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
- struct sk_buff *);
+int ping_getfrag(struct msghdr *msg, void *from, char *to,
+ int offset, int fraglen, int odd, struct sk_buff *skb);
int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int flags, int *addr_len);
@@ -18,10 +18,10 @@ extern struct udp_table udplite_table;
/*
* Checksum computation is all in software, hence simpler getfrag.
*/
-static __inline__ int udplite_getfrag(void *from, char *to, int offset,
+static __inline__ int udplite_getfrag(struct msghdr *msg,
+ void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
- struct msghdr *msg = from;
return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT;
}
@@ -344,8 +344,8 @@ void icmp_out_count(struct net *net, unsigned char type)
* Checksum each fragment, and on the first include the headers and final
* checksum.
*/
-static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
- struct sk_buff *skb)
+static int icmp_glue_bits(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb)
{
struct icmp_bxm *icmp_param = from;
__wsum csum;
@@ -366,11 +366,13 @@ static void icmp_push_reply(struct sock *sk,
struct ipcm_cookie *ipc, struct rtable **rt)
{
struct sk_buff *skb;
+ struct msghdr msg = {
+ .msg_flags = MSG_DONTWAIT,
+ .msg_iter.count = icmp_param->data_len,
+ };
- if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param,
- icmp_param->data_len+icmp_param->head_len,
- icmp_param->head_len,
- ipc, rt, MSG_DONTWAIT) < 0) {
+ if (ip_append_data(sk, fl4, &msg, icmp_glue_bits, icmp_param,
+ icmp_param->head_len, ipc, rt) < 0) {
__ICMP_INC_STATS(sock_net(sk), ICMP_MIB_OUTERRORS);
ip_flush_pending_frames(sk);
} else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
@@ -929,10 +929,9 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
EXPORT_SYMBOL(ip_do_fragment);
int
-ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
+ip_generic_getfrag(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb)
{
- struct msghdr *msg = from;
-
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (!copy_from_iter_full(to, len, &msg->msg_iter))
return -EFAULT;
@@ -959,13 +958,12 @@ csum_page(struct page *page, int offset, int copy)
static int __ip_append_data(struct sock *sk,
struct flowi4 *fl4,
+ struct msghdr *msg,
struct sk_buff_head *queue,
struct inet_cork *cork,
struct page_frag *pfrag,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, int length, int transhdrlen,
- unsigned int flags)
+ ip_getfrag_t getfrag,
+ void *from, int transhdrlen)
{
struct inet_sock *inet = inet_sk(sk);
struct ubuf_info *uarg = NULL;
@@ -978,6 +976,7 @@ static int __ip_append_data(struct sock *sk,
int err;
int offset = 0;
bool zc = false;
+ unsigned int length = msg_data_left(msg) + transhdrlen;
unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
int csummode = CHECKSUM_NONE;
struct rtable *rt = (struct rtable *)cork->dst;
@@ -1014,11 +1013,11 @@ static int __ip_append_data(struct sock *sk,
if (transhdrlen &&
length + fragheaderlen <= mtu &&
rt->dst.dev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM) &&
- (!(flags & MSG_MORE) || cork->gso_size) &&
+ (!(msg->msg_flags & MSG_MORE) || cork->gso_size) &&
(!exthdrlen || (rt->dst.dev->features & NETIF_F_HW_ESP_TX_CSUM)))
csummode = CHECKSUM_PARTIAL;
- if ((flags & MSG_ZEROCOPY) && length) {
+ if ((msg->msg_flags & MSG_ZEROCOPY) && length) {
struct msghdr *msg = from;
if (getfrag == ip_generic_getfrag && msg->msg_ubuf) {
@@ -1103,7 +1102,7 @@ static int __ip_append_data(struct sock *sk,
if (datalen == length + fraggap)
alloc_extra += rt->dst.trailer_len;
- if ((flags & MSG_MORE) &&
+ if ((msg->msg_flags & MSG_MORE) &&
!(rt->dst.dev->features&NETIF_F_SG))
alloclen = mtu;
else if (!paged &&
@@ -1119,7 +1118,7 @@ static int __ip_append_data(struct sock *sk,
if (transhdrlen) {
skb = sock_alloc_send_skb(sk, alloclen,
- (flags & MSG_DONTWAIT), &err);
+ (msg->msg_flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
if (refcount_read(&sk->sk_wmem_alloc) + wmem_alloc_delta <=
@@ -1159,7 +1158,8 @@ static int __ip_append_data(struct sock *sk,
}
copy = datalen - transhdrlen - fraggap - pagedlen;
- if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
+ if (copy > 0 && getfrag(msg, from, data + transhdrlen,
+ offset, copy, fraggap, skb) < 0) {
err = -EFAULT;
kfree_skb(skb);
goto error;
@@ -1178,7 +1178,7 @@ static int __ip_append_data(struct sock *sk,
tskey = 0;
skb_zcopy_set(skb, uarg, &extra_uref);
- if ((flags & MSG_CONFIRM) && !skb_prev)
+ if ((msg->msg_flags & MSG_CONFIRM) && !skb_prev)
skb_set_dst_pending_confirm(skb, 1);
/*
@@ -1201,8 +1201,8 @@ static int __ip_append_data(struct sock *sk,
unsigned int off;
off = skb->len;
- if (getfrag(from, skb_put(skb, copy),
- offset, copy, off, skb) < 0) {
+ if (getfrag(msg, from, skb_put(skb, copy),
+ offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
goto error;
@@ -1227,7 +1227,7 @@ static int __ip_append_data(struct sock *sk,
get_page(pfrag->page);
}
copy = min_t(int, copy, pfrag->size - pfrag->offset);
- if (getfrag(from,
+ if (getfrag(msg, from,
page_address(pfrag->page) + pfrag->offset,
offset, copy, skb->len, skb) < 0)
goto error_efault;
@@ -1320,17 +1320,14 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
*
* LATER: length must be adjusted by pad at tail, when it is required.
*/
-int ip_append_data(struct sock *sk, struct flowi4 *fl4,
- int getfrag(void *from, char *to, int offset, int len,
- int odd, struct sk_buff *skb),
- void *from, int length, int transhdrlen,
- struct ipcm_cookie *ipc, struct rtable **rtp,
- unsigned int flags)
+int ip_append_data(struct sock *sk, struct flowi4 *fl4, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int transhdrlen,
+ struct ipcm_cookie *ipc, struct rtable **rtp)
{
struct inet_sock *inet = inet_sk(sk);
int err;
- if (flags&MSG_PROBE)
+ if (msg->msg_flags & MSG_PROBE)
return 0;
if (skb_queue_empty(&sk->sk_write_queue)) {
@@ -1341,9 +1338,9 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4,
transhdrlen = 0;
}
- return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base,
- sk_page_frag(sk), getfrag,
- from, length, transhdrlen, flags);
+ return __ip_append_data(sk, fl4, msg, &sk->sk_write_queue,
+ &inet->cork.base, sk_page_frag(sk),
+ getfrag, from, transhdrlen);
}
ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
@@ -1629,16 +1626,16 @@ void ip_flush_pending_frames(struct sock *sk)
struct sk_buff *ip_make_skb(struct sock *sk,
struct flowi4 *fl4,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, int length, int transhdrlen,
+ struct msghdr *msg,
+ ip_getfrag_t getfrag,
+ int transhdrlen,
struct ipcm_cookie *ipc, struct rtable **rtp,
- struct inet_cork *cork, unsigned int flags)
+ struct inet_cork *cork)
{
struct sk_buff_head queue;
int err;
- if (flags & MSG_PROBE)
+ if (msg->msg_flags & MSG_PROBE)
return NULL;
__skb_queue_head_init(&queue);
@@ -1650,9 +1647,9 @@ struct sk_buff *ip_make_skb(struct sock *sk,
if (err)
return ERR_PTR(err);
- err = __ip_append_data(sk, fl4, &queue, cork,
+ err = __ip_append_data(sk, fl4, msg, &queue, cork,
¤t->task_frag, getfrag,
- from, length, transhdrlen, flags);
+ msg, transhdrlen);
if (err) {
__ip_flush_pending_frames(sk, &queue, cork);
return ERR_PTR(err);
@@ -1664,7 +1661,7 @@ struct sk_buff *ip_make_skb(struct sock *sk,
/*
* Fetch data from kernel space and fill in checksum if needed.
*/
-static int ip_reply_glue_bits(void *dptr, char *to, int offset,
+static int ip_reply_glue_bits(struct msghdr *msg, void *dptr, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
__wsum csum;
@@ -1690,6 +1687,10 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
struct rtable *rt = skb_rtable(skb);
struct net *net = sock_net(sk);
struct sk_buff *nskb;
+ struct msghdr msg = {
+ .msg_flags = MSG_DONTWAIT,
+ .msg_iter.count = len,
+ };
int err;
int oif;
@@ -1730,8 +1731,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
sk->sk_bound_dev_if = arg->bound_dev_if;
sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default);
ipc.sockc.mark = fl4.flowi4_mark;
- err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
- len, 0, &ipc, &rt, MSG_DONTWAIT);
+ err = ip_append_data(sk, &fl4, &msg, ip_reply_glue_bits, arg->iov->iov_base,
+ 0, &ipc, &rt);
if (unlikely(err)) {
ip_flush_pending_frames(sk);
goto out;
@@ -617,13 +617,13 @@ EXPORT_SYMBOL_GPL(ping_err);
* starting from the payload.
*/
-int ping_getfrag(void *from, char *to,
+int ping_getfrag(struct msghdr *msg, void *from, char *to,
int offset, int fraglen, int odd, struct sk_buff *skb)
{
struct pingfakehdr *pfh = from;
if (!csum_and_copy_from_iter_full(to, fraglen, &pfh->wcheck,
- &pfh->msg->msg_iter))
+ &msg->msg_iter))
return -EFAULT;
#if IS_ENABLED(CONFIG_IPV6)
@@ -832,13 +832,11 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg)
pfh.icmph.checksum = 0;
pfh.icmph.un.echo.id = inet->inet_sport;
pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
- pfh.msg = msg;
pfh.wcheck = 0;
pfh.family = AF_INET;
- err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
- sizeof(struct icmphdr), &ipc, &rt,
- msg->msg_flags);
+ err = ip_append_data(sk, &fl4, msg, ping_getfrag, &pfh,
+ sizeof(struct icmphdr), &ipc, &rt);
if (err)
ip_flush_pending_frames(sk);
else
@@ -77,7 +77,6 @@
#include <linux/uio.h>
struct raw_frag_vec {
- struct msghdr *msg;
union {
struct icmphdr icmph;
char c[1];
@@ -420,7 +419,8 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
return err;
}
-static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
+static int raw_probe_proto_opt(struct msghdr *msg, struct raw_frag_vec *rfv,
+ struct flowi4 *fl4)
{
int err;
@@ -430,7 +430,7 @@ static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
/* We only need the first two bytes. */
rfv->hlen = 2;
- err = memcpy_from_msg(rfv->hdr.c, rfv->msg, rfv->hlen);
+ err = memcpy_from_msg(rfv->hdr.c, msg, rfv->hlen);
if (err)
return err;
@@ -440,8 +440,8 @@ static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
return 0;
}
-static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
- struct sk_buff *skb)
+static int raw_getfrag(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb)
{
struct raw_frag_vec *rfv = from;
@@ -468,7 +468,7 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
offset -= rfv->hlen;
- return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
+ return ip_generic_getfrag(msg, NULL, to, offset, len, odd, skb);
}
static int raw_sendmsg(struct sock *sk, struct msghdr *msg)
@@ -608,10 +608,9 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg)
daddr, saddr, 0, 0, sk->sk_uid);
if (!hdrincl) {
- rfv.msg = msg;
rfv.hlen = 0;
- err = raw_probe_proto_opt(&rfv, &fl4);
+ err = raw_probe_proto_opt(msg, &rfv, &fl4);
if (err)
goto done;
}
@@ -640,9 +639,8 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg)
if (!ipc.addr)
ipc.addr = fl4.daddr;
lock_sock(sk);
- err = ip_append_data(sk, &fl4, raw_getfrag,
- &rfv, len, 0,
- &ipc, &rt, msg->msg_flags);
+ err = ip_append_data(sk, &fl4, msg, raw_getfrag,
+ &rfv, 0, &ipc, &rt);
if (err)
ip_flush_pending_frames(sk);
else if (!(msg->msg_flags & MSG_MORE)) {
@@ -1066,11 +1066,16 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg)
__be16 dport;
u8 tos;
int err, is_udplite = IS_UDPLITE(sk);
- int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE;
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
+ bool corkreq = READ_ONCE(up->corkflag);
+ ip_getfrag_t getfrag;
struct sk_buff *skb;
struct ip_options_data opt_copy;
+ if (corkreq)
+ msg->msg_flags |= MSG_MORE;
+ else
+ corkreq = msg->msg_flags & MSG_MORE;
+
if (len > 0xFFFF)
return -EMSGSIZE;
@@ -1258,9 +1263,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg)
if (!corkreq) {
struct inet_cork cork;
- skb = ip_make_skb(sk, fl4, getfrag, msg, ulen,
- sizeof(struct udphdr), &ipc, &rt,
- &cork, msg->msg_flags);
+ skb = ip_make_skb(sk, fl4, msg, getfrag,
+ sizeof(struct udphdr), &ipc, &rt, &cork);
err = PTR_ERR(skb);
if (!IS_ERR_OR_NULL(skb))
err = udp_send_skb(skb, fl4, &cork);
@@ -1289,9 +1293,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg)
do_append_data:
up->len += ulen;
- err = ip_append_data(sk, fl4, getfrag, msg, ulen,
- sizeof(struct udphdr), &ipc, &rt,
- corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+ err = ip_append_data(sk, fl4, msg, getfrag, NULL,
+ sizeof(struct udphdr), &ipc, &rt);
if (err)
udp_flush_pending_frames(sk);
else if (!corkreq)
@@ -313,7 +313,8 @@ struct icmpv6_msg {
uint8_t type;
};
-static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
+static int icmpv6_getfrag(struct msghdr *_msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb)
{
struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
struct sk_buff *org_skb = msg->skb;
@@ -453,6 +454,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
struct flowi6 fl6;
struct icmpv6_msg msg;
struct ipcm6_cookie ipc6;
+ struct msghdr msghdr;
int iif = 0;
int addr_type = 0;
int len;
@@ -606,14 +608,15 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
goto out_dst_release;
}
+ msghdr.msg_iter.count = len;
+ msghdr.msg_flags = MSG_DONTWAIT;
+
rcu_read_lock();
idev = __in6_dev_get(skb->dev);
- if (ip6_append_data(sk, icmpv6_getfrag, &msg,
- len + sizeof(struct icmp6hdr),
+ if (ip6_append_data(sk, &msghdr, icmpv6_getfrag, &msg,
sizeof(struct icmp6hdr),
- &ipc6, &fl6, (struct rt6_info *)dst,
- MSG_DONTWAIT)) {
+ &ipc6, &fl6, (struct rt6_info *)dst)) {
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
} else {
@@ -718,6 +721,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
struct icmpv6_msg msg;
struct dst_entry *dst;
struct ipcm6_cookie ipc6;
+ struct msghdr msghdr;
u32 mark = IP6_REPLY_MARK(net, skb->mark);
SKB_DR(reason);
bool acast;
@@ -796,10 +800,11 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
if (!icmp_build_probe(skb, (struct icmphdr *)&tmp_hdr))
goto out_dst_release;
- if (ip6_append_data(sk, icmpv6_getfrag, &msg,
- skb->len + sizeof(struct icmp6hdr),
+ msghdr.msg_iter.count = skb->len;
+ msghdr.msg_flags = MSG_DONTWAIT;
+ if (ip6_append_data(sk, &msghdr, icmpv6_getfrag, &msg,
sizeof(struct icmp6hdr), &ipc6, &fl6,
- (struct rt6_info *)dst, MSG_DONTWAIT)) {
+ (struct rt6_info *)dst)) {
__ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
} else {
@@ -1462,13 +1462,13 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
static int __ip6_append_data(struct sock *sk,
struct sk_buff_head *queue,
+ struct msghdr *msg,
struct inet_cork_full *cork_full,
struct inet6_cork *v6_cork,
struct page_frag *pfrag,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, size_t length, int transhdrlen,
- unsigned int flags, struct ipcm6_cookie *ipc6)
+ ip_getfrag_t getfrag,
+ void *from, int transhdrlen,
+ struct ipcm6_cookie *ipc6)
{
struct sk_buff *skb, *skb_prev = NULL;
struct inet_cork *cork = &cork_full->base;
@@ -1488,6 +1488,7 @@ static int __ip6_append_data(struct sock *sk,
int csummode = CHECKSUM_NONE;
unsigned int maxnonfragsize, headersize;
unsigned int wmem_alloc_delta = 0;
+ size_t length = msg_data_left(msg) + transhdrlen;
bool paged, extra_uref = false;
skb = skb_peek_tail(queue);
@@ -1555,11 +1556,11 @@ static int __ip6_append_data(struct sock *sk,
if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
headersize == sizeof(struct ipv6hdr) &&
length <= mtu - headersize &&
- (!(flags & MSG_MORE) || cork->gso_size) &&
+ (!(msg->msg_flags & MSG_MORE) || cork->gso_size) &&
rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
csummode = CHECKSUM_PARTIAL;
- if ((flags & MSG_ZEROCOPY) && length) {
+ if ((msg->msg_flags & MSG_ZEROCOPY) && length) {
struct msghdr *msg = from;
if (getfrag == ip_generic_getfrag && msg->msg_ubuf) {
@@ -1659,7 +1660,7 @@ static int __ip6_append_data(struct sock *sk,
*/
alloc_extra += sizeof(struct frag_hdr);
- if ((flags & MSG_MORE) &&
+ if ((msg->msg_flags & MSG_MORE) &&
!(rt->dst.dev->features&NETIF_F_SG))
alloclen = mtu;
else if (!paged &&
@@ -1689,7 +1690,7 @@ static int __ip6_append_data(struct sock *sk,
}
if (transhdrlen) {
skb = sock_alloc_send_skb(sk, alloclen,
- (flags & MSG_DONTWAIT), &err);
+ (msg->msg_flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
if (refcount_read(&sk->sk_wmem_alloc) + wmem_alloc_delta <=
@@ -1729,7 +1730,7 @@ static int __ip6_append_data(struct sock *sk,
pskb_trim_unique(skb_prev, maxfraglen);
}
if (copy > 0 &&
- getfrag(from, data + transhdrlen, offset,
+ getfrag(msg, from, data + transhdrlen, offset,
copy, fraggap, skb) < 0) {
err = -EFAULT;
kfree_skb(skb);
@@ -1749,7 +1750,7 @@ static int __ip6_append_data(struct sock *sk,
tskey = 0;
skb_zcopy_set(skb, uarg, &extra_uref);
- if ((flags & MSG_CONFIRM) && !skb_prev)
+ if ((msg->msg_flags & MSG_CONFIRM) && !skb_prev)
skb_set_dst_pending_confirm(skb, 1);
/*
@@ -1772,8 +1773,8 @@ static int __ip6_append_data(struct sock *sk,
unsigned int off;
off = skb->len;
- if (getfrag(from, skb_put(skb, copy),
- offset, copy, off, skb) < 0) {
+ if (getfrag(msg, from, skb_put(skb, copy),
+ offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
goto error;
@@ -1798,7 +1799,7 @@ static int __ip6_append_data(struct sock *sk,
get_page(pfrag->page);
}
copy = min_t(int, copy, pfrag->size - pfrag->offset);
- if (getfrag(from,
+ if (getfrag(msg, from,
page_address(pfrag->page) + pfrag->offset,
offset, copy, skb->len, skb) < 0)
goto error_efault;
@@ -1832,19 +1833,17 @@ static int __ip6_append_data(struct sock *sk,
return err;
}
-int ip6_append_data(struct sock *sk,
- int getfrag(void *from, char *to, int offset, int len,
- int odd, struct sk_buff *skb),
- void *from, size_t length, int transhdrlen,
+int ip6_append_data(struct sock *sk, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int transhdrlen,
struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
- struct rt6_info *rt, unsigned int flags)
+ struct rt6_info *rt)
{
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
int exthdrlen;
int err;
- if (flags&MSG_PROBE)
+ if (msg->msg_flags & MSG_PROBE)
return 0;
if (skb_queue_empty(&sk->sk_write_queue)) {
/*
@@ -1858,15 +1857,14 @@ int ip6_append_data(struct sock *sk,
inet->cork.fl.u.ip6 = *fl6;
exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
- length += exthdrlen;
transhdrlen += exthdrlen;
} else {
transhdrlen = 0;
}
- return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork,
+ return __ip6_append_data(sk, &sk->sk_write_queue, msg, &inet->cork,
&np->cork, sk_page_frag(sk), getfrag,
- from, length, transhdrlen, flags, ipc6);
+ from, transhdrlen, ipc6);
}
EXPORT_SYMBOL_GPL(ip6_append_data);
@@ -2029,19 +2027,17 @@ void ip6_flush_pending_frames(struct sock *sk)
}
EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
-struct sk_buff *ip6_make_skb(struct sock *sk,
- int getfrag(void *from, char *to, int offset,
- int len, int odd, struct sk_buff *skb),
- void *from, size_t length, int transhdrlen,
+struct sk_buff *ip6_make_skb(struct sock *sk, struct msghdr *msg,
+ ip_getfrag_t getfrag, void *from, int transhdrlen,
struct ipcm6_cookie *ipc6, struct rt6_info *rt,
- unsigned int flags, struct inet_cork_full *cork)
+ struct inet_cork_full *cork)
{
struct inet6_cork v6_cork;
struct sk_buff_head queue;
int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
int err;
- if (flags & MSG_PROBE) {
+ if (msg->msg_flags & MSG_PROBE) {
dst_release(&rt->dst);
return NULL;
}
@@ -2060,10 +2056,9 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
if (ipc6->dontfrag < 0)
ipc6->dontfrag = inet6_sk(sk)->dontfrag;
- err = __ip6_append_data(sk, &queue, cork, &v6_cork,
+ err = __ip6_append_data(sk, &queue, msg, cork, &v6_cork,
¤t->task_frag, getfrag, from,
- length + exthdrlen, transhdrlen + exthdrlen,
- flags, ipc6);
+ transhdrlen + exthdrlen, ipc6);
if (err) {
__ip6_flush_pending_frames(sk, &queue, cork, &v6_cork);
return ERR_PTR(err);
@@ -166,17 +166,16 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg)
pfh.icmph.checksum = 0;
pfh.icmph.un.echo.id = inet->inet_sport;
pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence;
- pfh.msg = msg;
pfh.wcheck = 0;
pfh.family = AF_INET6;
if (ipc6.hlimit < 0)
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+ msg->msg_flags = MSG_DONTWAIT;
lock_sock(sk);
- err = ip6_append_data(sk, ping_getfrag, &pfh, len,
- sizeof(struct icmp6hdr), &ipc6, &fl6, rt,
- MSG_DONTWAIT);
+ err = ip6_append_data(sk, msg, ping_getfrag, &pfh,
+ sizeof(struct icmp6hdr), &ipc6, &fl6, rt);
if (err) {
ICMP6_INC_STATS(sock_net(sk), rt->rt6i_idev,
@@ -678,18 +678,18 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
}
struct raw6_frag_vec {
- struct msghdr *msg;
int hlen;
char c[4];
};
-static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
+static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6,
+ struct msghdr *msg)
{
int err = 0;
switch (fl6->flowi6_proto) {
case IPPROTO_ICMPV6:
rfv->hlen = 2;
- err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
+ err = memcpy_from_msg(rfv->c, msg, rfv->hlen);
if (!err) {
fl6->fl6_icmp_type = rfv->c[0];
fl6->fl6_icmp_code = rfv->c[1];
@@ -697,15 +697,15 @@ static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
break;
case IPPROTO_MH:
rfv->hlen = 4;
- err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
+ err = memcpy_from_msg(rfv->c, msg, rfv->hlen);
if (!err)
fl6->fl6_mh_type = rfv->c[2];
}
return err;
}
-static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
- struct sk_buff *skb)
+static int raw6_getfrag(struct msghdr *msg, void *from, char *to,
+ int offset, int len, int odd, struct sk_buff *skb)
{
struct raw6_frag_vec *rfv = from;
@@ -732,7 +732,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
offset -= rfv->hlen;
- return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
+ return ip_generic_getfrag(msg, NULL, to, offset, len, odd, skb);
}
static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg)
@@ -868,9 +868,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg)
fl6.flowi6_mark = ipc6.sockc.mark;
if (!hdrincl) {
- rfv.msg = msg;
rfv.hlen = 0;
- err = rawv6_probe_proto_opt(&rfv, &fl6);
+ err = rawv6_probe_proto_opt(&rfv, &fl6, msg);
if (err)
goto out;
}
@@ -919,9 +918,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg)
else {
ipc6.opt = opt;
lock_sock(sk);
- err = ip6_append_data(sk, raw6_getfrag, &rfv,
- len, 0, &ipc6, &fl6, (struct rt6_info *)dst,
- msg->msg_flags);
+ err = ip6_append_data(sk, msg, raw6_getfrag, &rfv,
+ 0, &ipc6, &fl6, (struct rt6_info *)dst);
if (err)
ip6_flush_pending_frames(sk);
@@ -1345,10 +1345,15 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg)
bool connected = false;
size_t len = msg_data_left(msg);
int ulen = len;
- int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE;
+ int corkreq = READ_ONCE(up->corkflag);
int err;
int is_udplite = IS_UDPLITE(sk);
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
+ ip_getfrag_t getfrag;
+
+ if (corkreq)
+ msg->msg_flags |= MSG_MORE;
+ else
+ corkreq = msg->msg_flags & MSG_MORE;
ipcm6_init(&ipc6);
ipc6.gso_size = READ_ONCE(up->gso_size);
@@ -1578,10 +1583,9 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg)
if (!corkreq) {
struct sk_buff *skb;
- skb = ip6_make_skb(sk, getfrag, msg, ulen,
+ skb = ip6_make_skb(sk, msg, getfrag, NULL,
sizeof(struct udphdr), &ipc6,
- (struct rt6_info *)dst,
- msg->msg_flags, &cork);
+ (struct rt6_info *)dst, &cork);
err = PTR_ERR(skb);
if (!IS_ERR_OR_NULL(skb))
err = udp_v6_send_skb(skb, fl6, &cork.base);
@@ -1606,9 +1610,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg)
if (ipc6.dontfrag < 0)
ipc6.dontfrag = np->dontfrag;
up->len += ulen;
- err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
- &ipc6, fl6, (struct rt6_info *)dst,
- corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+ err = ip6_append_data(sk, msg, getfrag, NULL, sizeof(struct udphdr),
+ &ipc6, fl6, (struct rt6_info *)dst);
if (err)
udp_v6_flush_pending_frames(sk);
else if (!corkreq)