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 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;