aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevich@gmail.com>2015-01-31 10:40:16 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-02 22:28:04 -0500
commitd39d938c8228a4c5860138a53cf2b9ae4c4baec2 (patch)
tree187e996dd064f32b17528c357bf07149be77012b /net/ipv6/udp.c
parent6422398c2ab09268a55112f98cbf96bbf0184328 (diff)
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: Vladislav Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c67
1 files changed, 40 insertions, 27 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index e41f017cd479..67a3d70f7ac4 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
990{ 990{
991 unsigned int offset; 991 unsigned int offset;
992 struct udphdr *uh = udp_hdr(skb); 992 struct udphdr *uh = udp_hdr(skb);
993 struct sk_buff *frags = skb_shinfo(skb)->frag_list;
993 __wsum csum = 0; 994 __wsum csum = 0;
994 995
995 if (skb_queue_len(&sk->sk_write_queue) == 1) { 996 if (!frags) {
996 /* Only one fragment on the socket. */ 997 /* Only one fragment on the socket. */
997 skb->csum_start = skb_transport_header(skb) - skb->head; 998 skb->csum_start = skb_transport_header(skb) - skb->head;
998 skb->csum_offset = offsetof(struct udphdr, check); 999 skb->csum_offset = offsetof(struct udphdr, check);
@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
1008 1009
1009 skb->ip_summed = CHECKSUM_NONE; 1010 skb->ip_summed = CHECKSUM_NONE;
1010 1011
1011 skb_queue_walk(&sk->sk_write_queue, skb) { 1012 do {
1012 csum = csum_add(csum, skb->csum); 1013 csum = csum_add(csum, frags->csum);
1013 } 1014 } while ((frags = frags->next));
1014 1015
1015 uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 1016 uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
1016 csum); 1017 csum);
@@ -1023,26 +1024,15 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
1023 * Sending 1024 * Sending
1024 */ 1025 */
1025 1026
1026static int udp_v6_push_pending_frames(struct sock *sk) 1027static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6)
1027{ 1028{
1028 struct sk_buff *skb; 1029 struct sock *sk = skb->sk;
1029 struct udphdr *uh; 1030 struct udphdr *uh;
1030 struct udp_sock *up = udp_sk(sk);
1031 struct inet_sock *inet = inet_sk(sk);
1032 struct flowi6 *fl6;
1033 int err = 0; 1031 int err = 0;
1034 int is_udplite = IS_UDPLITE(sk); 1032 int is_udplite = IS_UDPLITE(sk);
1035 __wsum csum = 0; 1033 __wsum csum = 0;
1036 1034 int offset = skb_transport_offset(skb);
1037 if (up->pending == AF_INET) 1035 int len = skb->len - offset;
1038 return udp_push_pending_frames(sk);
1039
1040 fl6 = &inet->cork.fl.u.ip6;
1041
1042 /* Grab the skbuff where UDP header space exists. */
1043 skb = skb_peek(&sk->sk_write_queue);
1044 if (skb == NULL)
1045 goto out;
1046 1036
1047 /* 1037 /*
1048 * Create a UDP header 1038 * Create a UDP header
@@ -1050,29 +1040,28 @@ static int udp_v6_push_pending_frames(struct sock *sk)
1050 uh = udp_hdr(skb); 1040 uh = udp_hdr(skb);
1051 uh->source = fl6->fl6_sport; 1041 uh->source = fl6->fl6_sport;
1052 uh->dest = fl6->fl6_dport; 1042 uh->dest = fl6->fl6_dport;
1053 uh->len = htons(up->len); 1043 uh->len = htons(len);
1054 uh->check = 0; 1044 uh->check = 0;
1055 1045
1056 if (is_udplite) 1046 if (is_udplite)
1057 csum = udplite_csum_outgoing(sk, skb); 1047 csum = udplite_csum(skb);
1058 else if (up->no_check6_tx) { /* UDP csum disabled */ 1048 else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */
1059 skb->ip_summed = CHECKSUM_NONE; 1049 skb->ip_summed = CHECKSUM_NONE;
1060 goto send; 1050 goto send;
1061 } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ 1051 } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
1062 udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, 1052 udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len);
1063 up->len);
1064 goto send; 1053 goto send;
1065 } else 1054 } else
1066 csum = udp_csum_outgoing(sk, skb); 1055 csum = udp_csum(skb);
1067 1056
1068 /* add protocol-dependent pseudo-header */ 1057 /* add protocol-dependent pseudo-header */
1069 uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, 1058 uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
1070 up->len, fl6->flowi6_proto, csum); 1059 len, fl6->flowi6_proto, csum);
1071 if (uh->check == 0) 1060 if (uh->check == 0)
1072 uh->check = CSUM_MANGLED_0; 1061 uh->check = CSUM_MANGLED_0;
1073 1062
1074send: 1063send:
1075 err = ip6_push_pending_frames(sk); 1064 err = ip6_send_skb(skb);
1076 if (err) { 1065 if (err) {
1077 if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { 1066 if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
1078 UDP6_INC_STATS_USER(sock_net(sk), 1067 UDP6_INC_STATS_USER(sock_net(sk),
@@ -1082,6 +1071,30 @@ send:
1082 } else 1071 } else
1083 UDP6_INC_STATS_USER(sock_net(sk), 1072 UDP6_INC_STATS_USER(sock_net(sk),
1084 UDP_MIB_OUTDATAGRAMS, is_udplite); 1073 UDP_MIB_OUTDATAGRAMS, is_udplite);
1074 return err;
1075}
1076
1077static int udp_v6_push_pending_frames(struct sock *sk)
1078{
1079 struct sk_buff *skb;
1080 struct udp_sock *up = udp_sk(sk);
1081 struct flowi6 fl6;
1082 int err = 0;
1083
1084 if (up->pending == AF_INET)
1085 return udp_push_pending_frames(sk);
1086
1087 /* ip6_finish_skb will release the cork, so make a copy of
1088 * fl6 here.
1089 */
1090 fl6 = inet_sk(sk)->cork.fl.u.ip6;
1091
1092 skb = ip6_finish_skb(sk);
1093 if (!skb)
1094 goto out;
1095
1096 err = udp_v6_send_skb(skb, &fl6);
1097
1085out: 1098out:
1086 up->len = 0; 1099 up->len = 0;
1087 up->pending = 0; 1100 up->pending = 0;