Loading include/net/protocol.h +6 −0 Original line number Diff line number Diff line Loading @@ -50,11 +50,17 @@ struct inet6_protocol struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); unsigned int flags; /* INET6_PROTO_xxx */ }; #define INET6_PROTO_NOPOLICY 0x1 #define INET6_PROTO_FINAL 0x2 /* This should be set for any extension header which is compatible with GSO. */ #define INET6_PROTO_GSO_EXTHDR 0x4 #endif /* This is used to register socket interfaces for IP protocols. */ Loading net/ipv4/tcp.c +1 −0 Original line number Diff line number Diff line Loading @@ -2215,6 +2215,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) out: return segs; } EXPORT_SYMBOL(tcp_tso_segment); extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; Loading net/ipv6/exthdrs.c +2 −2 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) static struct inet6_protocol destopt_protocol = { .handler = ipv6_destopt_rcv, .flags = INET6_PROTO_NOPOLICY, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; void __init ipv6_destopt_init(void) Loading Loading @@ -340,7 +340,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) static struct inet6_protocol rthdr_protocol = { .handler = ipv6_rthdr_rcv, .flags = INET6_PROTO_NOPOLICY, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; void __init ipv6_rthdr_init(void) Loading net/ipv6/ipv6_sockglue.c +62 −0 Original line number Diff line number Diff line Loading @@ -58,9 +58,71 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct ipv6hdr *ipv6h; struct inet6_protocol *ops; int proto; if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) goto out; ipv6h = skb->nh.ipv6h; proto = ipv6h->nexthdr; __skb_pull(skb, sizeof(*ipv6h)); rcu_read_lock(); for (;;) { struct ipv6_opt_hdr *opth; int len; if (proto != NEXTHDR_HOP) { ops = rcu_dereference(inet6_protos[proto]); if (unlikely(!ops)) goto unlock; if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) break; } if (unlikely(!pskb_may_pull(skb, 8))) goto unlock; opth = (void *)skb->data; len = opth->hdrlen * 8 + 8; if (unlikely(!pskb_may_pull(skb, len))) goto unlock; proto = opth->nexthdr; __skb_pull(skb, len); } skb->h.raw = skb->data; if (likely(ops->gso_segment)) segs = ops->gso_segment(skb, features); unlock: rcu_read_unlock(); if (unlikely(IS_ERR(segs))) goto out; for (skb = segs; skb; skb = skb->next) { ipv6h = skb->nh.ipv6h; ipv6h->payload_len = htons(skb->len - skb->mac_len); } out: return segs; } static struct packet_type ipv6_packet_type = { .type = __constant_htons(ETH_P_IPV6), .func = ipv6_rcv, .gso_segment = ipv6_gso_segment, }; struct ip6_ra_chain *ip6_ra_chain; Loading net/ipv6/tcp_ipv6.c +1 −0 Original line number Diff line number Diff line Loading @@ -1606,6 +1606,7 @@ struct proto tcpv6_prot = { static struct inet6_protocol tcpv6_protocol = { .handler = tcp_v6_rcv, .err_handler = tcp_v6_err, .gso_segment = tcp_tso_segment, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; Loading Loading
include/net/protocol.h +6 −0 Original line number Diff line number Diff line Loading @@ -50,11 +50,17 @@ struct inet6_protocol struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); unsigned int flags; /* INET6_PROTO_xxx */ }; #define INET6_PROTO_NOPOLICY 0x1 #define INET6_PROTO_FINAL 0x2 /* This should be set for any extension header which is compatible with GSO. */ #define INET6_PROTO_GSO_EXTHDR 0x4 #endif /* This is used to register socket interfaces for IP protocols. */ Loading
net/ipv4/tcp.c +1 −0 Original line number Diff line number Diff line Loading @@ -2215,6 +2215,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) out: return segs; } EXPORT_SYMBOL(tcp_tso_segment); extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; Loading
net/ipv6/exthdrs.c +2 −2 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) static struct inet6_protocol destopt_protocol = { .handler = ipv6_destopt_rcv, .flags = INET6_PROTO_NOPOLICY, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; void __init ipv6_destopt_init(void) Loading Loading @@ -340,7 +340,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) static struct inet6_protocol rthdr_protocol = { .handler = ipv6_rthdr_rcv, .flags = INET6_PROTO_NOPOLICY, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; void __init ipv6_rthdr_init(void) Loading
net/ipv6/ipv6_sockglue.c +62 −0 Original line number Diff line number Diff line Loading @@ -58,9 +58,71 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct ipv6hdr *ipv6h; struct inet6_protocol *ops; int proto; if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) goto out; ipv6h = skb->nh.ipv6h; proto = ipv6h->nexthdr; __skb_pull(skb, sizeof(*ipv6h)); rcu_read_lock(); for (;;) { struct ipv6_opt_hdr *opth; int len; if (proto != NEXTHDR_HOP) { ops = rcu_dereference(inet6_protos[proto]); if (unlikely(!ops)) goto unlock; if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) break; } if (unlikely(!pskb_may_pull(skb, 8))) goto unlock; opth = (void *)skb->data; len = opth->hdrlen * 8 + 8; if (unlikely(!pskb_may_pull(skb, len))) goto unlock; proto = opth->nexthdr; __skb_pull(skb, len); } skb->h.raw = skb->data; if (likely(ops->gso_segment)) segs = ops->gso_segment(skb, features); unlock: rcu_read_unlock(); if (unlikely(IS_ERR(segs))) goto out; for (skb = segs; skb; skb = skb->next) { ipv6h = skb->nh.ipv6h; ipv6h->payload_len = htons(skb->len - skb->mac_len); } out: return segs; } static struct packet_type ipv6_packet_type = { .type = __constant_htons(ETH_P_IPV6), .func = ipv6_rcv, .gso_segment = ipv6_gso_segment, }; struct ip6_ra_chain *ip6_ra_chain; Loading
net/ipv6/tcp_ipv6.c +1 −0 Original line number Diff line number Diff line Loading @@ -1606,6 +1606,7 @@ struct proto tcpv6_prot = { static struct inet6_protocol tcpv6_protocol = { .handler = tcp_v6_rcv, .err_handler = tcp_v6_err, .gso_segment = tcp_tso_segment, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; Loading