diff options
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 89 |
1 files changed, 86 insertions, 3 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e38d6f240321..47e2f4972f79 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -912,6 +912,39 @@ static inline int select_size(const struct sock *sk, bool sg) | |||
912 | return tmp; | 912 | return tmp; |
913 | } | 913 | } |
914 | 914 | ||
915 | static int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) | ||
916 | { | ||
917 | struct sk_buff *skb; | ||
918 | struct tcp_skb_cb *cb; | ||
919 | struct tcphdr *th; | ||
920 | |||
921 | skb = alloc_skb(size + sizeof(*th), sk->sk_allocation); | ||
922 | if (!skb) | ||
923 | goto err; | ||
924 | |||
925 | th = (struct tcphdr *)skb_put(skb, sizeof(*th)); | ||
926 | skb_reset_transport_header(skb); | ||
927 | memset(th, 0, sizeof(*th)); | ||
928 | |||
929 | if (memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size)) | ||
930 | goto err_free; | ||
931 | |||
932 | cb = TCP_SKB_CB(skb); | ||
933 | |||
934 | TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt; | ||
935 | TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + size; | ||
936 | TCP_SKB_CB(skb)->ack_seq = tcp_sk(sk)->snd_una - 1; | ||
937 | |||
938 | tcp_queue_rcv(sk, skb, sizeof(*th)); | ||
939 | |||
940 | return size; | ||
941 | |||
942 | err_free: | ||
943 | kfree_skb(skb); | ||
944 | err: | ||
945 | return -ENOMEM; | ||
946 | } | ||
947 | |||
915 | int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 948 | int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
916 | size_t size) | 949 | size_t size) |
917 | { | 950 | { |
@@ -933,6 +966,19 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
933 | if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) | 966 | if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) |
934 | goto out_err; | 967 | goto out_err; |
935 | 968 | ||
969 | if (unlikely(tp->repair)) { | ||
970 | if (tp->repair_queue == TCP_RECV_QUEUE) { | ||
971 | copied = tcp_send_rcvq(sk, msg, size); | ||
972 | goto out; | ||
973 | } | ||
974 | |||
975 | err = -EINVAL; | ||
976 | if (tp->repair_queue == TCP_NO_QUEUE) | ||
977 | goto out_err; | ||
978 | |||
979 | /* 'common' sending to sendq */ | ||
980 | } | ||
981 | |||
936 | /* This should be in poll */ | 982 | /* This should be in poll */ |
937 | clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); | 983 | clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); |
938 | 984 | ||
@@ -1089,7 +1135,7 @@ new_segment: | |||
1089 | if ((seglen -= copy) == 0 && iovlen == 0) | 1135 | if ((seglen -= copy) == 0 && iovlen == 0) |
1090 | goto out; | 1136 | goto out; |
1091 | 1137 | ||
1092 | if (skb->len < max || (flags & MSG_OOB)) | 1138 | if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) |
1093 | continue; | 1139 | continue; |
1094 | 1140 | ||
1095 | if (forced_push(tp)) { | 1141 | if (forced_push(tp)) { |
@@ -1102,7 +1148,7 @@ new_segment: | |||
1102 | wait_for_sndbuf: | 1148 | wait_for_sndbuf: |
1103 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); | 1149 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); |
1104 | wait_for_memory: | 1150 | wait_for_memory: |
1105 | if (copied) | 1151 | if (copied && likely(!tp->repair)) |
1106 | tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); | 1152 | tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); |
1107 | 1153 | ||
1108 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) | 1154 | if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) |
@@ -1113,7 +1159,7 @@ wait_for_memory: | |||
1113 | } | 1159 | } |
1114 | 1160 | ||
1115 | out: | 1161 | out: |
1116 | if (copied) | 1162 | if (copied && likely(!tp->repair)) |
1117 | tcp_push(sk, flags, mss_now, tp->nonagle); | 1163 | tcp_push(sk, flags, mss_now, tp->nonagle); |
1118 | release_sock(sk); | 1164 | release_sock(sk); |
1119 | return copied; | 1165 | return copied; |
@@ -1187,6 +1233,24 @@ static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags) | |||
1187 | return -EAGAIN; | 1233 | return -EAGAIN; |
1188 | } | 1234 | } |
1189 | 1235 | ||
1236 | static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len) | ||
1237 | { | ||
1238 | struct sk_buff *skb; | ||
1239 | int copied = 0, err = 0; | ||
1240 | |||
1241 | /* XXX -- need to support SO_PEEK_OFF */ | ||
1242 | |||
1243 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
1244 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, skb->len); | ||
1245 | if (err) | ||
1246 | break; | ||
1247 | |||
1248 | copied += skb->len; | ||
1249 | } | ||
1250 | |||
1251 | return err ?: copied; | ||
1252 | } | ||
1253 | |||
1190 | /* Clean up the receive buffer for full frames taken by the user, | 1254 | /* Clean up the receive buffer for full frames taken by the user, |
1191 | * then send an ACK if necessary. COPIED is the number of bytes | 1255 | * then send an ACK if necessary. COPIED is the number of bytes |
1192 | * tcp_recvmsg has given to the user so far, it speeds up the | 1256 | * tcp_recvmsg has given to the user so far, it speeds up the |
@@ -1432,6 +1496,21 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1432 | if (flags & MSG_OOB) | 1496 | if (flags & MSG_OOB) |
1433 | goto recv_urg; | 1497 | goto recv_urg; |
1434 | 1498 | ||
1499 | if (unlikely(tp->repair)) { | ||
1500 | err = -EPERM; | ||
1501 | if (!(flags & MSG_PEEK)) | ||
1502 | goto out; | ||
1503 | |||
1504 | if (tp->repair_queue == TCP_SEND_QUEUE) | ||
1505 | goto recv_sndq; | ||
1506 | |||
1507 | err = -EINVAL; | ||
1508 | if (tp->repair_queue == TCP_NO_QUEUE) | ||
1509 | goto out; | ||
1510 | |||
1511 | /* 'common' recv queue MSG_PEEK-ing */ | ||
1512 | } | ||
1513 | |||
1435 | seq = &tp->copied_seq; | 1514 | seq = &tp->copied_seq; |
1436 | if (flags & MSG_PEEK) { | 1515 | if (flags & MSG_PEEK) { |
1437 | peek_seq = tp->copied_seq; | 1516 | peek_seq = tp->copied_seq; |
@@ -1783,6 +1862,10 @@ out: | |||
1783 | recv_urg: | 1862 | recv_urg: |
1784 | err = tcp_recv_urg(sk, msg, len, flags); | 1863 | err = tcp_recv_urg(sk, msg, len, flags); |
1785 | goto out; | 1864 | goto out; |
1865 | |||
1866 | recv_sndq: | ||
1867 | err = tcp_peek_sndq(sk, msg, len); | ||
1868 | goto out; | ||
1786 | } | 1869 | } |
1787 | EXPORT_SYMBOL(tcp_recvmsg); | 1870 | EXPORT_SYMBOL(tcp_recvmsg); |
1788 | 1871 | ||