diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/af_inet6.c | 2 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 4 | ||||
-rw-r--r-- | net/ipv6/inet6_connection_sock.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 7 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 4 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 62 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 7 |
7 files changed, 70 insertions, 18 deletions
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 | ||
180 | static struct inet6_protocol destopt_protocol = { | 180 | static 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 | ||
185 | void __init ipv6_destopt_init(void) | 185 | void __init ipv6_destopt_init(void) |
@@ -340,7 +340,7 @@ looped_back: | |||
340 | 340 | ||
341 | static struct inet6_protocol rthdr_protocol = { | 341 | static 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 | ||
346 | void __init ipv6_rthdr_init(void) | 346 | void __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 | ||
58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | 58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; |
59 | 59 | ||
60 | static 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 | |||
106 | unlock: | ||
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 | |||
117 | out: | ||
118 | return segs; | ||
119 | } | ||
120 | |||
60 | static struct packet_type ipv6_packet_type = { | 121 | static 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 | ||
65 | struct ip6_ra_chain *ip6_ra_chain; | 127 | struct 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 = { | |||
1605 | static struct inet6_protocol tcpv6_protocol = { | 1603 | static 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 | ||