aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_sctp.c2
-rw-r--r--net/ipv4/tcp.c17
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_output.c9
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/exthdrs.c4
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_input.c7
-rw-r--r--net/ipv6/ip6_output.c4
-rw-r--r--net/ipv6/ipv6_sockglue.c62
-rw-r--r--net/ipv6/tcp_ipv6.c7
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c2
13 files changed, 91 insertions, 33 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0c872fd0849d..ca0e714613fb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -743,7 +743,7 @@ static inline int ip_ufo_append_data(struct sock *sk,
743 if (!err) { 743 if (!err) {
744 /* specify the length of each IP datagram fragment*/ 744 /* specify the length of each IP datagram fragment*/
745 skb_shinfo(skb)->gso_size = mtu - fragheaderlen; 745 skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
746 skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; 746 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
747 __skb_queue_tail(&sk->sk_write_queue, skb); 747 __skb_queue_tail(&sk->sk_write_queue, skb);
748 748
749 return 0; 749 return 0;
@@ -1088,7 +1088,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
1088 if ((sk->sk_protocol == IPPROTO_UDP) && 1088 if ((sk->sk_protocol == IPPROTO_UDP) &&
1089 (rt->u.dst.dev->features & NETIF_F_UFO)) { 1089 (rt->u.dst.dev->features & NETIF_F_UFO)) {
1090 skb_shinfo(skb)->gso_size = mtu - fragheaderlen; 1090 skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
1091 skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; 1091 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
1092 } 1092 }
1093 1093
1094 1094
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index 0416073c5600..2d3612cd5f18 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -254,7 +254,7 @@ static int do_basic_checks(struct ip_conntrack *conntrack,
254 } 254 }
255 255
256 DEBUGP("Basic checks passed\n"); 256 DEBUGP("Basic checks passed\n");
257 return 0; 257 return count == 0;
258} 258}
259 259
260static int new_state(enum ip_conntrack_dir dir, 260static int new_state(enum ip_conntrack_dir dir,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index a97450e9eb34..804458712d88 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -642,7 +642,7 @@ static inline int select_size(struct sock *sk, struct tcp_sock *tp)
642 int tmp = tp->mss_cache; 642 int tmp = tp->mss_cache;
643 643
644 if (sk->sk_route_caps & NETIF_F_SG) { 644 if (sk->sk_route_caps & NETIF_F_SG) {
645 if (sk->sk_route_caps & NETIF_F_TSO) 645 if (sk_can_gso(sk))
646 tmp = 0; 646 tmp = 0;
647 else { 647 else {
648 int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); 648 int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
@@ -2165,13 +2165,19 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2165 if (!pskb_may_pull(skb, thlen)) 2165 if (!pskb_may_pull(skb, thlen))
2166 goto out; 2166 goto out;
2167 2167
2168 segs = NULL;
2169 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST))
2170 goto out;
2171
2172 oldlen = (u16)~skb->len; 2168 oldlen = (u16)~skb->len;
2173 __skb_pull(skb, thlen); 2169 __skb_pull(skb, thlen);
2174 2170
2171 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
2172 /* Packet is from an untrusted source, reset gso_segs. */
2173 int mss = skb_shinfo(skb)->gso_size;
2174
2175 skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
2176
2177 segs = NULL;
2178 goto out;
2179 }
2180
2175 segs = skb_segment(skb, features); 2181 segs = skb_segment(skb, features);
2176 if (IS_ERR(segs)) 2182 if (IS_ERR(segs))
2177 goto out; 2183 goto out;
@@ -2208,6 +2214,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2208out: 2214out:
2209 return segs; 2215 return segs;
2210} 2216}
2217EXPORT_SYMBOL(tcp_tso_segment);
2211 2218
2212extern void __skb_cb_too_small_for_tcp(int, int); 2219extern void __skb_cb_too_small_for_tcp(int, int);
2213extern struct tcp_congestion_ops tcp_reno; 2220extern struct tcp_congestion_ops tcp_reno;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index e02a84cf9a53..8355b729fa95 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -241,6 +241,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
241 goto failure; 241 goto failure;
242 242
243 /* OK, now commit destination to socket. */ 243 /* OK, now commit destination to socket. */
244 sk->sk_gso_type = SKB_GSO_TCPV4;
244 sk_setup_caps(sk, &rt->u.dst); 245 sk_setup_caps(sk, &rt->u.dst);
245 246
246 if (!tp->write_seq) 247 if (!tp->write_seq)
@@ -883,6 +884,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
883 if (!newsk) 884 if (!newsk)
884 goto exit; 885 goto exit;
885 886
887 newsk->sk_gso_type = SKB_GSO_TCPV4;
886 sk_setup_caps(newsk, dst); 888 sk_setup_caps(newsk, dst);
887 889
888 newtp = tcp_sk(newsk); 890 newtp = tcp_sk(newsk);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 5a7cb4a9c867..5c08ea20a18d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -510,8 +510,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
510 510
511static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int mss_now) 511static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int mss_now)
512{ 512{
513 if (skb->len <= mss_now || 513 if (skb->len <= mss_now || !sk_can_gso(sk)) {
514 !(sk->sk_route_caps & NETIF_F_TSO)) {
515 /* Avoid the costly divide in the normal 514 /* Avoid the costly divide in the normal
516 * non-TSO case. 515 * non-TSO case.
517 */ 516 */
@@ -525,7 +524,7 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned
525 factor /= mss_now; 524 factor /= mss_now;
526 skb_shinfo(skb)->gso_segs = factor; 525 skb_shinfo(skb)->gso_segs = factor;
527 skb_shinfo(skb)->gso_size = mss_now; 526 skb_shinfo(skb)->gso_size = mss_now;
528 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; 527 skb_shinfo(skb)->gso_type = sk->sk_gso_type;
529 } 528 }
530} 529}
531 530
@@ -824,9 +823,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
824 823
825 mss_now = tp->mss_cache; 824 mss_now = tp->mss_cache;
826 825
827 if (large_allowed && 826 if (large_allowed && sk_can_gso(sk) && !tp->urg_mode)
828 (sk->sk_route_caps & NETIF_F_TSO) &&
829 !tp->urg_mode)
830 doing_tso = 1; 827 doing_tso = 1;
831 828
832 if (dst) { 829 if (dst) {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index a94c91b407ef..5a0ba58b86cc 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -659,8 +659,6 @@ int inet6_sk_rebuild_header(struct sock *sk)
659 } 659 }
660 660
661 ip6_dst_store(sk, dst, NULL); 661 ip6_dst_store(sk, dst, NULL);
662 sk->sk_route_caps = dst->dev->features &
663 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
664 } 662 }
665 663
666 return 0; 664 return 0;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index a18d4256372c..9d0ee7f0eeb5 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -179,7 +179,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
179 179
180static struct inet6_protocol destopt_protocol = { 180static struct inet6_protocol destopt_protocol = {
181 .handler = ipv6_destopt_rcv, 181 .handler = ipv6_destopt_rcv,
182 .flags = INET6_PROTO_NOPOLICY, 182 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
183}; 183};
184 184
185void __init ipv6_destopt_init(void) 185void __init ipv6_destopt_init(void)
@@ -340,7 +340,7 @@ looped_back:
340 340
341static struct inet6_protocol rthdr_protocol = { 341static struct inet6_protocol rthdr_protocol = {
342 .handler = ipv6_rthdr_rcv, 342 .handler = ipv6_rthdr_rcv,
343 .flags = INET6_PROTO_NOPOLICY, 343 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
344}; 344};
345 345
346void __init ipv6_rthdr_init(void) 346void __init ipv6_rthdr_init(void)
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 11536db225d7..5c950cc79d80 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -186,8 +186,6 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
186 } 186 }
187 187
188 ip6_dst_store(sk, dst, NULL); 188 ip6_dst_store(sk, dst, NULL);
189 sk->sk_route_caps = dst->dev->features &
190 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
191 } 189 }
192 190
193 skb->dst = dst_clone(dst); 191 skb->dst = dst_clone(dst);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index aceee252503d..df8f051c0fce 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -84,14 +84,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
84 */ 84 */
85 IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex; 85 IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex;
86 86
87 if (skb->len < sizeof(struct ipv6hdr)) 87 if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
88 goto err; 88 goto err;
89 89
90 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) {
91 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
92 goto drop;
93 }
94
95 hdr = skb->nh.ipv6h; 90 hdr = skb->nh.ipv6h;
96 91
97 if (hdr->version != 6) 92 if (hdr->version != 6)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index aa2b2c3e5076..2c5b44575af0 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -229,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
229 skb->priority = sk->sk_priority; 229 skb->priority = sk->sk_priority;
230 230
231 mtu = dst_mtu(dst); 231 mtu = dst_mtu(dst);
232 if ((skb->len <= mtu) || ipfragok) { 232 if ((skb->len <= mtu) || ipfragok || skb_shinfo(skb)->gso_size) {
233 IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 233 IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
234 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, 234 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
235 dst_output); 235 dst_output);
@@ -834,7 +834,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
834 /* specify the length of each IP datagram fragment*/ 834 /* specify the length of each IP datagram fragment*/
835 skb_shinfo(skb)->gso_size = mtu - fragheaderlen - 835 skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
836 sizeof(struct frag_hdr); 836 sizeof(struct frag_hdr);
837 skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; 837 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
838 ipv6_select_ident(skb, &fhdr); 838 ipv6_select_ident(skb, &fhdr);
839 skb_shinfo(skb)->ip6_frag_id = fhdr.identification; 839 skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
840 __skb_queue_tail(&sk->sk_write_queue, skb); 840 __skb_queue_tail(&sk->sk_write_queue, skb);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 97199d6ec79f..c28e5c287447 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -57,9 +57,71 @@
57 57
58DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; 58DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
59 59
60static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
61{
62 struct sk_buff *segs = ERR_PTR(-EINVAL);
63 struct ipv6hdr *ipv6h;
64 struct inet6_protocol *ops;
65 int proto;
66
67 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
68 goto out;
69
70 ipv6h = skb->nh.ipv6h;
71 proto = ipv6h->nexthdr;
72 __skb_pull(skb, sizeof(*ipv6h));
73
74 rcu_read_lock();
75 for (;;) {
76 struct ipv6_opt_hdr *opth;
77 int len;
78
79 if (proto != NEXTHDR_HOP) {
80 ops = rcu_dereference(inet6_protos[proto]);
81
82 if (unlikely(!ops))
83 goto unlock;
84
85 if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
86 break;
87 }
88
89 if (unlikely(!pskb_may_pull(skb, 8)))
90 goto unlock;
91
92 opth = (void *)skb->data;
93 len = opth->hdrlen * 8 + 8;
94
95 if (unlikely(!pskb_may_pull(skb, len)))
96 goto unlock;
97
98 proto = opth->nexthdr;
99 __skb_pull(skb, len);
100 }
101
102 skb->h.raw = skb->data;
103 if (likely(ops->gso_segment))
104 segs = ops->gso_segment(skb, features);
105
106unlock:
107 rcu_read_unlock();
108
109 if (unlikely(IS_ERR(segs)))
110 goto out;
111
112 for (skb = segs; skb; skb = skb->next) {
113 ipv6h = skb->nh.ipv6h;
114 ipv6h->payload_len = htons(skb->len - skb->mac_len);
115 }
116
117out:
118 return segs;
119}
120
60static struct packet_type ipv6_packet_type = { 121static struct packet_type ipv6_packet_type = {
61 .type = __constant_htons(ETH_P_IPV6), 122 .type = __constant_htons(ETH_P_IPV6),
62 .func = ipv6_rcv, 123 .func = ipv6_rcv,
124 .gso_segment = ipv6_gso_segment,
63}; 125};
64 126
65struct ip6_ra_chain *ip6_ra_chain; 127struct ip6_ra_chain *ip6_ra_chain;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 81dbc9c3bf04..5bdcb9002cf7 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -269,9 +269,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
269 ipv6_addr_copy(&np->saddr, saddr); 269 ipv6_addr_copy(&np->saddr, saddr);
270 inet->rcv_saddr = LOOPBACK4_IPV6; 270 inet->rcv_saddr = LOOPBACK4_IPV6;
271 271
272 sk->sk_gso_type = SKB_GSO_TCPV6;
272 ip6_dst_store(sk, dst, NULL); 273 ip6_dst_store(sk, dst, NULL);
273 sk->sk_route_caps = dst->dev->features &
274 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
275 274
276 icsk->icsk_ext_hdr_len = 0; 275 icsk->icsk_ext_hdr_len = 0;
277 if (np->opt) 276 if (np->opt)
@@ -929,9 +928,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
929 * comment in that function for the gory details. -acme 928 * comment in that function for the gory details. -acme
930 */ 929 */
931 930
931 sk->sk_gso_type = SKB_GSO_TCPV6;
932 ip6_dst_store(newsk, dst, NULL); 932 ip6_dst_store(newsk, dst, NULL);
933 newsk->sk_route_caps = dst->dev->features &
934 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
935 933
936 newtcp6sk = (struct tcp6_sock *)newsk; 934 newtcp6sk = (struct tcp6_sock *)newsk;
937 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; 935 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
@@ -1605,6 +1603,7 @@ struct proto tcpv6_prot = {
1605static struct inet6_protocol tcpv6_protocol = { 1603static struct inet6_protocol tcpv6_protocol = {
1606 .handler = tcp_v6_rcv, 1604 .handler = tcp_v6_rcv,
1607 .err_handler = tcp_v6_err, 1605 .err_handler = tcp_v6_err,
1606 .gso_segment = tcp_tso_segment,
1608 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 1607 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1609}; 1608};
1610 1609
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 0839b701b930..9bd8a7877fd5 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -261,7 +261,7 @@ static int do_basic_checks(struct nf_conn *conntrack,
261 } 261 }
262 262
263 DEBUGP("Basic checks passed\n"); 263 DEBUGP("Basic checks passed\n");
264 return 0; 264 return count == 0;
265} 265}
266 266
267static int new_state(enum ip_conntrack_dir dir, 267static int new_state(enum ip_conntrack_dir dir,