aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c62
1 files changed, 62 insertions, 0 deletions
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
59DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; 59DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
60 60
61static 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
107unlock:
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
118out:
119 return segs;
120}
121
61static struct packet_type ipv6_packet_type = { 122static 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
66struct ip6_ra_chain *ip6_ra_chain; 128struct ip6_ra_chain *ip6_ra_chain;