diff options
-rw-r--r-- | include/net/protocol.h | 6 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 1 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 4 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 62 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 1 |
5 files changed, 72 insertions, 2 deletions
diff --git a/include/net/protocol.h b/include/net/protocol.h index 40b6b9c9973f..a225d6371cb1 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h | |||
@@ -50,11 +50,17 @@ struct inet6_protocol | |||
50 | struct inet6_skb_parm *opt, | 50 | struct inet6_skb_parm *opt, |
51 | int type, int code, int offset, | 51 | int type, int code, int offset, |
52 | __u32 info); | 52 | __u32 info); |
53 | |||
54 | struct sk_buff *(*gso_segment)(struct sk_buff *skb, | ||
55 | int features); | ||
56 | |||
53 | unsigned int flags; /* INET6_PROTO_xxx */ | 57 | unsigned int flags; /* INET6_PROTO_xxx */ |
54 | }; | 58 | }; |
55 | 59 | ||
56 | #define INET6_PROTO_NOPOLICY 0x1 | 60 | #define INET6_PROTO_NOPOLICY 0x1 |
57 | #define INET6_PROTO_FINAL 0x2 | 61 | #define INET6_PROTO_FINAL 0x2 |
62 | /* This should be set for any extension header which is compatible with GSO. */ | ||
63 | #define INET6_PROTO_GSO_EXTHDR 0x4 | ||
58 | #endif | 64 | #endif |
59 | 65 | ||
60 | /* This is used to register socket interfaces for IP protocols. */ | 66 | /* This is used to register socket interfaces for IP protocols. */ |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0bb0ac96d675..b7cf26e0e5c2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2215,6 +2215,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2215 | out: | 2215 | out: |
2216 | return segs; | 2216 | return segs; |
2217 | } | 2217 | } |
2218 | EXPORT_SYMBOL(tcp_tso_segment); | ||
2218 | 2219 | ||
2219 | extern void __skb_cb_too_small_for_tcp(int, int); | 2220 | extern void __skb_cb_too_small_for_tcp(int, int); |
2220 | extern struct tcp_congestion_ops tcp_reno; | 2221 | extern struct tcp_congestion_ops tcp_reno; |
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/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4c20eeb3d568..25f8bf8ac49b 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -58,9 +58,71 @@ | |||
58 | 58 | ||
59 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | 59 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; |
60 | 60 | ||
61 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | ||
62 | { | ||
63 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
64 | struct ipv6hdr *ipv6h; | ||
65 | struct inet6_protocol *ops; | ||
66 | int proto; | ||
67 | |||
68 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
69 | goto out; | ||
70 | |||
71 | ipv6h = skb->nh.ipv6h; | ||
72 | proto = ipv6h->nexthdr; | ||
73 | __skb_pull(skb, sizeof(*ipv6h)); | ||
74 | |||
75 | rcu_read_lock(); | ||
76 | for (;;) { | ||
77 | struct ipv6_opt_hdr *opth; | ||
78 | int len; | ||
79 | |||
80 | if (proto != NEXTHDR_HOP) { | ||
81 | ops = rcu_dereference(inet6_protos[proto]); | ||
82 | |||
83 | if (unlikely(!ops)) | ||
84 | goto unlock; | ||
85 | |||
86 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
91 | goto unlock; | ||
92 | |||
93 | opth = (void *)skb->data; | ||
94 | len = opth->hdrlen * 8 + 8; | ||
95 | |||
96 | if (unlikely(!pskb_may_pull(skb, len))) | ||
97 | goto unlock; | ||
98 | |||
99 | proto = opth->nexthdr; | ||
100 | __skb_pull(skb, len); | ||
101 | } | ||
102 | |||
103 | skb->h.raw = skb->data; | ||
104 | if (likely(ops->gso_segment)) | ||
105 | segs = ops->gso_segment(skb, features); | ||
106 | |||
107 | unlock: | ||
108 | rcu_read_unlock(); | ||
109 | |||
110 | if (unlikely(IS_ERR(segs))) | ||
111 | goto out; | ||
112 | |||
113 | for (skb = segs; skb; skb = skb->next) { | ||
114 | ipv6h = skb->nh.ipv6h; | ||
115 | ipv6h->payload_len = htons(skb->len - skb->mac_len); | ||
116 | } | ||
117 | |||
118 | out: | ||
119 | return segs; | ||
120 | } | ||
121 | |||
61 | static struct packet_type ipv6_packet_type = { | 122 | static struct packet_type ipv6_packet_type = { |
62 | .type = __constant_htons(ETH_P_IPV6), | 123 | .type = __constant_htons(ETH_P_IPV6), |
63 | .func = ipv6_rcv, | 124 | .func = ipv6_rcv, |
125 | .gso_segment = ipv6_gso_segment, | ||
64 | }; | 126 | }; |
65 | 127 | ||
66 | struct ip6_ra_chain *ip6_ra_chain; | 128 | struct ip6_ra_chain *ip6_ra_chain; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b36d5b2e7c30..bf7f8c26c488 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1606,6 +1606,7 @@ struct proto tcpv6_prot = { | |||
1606 | static struct inet6_protocol tcpv6_protocol = { | 1606 | static struct inet6_protocol tcpv6_protocol = { |
1607 | .handler = tcp_v6_rcv, | 1607 | .handler = tcp_v6_rcv, |
1608 | .err_handler = tcp_v6_err, | 1608 | .err_handler = tcp_v6_err, |
1609 | .gso_segment = tcp_tso_segment, | ||
1609 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 1610 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
1610 | }; | 1611 | }; |
1611 | 1612 | ||