Commit d39d938c authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

ipv6: Introduce udpv6_send_skb()

Now that we can individually construct IPv6 skbs to send, add a
udpv6_send_skb() function to populate the udp header and send the
skb.  This allows udp_v6_push_pending_frames() to re-use this
function as well as enables us to add lockless sendmsg() support.
Signed-off-by: default avatarVladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6422398c
...@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ...@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
{ {
unsigned int offset; unsigned int offset;
struct udphdr *uh = udp_hdr(skb); struct udphdr *uh = udp_hdr(skb);
struct sk_buff *frags = skb_shinfo(skb)->frag_list;
__wsum csum = 0; __wsum csum = 0;
if (skb_queue_len(&sk->sk_write_queue) == 1) { if (!frags) {
/* Only one fragment on the socket. */ /* Only one fragment on the socket. */
skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct udphdr, check); skb->csum_offset = offsetof(struct udphdr, check);
...@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ...@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
skb_queue_walk(&sk->sk_write_queue, skb) { do {
csum = csum_add(csum, skb->csum); csum = csum_add(csum, frags->csum);
} } while ((frags = frags->next));
uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
csum); csum);
...@@ -1023,26 +1024,15 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ...@@ -1023,26 +1024,15 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
* Sending * Sending
*/ */
static int udp_v6_push_pending_frames(struct sock *sk) static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6)
{ {
struct sk_buff *skb; struct sock *sk = skb->sk;
struct udphdr *uh; struct udphdr *uh;
struct udp_sock *up = udp_sk(sk);
struct inet_sock *inet = inet_sk(sk);
struct flowi6 *fl6;
int err = 0; int err = 0;
int is_udplite = IS_UDPLITE(sk); int is_udplite = IS_UDPLITE(sk);
__wsum csum = 0; __wsum csum = 0;
int offset = skb_transport_offset(skb);
if (up->pending == AF_INET) int len = skb->len - offset;
return udp_push_pending_frames(sk);
fl6 = &inet->cork.fl.u.ip6;
/* Grab the skbuff where UDP header space exists. */
skb = skb_peek(&sk->sk_write_queue);
if (skb == NULL)
goto out;
/* /*
* Create a UDP header * Create a UDP header
...@@ -1050,29 +1040,28 @@ static int udp_v6_push_pending_frames(struct sock *sk) ...@@ -1050,29 +1040,28 @@ static int udp_v6_push_pending_frames(struct sock *sk)
uh = udp_hdr(skb); uh = udp_hdr(skb);
uh->source = fl6->fl6_sport; uh->source = fl6->fl6_sport;
uh->dest = fl6->fl6_dport; uh->dest = fl6->fl6_dport;
uh->len = htons(up->len); uh->len = htons(len);
uh->check = 0; uh->check = 0;
if (is_udplite) if (is_udplite)
csum = udplite_csum_outgoing(sk, skb); csum = udplite_csum(skb);
else if (up->no_check6_tx) { /* UDP csum disabled */ else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
goto send; goto send;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len);
up->len);
goto send; goto send;
} else } else
csum = udp_csum_outgoing(sk, skb); csum = udp_csum(skb);
/* add protocol-dependent pseudo-header */ /* add protocol-dependent pseudo-header */
uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
up->len, fl6->flowi6_proto, csum); len, fl6->flowi6_proto, csum);
if (uh->check == 0) if (uh->check == 0)
uh->check = CSUM_MANGLED_0; uh->check = CSUM_MANGLED_0;
send: send:
err = ip6_push_pending_frames(sk); err = ip6_send_skb(skb);
if (err) { if (err) {
if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
UDP6_INC_STATS_USER(sock_net(sk), UDP6_INC_STATS_USER(sock_net(sk),
...@@ -1082,6 +1071,30 @@ static int udp_v6_push_pending_frames(struct sock *sk) ...@@ -1082,6 +1071,30 @@ static int udp_v6_push_pending_frames(struct sock *sk)
} else } else
UDP6_INC_STATS_USER(sock_net(sk), UDP6_INC_STATS_USER(sock_net(sk),
UDP_MIB_OUTDATAGRAMS, is_udplite); UDP_MIB_OUTDATAGRAMS, is_udplite);
return err;
}
static int udp_v6_push_pending_frames(struct sock *sk)
{
struct sk_buff *skb;
struct udp_sock *up = udp_sk(sk);
struct flowi6 fl6;
int err = 0;
if (up->pending == AF_INET)
return udp_push_pending_frames(sk);
/* ip6_finish_skb will release the cork, so make a copy of
* fl6 here.
*/
fl6 = inet_sk(sk)->cork.fl.u.ip6;
skb = ip6_finish_skb(sk);
if (!skb)
goto out;
err = udp_v6_send_skb(skb, &fl6);
out: out:
up->len = 0; up->len = 0;
up->pending = 0; up->pending = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment