diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/af_inet.c | 51 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 16 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 66 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 47 | ||||
-rw-r--r-- | net/ipv4/xfrm4_output.c | 54 |
6 files changed, 199 insertions, 37 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0a277453526b..461216b47948 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -68,6 +68,7 @@ | |||
68 | */ | 68 | */ |
69 | 69 | ||
70 | #include <linux/config.h> | 70 | #include <linux/config.h> |
71 | #include <linux/err.h> | ||
71 | #include <linux/errno.h> | 72 | #include <linux/errno.h> |
72 | #include <linux/types.h> | 73 | #include <linux/types.h> |
73 | #include <linux/socket.h> | 74 | #include <linux/socket.h> |
@@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *sk) | |||
1096 | 1097 | ||
1097 | EXPORT_SYMBOL(inet_sk_rebuild_header); | 1098 | EXPORT_SYMBOL(inet_sk_rebuild_header); |
1098 | 1099 | ||
1100 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) | ||
1101 | { | ||
1102 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
1103 | struct iphdr *iph; | ||
1104 | struct net_protocol *ops; | ||
1105 | int proto; | ||
1106 | int ihl; | ||
1107 | int id; | ||
1108 | |||
1109 | if (!pskb_may_pull(skb, sizeof(*iph))) | ||
1110 | goto out; | ||
1111 | |||
1112 | iph = skb->nh.iph; | ||
1113 | ihl = iph->ihl * 4; | ||
1114 | if (ihl < sizeof(*iph)) | ||
1115 | goto out; | ||
1116 | |||
1117 | if (!pskb_may_pull(skb, ihl)) | ||
1118 | goto out; | ||
1119 | |||
1120 | skb->h.raw = __skb_pull(skb, ihl); | ||
1121 | iph = skb->nh.iph; | ||
1122 | id = ntohs(iph->id); | ||
1123 | proto = iph->protocol & (MAX_INET_PROTOS - 1); | ||
1124 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
1125 | |||
1126 | rcu_read_lock(); | ||
1127 | ops = rcu_dereference(inet_protos[proto]); | ||
1128 | if (ops && ops->gso_segment) | ||
1129 | segs = ops->gso_segment(skb, sg); | ||
1130 | rcu_read_unlock(); | ||
1131 | |||
1132 | if (IS_ERR(segs)) | ||
1133 | goto out; | ||
1134 | |||
1135 | skb = segs; | ||
1136 | do { | ||
1137 | iph = skb->nh.iph; | ||
1138 | iph->id = htons(id++); | ||
1139 | iph->tot_len = htons(skb->len - skb->mac_len); | ||
1140 | iph->check = 0; | ||
1141 | iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); | ||
1142 | } while ((skb = skb->next)); | ||
1143 | |||
1144 | out: | ||
1145 | return segs; | ||
1146 | } | ||
1147 | |||
1099 | #ifdef CONFIG_IP_MULTICAST | 1148 | #ifdef CONFIG_IP_MULTICAST |
1100 | static struct net_protocol igmp_protocol = { | 1149 | static struct net_protocol igmp_protocol = { |
1101 | .handler = igmp_rcv, | 1150 | .handler = igmp_rcv, |
@@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol = { | |||
1105 | static struct net_protocol tcp_protocol = { | 1154 | static struct net_protocol tcp_protocol = { |
1106 | .handler = tcp_v4_rcv, | 1155 | .handler = tcp_v4_rcv, |
1107 | .err_handler = tcp_v4_err, | 1156 | .err_handler = tcp_v4_err, |
1157 | .gso_segment = tcp_tso_segment, | ||
1108 | .no_policy = 1, | 1158 | .no_policy = 1, |
1109 | }; | 1159 | }; |
1110 | 1160 | ||
@@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void); | |||
1150 | static struct packet_type ip_packet_type = { | 1200 | static struct packet_type ip_packet_type = { |
1151 | .type = __constant_htons(ETH_P_IP), | 1201 | .type = __constant_htons(ETH_P_IP), |
1152 | .func = ip_rcv, | 1202 | .func = ip_rcv, |
1203 | .gso_segment = inet_gso_segment, | ||
1153 | }; | 1204 | }; |
1154 | 1205 | ||
1155 | static int __init inet_init(void) | 1206 | static int __init inet_init(void) |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8538aac3d148..7624fd1d8f9f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -210,8 +210,7 @@ static inline int ip_finish_output(struct sk_buff *skb) | |||
210 | return dst_output(skb); | 210 | return dst_output(skb); |
211 | } | 211 | } |
212 | #endif | 212 | #endif |
213 | if (skb->len > dst_mtu(skb->dst) && | 213 | if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) |
214 | !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) | ||
215 | return ip_fragment(skb, ip_finish_output2); | 214 | return ip_fragment(skb, ip_finish_output2); |
216 | else | 215 | else |
217 | return ip_finish_output2(skb); | 216 | return ip_finish_output2(skb); |
@@ -362,7 +361,7 @@ packet_routed: | |||
362 | } | 361 | } |
363 | 362 | ||
364 | ip_select_ident_more(iph, &rt->u.dst, sk, | 363 | ip_select_ident_more(iph, &rt->u.dst, sk, |
365 | (skb_shinfo(skb)->tso_segs ?: 1) - 1); | 364 | (skb_shinfo(skb)->gso_segs ?: 1) - 1); |
366 | 365 | ||
367 | /* Add an IP checksum. */ | 366 | /* Add an IP checksum. */ |
368 | ip_send_check(iph); | 367 | ip_send_check(iph); |
@@ -744,7 +743,8 @@ static inline int ip_ufo_append_data(struct sock *sk, | |||
744 | (length - transhdrlen)); | 743 | (length - transhdrlen)); |
745 | if (!err) { | 744 | if (!err) { |
746 | /* specify the length of each IP datagram fragment*/ | 745 | /* specify the length of each IP datagram fragment*/ |
747 | skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); | 746 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; |
747 | skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; | ||
748 | __skb_queue_tail(&sk->sk_write_queue, skb); | 748 | __skb_queue_tail(&sk->sk_write_queue, skb); |
749 | 749 | ||
750 | return 0; | 750 | return 0; |
@@ -1087,14 +1087,16 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
1087 | 1087 | ||
1088 | inet->cork.length += size; | 1088 | inet->cork.length += size; |
1089 | if ((sk->sk_protocol == IPPROTO_UDP) && | 1089 | if ((sk->sk_protocol == IPPROTO_UDP) && |
1090 | (rt->u.dst.dev->features & NETIF_F_UFO)) | 1090 | (rt->u.dst.dev->features & NETIF_F_UFO)) { |
1091 | skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); | 1091 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; |
1092 | skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; | ||
1093 | } | ||
1092 | 1094 | ||
1093 | 1095 | ||
1094 | while (size > 0) { | 1096 | while (size > 0) { |
1095 | int i; | 1097 | int i; |
1096 | 1098 | ||
1097 | if (skb_shinfo(skb)->ufo_size) | 1099 | if (skb_shinfo(skb)->gso_size) |
1098 | len = size; | 1100 | len = size; |
1099 | else { | 1101 | else { |
1100 | 1102 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 74998f250071..0e029c4e2903 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -258,6 +258,7 @@ | |||
258 | #include <linux/random.h> | 258 | #include <linux/random.h> |
259 | #include <linux/bootmem.h> | 259 | #include <linux/bootmem.h> |
260 | #include <linux/cache.h> | 260 | #include <linux/cache.h> |
261 | #include <linux/err.h> | ||
261 | 262 | ||
262 | #include <net/icmp.h> | 263 | #include <net/icmp.h> |
263 | #include <net/tcp.h> | 264 | #include <net/tcp.h> |
@@ -571,7 +572,7 @@ new_segment: | |||
571 | skb->ip_summed = CHECKSUM_HW; | 572 | skb->ip_summed = CHECKSUM_HW; |
572 | tp->write_seq += copy; | 573 | tp->write_seq += copy; |
573 | TCP_SKB_CB(skb)->end_seq += copy; | 574 | TCP_SKB_CB(skb)->end_seq += copy; |
574 | skb_shinfo(skb)->tso_segs = 0; | 575 | skb_shinfo(skb)->gso_segs = 0; |
575 | 576 | ||
576 | if (!copied) | 577 | if (!copied) |
577 | TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; | 578 | TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; |
@@ -818,7 +819,7 @@ new_segment: | |||
818 | 819 | ||
819 | tp->write_seq += copy; | 820 | tp->write_seq += copy; |
820 | TCP_SKB_CB(skb)->end_seq += copy; | 821 | TCP_SKB_CB(skb)->end_seq += copy; |
821 | skb_shinfo(skb)->tso_segs = 0; | 822 | skb_shinfo(skb)->gso_segs = 0; |
822 | 823 | ||
823 | from += copy; | 824 | from += copy; |
824 | copied += copy; | 825 | copied += copy; |
@@ -2144,6 +2145,67 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, | |||
2144 | EXPORT_SYMBOL(compat_tcp_getsockopt); | 2145 | EXPORT_SYMBOL(compat_tcp_getsockopt); |
2145 | #endif | 2146 | #endif |
2146 | 2147 | ||
2148 | struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) | ||
2149 | { | ||
2150 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
2151 | struct tcphdr *th; | ||
2152 | unsigned thlen; | ||
2153 | unsigned int seq; | ||
2154 | unsigned int delta; | ||
2155 | unsigned int oldlen; | ||
2156 | unsigned int len; | ||
2157 | |||
2158 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
2159 | goto out; | ||
2160 | |||
2161 | th = skb->h.th; | ||
2162 | thlen = th->doff * 4; | ||
2163 | if (thlen < sizeof(*th)) | ||
2164 | goto out; | ||
2165 | |||
2166 | if (!pskb_may_pull(skb, thlen)) | ||
2167 | goto out; | ||
2168 | |||
2169 | oldlen = ~htonl(skb->len); | ||
2170 | __skb_pull(skb, thlen); | ||
2171 | |||
2172 | segs = skb_segment(skb, sg); | ||
2173 | if (IS_ERR(segs)) | ||
2174 | goto out; | ||
2175 | |||
2176 | len = skb_shinfo(skb)->gso_size; | ||
2177 | delta = csum_add(oldlen, htonl(thlen + len)); | ||
2178 | |||
2179 | skb = segs; | ||
2180 | th = skb->h.th; | ||
2181 | seq = ntohl(th->seq); | ||
2182 | |||
2183 | do { | ||
2184 | th->fin = th->psh = 0; | ||
2185 | |||
2186 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
2187 | th->check = csum_fold(csum_partial( | ||
2188 | skb->h.raw, thlen, csum_add(skb->csum, delta))); | ||
2189 | } | ||
2190 | |||
2191 | seq += len; | ||
2192 | skb = skb->next; | ||
2193 | th = skb->h.th; | ||
2194 | |||
2195 | th->seq = htonl(seq); | ||
2196 | th->cwr = 0; | ||
2197 | } while (skb->next); | ||
2198 | |||
2199 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
2200 | delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw)); | ||
2201 | th->check = csum_fold(csum_partial( | ||
2202 | skb->h.raw, thlen, csum_add(skb->csum, delta))); | ||
2203 | } | ||
2204 | |||
2205 | out: | ||
2206 | return segs; | ||
2207 | } | ||
2208 | |||
2147 | extern void __skb_cb_too_small_for_tcp(int, int); | 2209 | extern void __skb_cb_too_small_for_tcp(int, int); |
2148 | extern struct tcp_congestion_ops tcp_reno; | 2210 | extern struct tcp_congestion_ops tcp_reno; |
2149 | 2211 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e08245bdda3a..94fe5b1f9dcb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1073,7 +1073,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1073 | else | 1073 | else |
1074 | pkt_len = (end_seq - | 1074 | pkt_len = (end_seq - |
1075 | TCP_SKB_CB(skb)->seq); | 1075 | TCP_SKB_CB(skb)->seq); |
1076 | if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size)) | 1076 | if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size)) |
1077 | break; | 1077 | break; |
1078 | pcount = tcp_skb_pcount(skb); | 1078 | pcount = tcp_skb_pcount(skb); |
1079 | } | 1079 | } |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 07bb5a2b375e..bdd71db8bf90 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -515,15 +515,17 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned | |||
515 | /* Avoid the costly divide in the normal | 515 | /* Avoid the costly divide in the normal |
516 | * non-TSO case. | 516 | * non-TSO case. |
517 | */ | 517 | */ |
518 | skb_shinfo(skb)->tso_segs = 1; | 518 | skb_shinfo(skb)->gso_segs = 1; |
519 | skb_shinfo(skb)->tso_size = 0; | 519 | skb_shinfo(skb)->gso_size = 0; |
520 | skb_shinfo(skb)->gso_type = 0; | ||
520 | } else { | 521 | } else { |
521 | unsigned int factor; | 522 | unsigned int factor; |
522 | 523 | ||
523 | factor = skb->len + (mss_now - 1); | 524 | factor = skb->len + (mss_now - 1); |
524 | factor /= mss_now; | 525 | factor /= mss_now; |
525 | skb_shinfo(skb)->tso_segs = factor; | 526 | skb_shinfo(skb)->gso_segs = factor; |
526 | skb_shinfo(skb)->tso_size = mss_now; | 527 | skb_shinfo(skb)->gso_size = mss_now; |
528 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | ||
527 | } | 529 | } |
528 | } | 530 | } |
529 | 531 | ||
@@ -914,7 +916,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int | |||
914 | 916 | ||
915 | if (!tso_segs || | 917 | if (!tso_segs || |
916 | (tso_segs > 1 && | 918 | (tso_segs > 1 && |
917 | skb_shinfo(skb)->tso_size != mss_now)) { | 919 | tcp_skb_mss(skb) != mss_now)) { |
918 | tcp_set_skb_tso_segs(sk, skb, mss_now); | 920 | tcp_set_skb_tso_segs(sk, skb, mss_now); |
919 | tso_segs = tcp_skb_pcount(skb); | 921 | tso_segs = tcp_skb_pcount(skb); |
920 | } | 922 | } |
@@ -1724,8 +1726,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
1724 | tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { | 1726 | tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { |
1725 | if (!pskb_trim(skb, 0)) { | 1727 | if (!pskb_trim(skb, 0)) { |
1726 | TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; | 1728 | TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; |
1727 | skb_shinfo(skb)->tso_segs = 1; | 1729 | skb_shinfo(skb)->gso_segs = 1; |
1728 | skb_shinfo(skb)->tso_size = 0; | 1730 | skb_shinfo(skb)->gso_size = 0; |
1731 | skb_shinfo(skb)->gso_type = 0; | ||
1729 | skb->ip_summed = CHECKSUM_NONE; | 1732 | skb->ip_summed = CHECKSUM_NONE; |
1730 | skb->csum = 0; | 1733 | skb->csum = 0; |
1731 | } | 1734 | } |
@@ -1930,8 +1933,9 @@ void tcp_send_fin(struct sock *sk) | |||
1930 | skb->csum = 0; | 1933 | skb->csum = 0; |
1931 | TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN); | 1934 | TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN); |
1932 | TCP_SKB_CB(skb)->sacked = 0; | 1935 | TCP_SKB_CB(skb)->sacked = 0; |
1933 | skb_shinfo(skb)->tso_segs = 1; | 1936 | skb_shinfo(skb)->gso_segs = 1; |
1934 | skb_shinfo(skb)->tso_size = 0; | 1937 | skb_shinfo(skb)->gso_size = 0; |
1938 | skb_shinfo(skb)->gso_type = 0; | ||
1935 | 1939 | ||
1936 | /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ | 1940 | /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ |
1937 | TCP_SKB_CB(skb)->seq = tp->write_seq; | 1941 | TCP_SKB_CB(skb)->seq = tp->write_seq; |
@@ -1963,8 +1967,9 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) | |||
1963 | skb->csum = 0; | 1967 | skb->csum = 0; |
1964 | TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST); | 1968 | TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST); |
1965 | TCP_SKB_CB(skb)->sacked = 0; | 1969 | TCP_SKB_CB(skb)->sacked = 0; |
1966 | skb_shinfo(skb)->tso_segs = 1; | 1970 | skb_shinfo(skb)->gso_segs = 1; |
1967 | skb_shinfo(skb)->tso_size = 0; | 1971 | skb_shinfo(skb)->gso_size = 0; |
1972 | skb_shinfo(skb)->gso_type = 0; | ||
1968 | 1973 | ||
1969 | /* Send it off. */ | 1974 | /* Send it off. */ |
1970 | TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp); | 1975 | TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp); |
@@ -2047,8 +2052,9 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2047 | TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn; | 2052 | TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn; |
2048 | TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; | 2053 | TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; |
2049 | TCP_SKB_CB(skb)->sacked = 0; | 2054 | TCP_SKB_CB(skb)->sacked = 0; |
2050 | skb_shinfo(skb)->tso_segs = 1; | 2055 | skb_shinfo(skb)->gso_segs = 1; |
2051 | skb_shinfo(skb)->tso_size = 0; | 2056 | skb_shinfo(skb)->gso_size = 0; |
2057 | skb_shinfo(skb)->gso_type = 0; | ||
2052 | th->seq = htonl(TCP_SKB_CB(skb)->seq); | 2058 | th->seq = htonl(TCP_SKB_CB(skb)->seq); |
2053 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); | 2059 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); |
2054 | if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ | 2060 | if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ |
@@ -2152,8 +2158,9 @@ int tcp_connect(struct sock *sk) | |||
2152 | TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; | 2158 | TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; |
2153 | TCP_ECN_send_syn(sk, tp, buff); | 2159 | TCP_ECN_send_syn(sk, tp, buff); |
2154 | TCP_SKB_CB(buff)->sacked = 0; | 2160 | TCP_SKB_CB(buff)->sacked = 0; |
2155 | skb_shinfo(buff)->tso_segs = 1; | 2161 | skb_shinfo(buff)->gso_segs = 1; |
2156 | skb_shinfo(buff)->tso_size = 0; | 2162 | skb_shinfo(buff)->gso_size = 0; |
2163 | skb_shinfo(buff)->gso_type = 0; | ||
2157 | buff->csum = 0; | 2164 | buff->csum = 0; |
2158 | TCP_SKB_CB(buff)->seq = tp->write_seq++; | 2165 | TCP_SKB_CB(buff)->seq = tp->write_seq++; |
2159 | TCP_SKB_CB(buff)->end_seq = tp->write_seq; | 2166 | TCP_SKB_CB(buff)->end_seq = tp->write_seq; |
@@ -2257,8 +2264,9 @@ void tcp_send_ack(struct sock *sk) | |||
2257 | buff->csum = 0; | 2264 | buff->csum = 0; |
2258 | TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK; | 2265 | TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK; |
2259 | TCP_SKB_CB(buff)->sacked = 0; | 2266 | TCP_SKB_CB(buff)->sacked = 0; |
2260 | skb_shinfo(buff)->tso_segs = 1; | 2267 | skb_shinfo(buff)->gso_segs = 1; |
2261 | skb_shinfo(buff)->tso_size = 0; | 2268 | skb_shinfo(buff)->gso_size = 0; |
2269 | skb_shinfo(buff)->gso_type = 0; | ||
2262 | 2270 | ||
2263 | /* Send it off, this clears delayed acks for us. */ | 2271 | /* Send it off, this clears delayed acks for us. */ |
2264 | TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp); | 2272 | TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp); |
@@ -2293,8 +2301,9 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent) | |||
2293 | skb->csum = 0; | 2301 | skb->csum = 0; |
2294 | TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; | 2302 | TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; |
2295 | TCP_SKB_CB(skb)->sacked = urgent; | 2303 | TCP_SKB_CB(skb)->sacked = urgent; |
2296 | skb_shinfo(skb)->tso_segs = 1; | 2304 | skb_shinfo(skb)->gso_segs = 1; |
2297 | skb_shinfo(skb)->tso_size = 0; | 2305 | skb_shinfo(skb)->gso_size = 0; |
2306 | skb_shinfo(skb)->gso_type = 0; | ||
2298 | 2307 | ||
2299 | /* Use a previous sequence. This should cause the other | 2308 | /* Use a previous sequence. This should cause the other |
2300 | * end to send an ack. Don't queue or clone SKB, just | 2309 | * end to send an ack. Don't queue or clone SKB, just |
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index ac9d91d4bb05..193363e22932 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -9,6 +9,8 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/compiler.h> | 11 | #include <linux/compiler.h> |
12 | #include <linux/if_ether.h> | ||
13 | #include <linux/kernel.h> | ||
12 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
13 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
14 | #include <linux/netfilter_ipv4.h> | 16 | #include <linux/netfilter_ipv4.h> |
@@ -97,16 +99,10 @@ error_nolock: | |||
97 | goto out_exit; | 99 | goto out_exit; |
98 | } | 100 | } |
99 | 101 | ||
100 | static int xfrm4_output_finish(struct sk_buff *skb) | 102 | static int xfrm4_output_finish2(struct sk_buff *skb) |
101 | { | 103 | { |
102 | int err; | 104 | int err; |
103 | 105 | ||
104 | #ifdef CONFIG_NETFILTER | ||
105 | if (!skb->dst->xfrm) { | ||
106 | IPCB(skb)->flags |= IPSKB_REROUTED; | ||
107 | return dst_output(skb); | ||
108 | } | ||
109 | #endif | ||
110 | while (likely((err = xfrm4_output_one(skb)) == 0)) { | 106 | while (likely((err = xfrm4_output_one(skb)) == 0)) { |
111 | nf_reset(skb); | 107 | nf_reset(skb); |
112 | 108 | ||
@@ -119,7 +115,7 @@ static int xfrm4_output_finish(struct sk_buff *skb) | |||
119 | return dst_output(skb); | 115 | return dst_output(skb); |
120 | 116 | ||
121 | err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, | 117 | err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, |
122 | skb->dst->dev, xfrm4_output_finish); | 118 | skb->dst->dev, xfrm4_output_finish2); |
123 | if (unlikely(err != 1)) | 119 | if (unlikely(err != 1)) |
124 | break; | 120 | break; |
125 | } | 121 | } |
@@ -127,6 +123,48 @@ static int xfrm4_output_finish(struct sk_buff *skb) | |||
127 | return err; | 123 | return err; |
128 | } | 124 | } |
129 | 125 | ||
126 | static int xfrm4_output_finish(struct sk_buff *skb) | ||
127 | { | ||
128 | struct sk_buff *segs; | ||
129 | |||
130 | #ifdef CONFIG_NETFILTER | ||
131 | if (!skb->dst->xfrm) { | ||
132 | IPCB(skb)->flags |= IPSKB_REROUTED; | ||
133 | return dst_output(skb); | ||
134 | } | ||
135 | #endif | ||
136 | |||
137 | if (!skb_shinfo(skb)->gso_size) | ||
138 | return xfrm4_output_finish2(skb); | ||
139 | |||
140 | skb->protocol = htons(ETH_P_IP); | ||
141 | segs = skb_gso_segment(skb, 0); | ||
142 | kfree_skb(skb); | ||
143 | if (unlikely(IS_ERR(segs))) | ||
144 | return PTR_ERR(segs); | ||
145 | |||
146 | do { | ||
147 | struct sk_buff *nskb = segs->next; | ||
148 | int err; | ||
149 | |||
150 | segs->next = NULL; | ||
151 | err = xfrm4_output_finish2(segs); | ||
152 | |||
153 | if (unlikely(err)) { | ||
154 | while ((segs = nskb)) { | ||
155 | nskb = segs->next; | ||
156 | segs->next = NULL; | ||
157 | kfree_skb(segs); | ||
158 | } | ||
159 | return err; | ||
160 | } | ||
161 | |||
162 | segs = nskb; | ||
163 | } while (segs); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
130 | int xfrm4_output(struct sk_buff *skb) | 168 | int xfrm4_output(struct sk_buff *skb) |
131 | { | 169 | { |
132 | return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, | 170 | return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, |