diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-03 13:49:45 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-03 13:49:45 -0400 |
| commit | 026477c1141b67e98e3bd8bdedb7d4b88a3ecd09 (patch) | |
| tree | 2624a44924c625c367f3cebf937853b9da2de282 /net/ipv6/ipv6_sockglue.c | |
| parent | 9f2fa466383ce100b90fe52cb4489d7a26bf72a9 (diff) | |
| parent | 29454dde27d8e340bb1987bad9aa504af7081eba (diff) | |
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4c20eeb3d568..c28e5c287447 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/capability.h> | 29 | #include <linux/capability.h> |
| 30 | #include <linux/config.h> | ||
| 31 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 32 | #include <linux/types.h> | 31 | #include <linux/types.h> |
| 33 | #include <linux/socket.h> | 32 | #include <linux/socket.h> |
| @@ -58,9 +57,71 @@ | |||
| 58 | 57 | ||
| 59 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | 58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; |
| 60 | 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 | |||
| 61 | static struct packet_type ipv6_packet_type = { | 121 | static struct packet_type ipv6_packet_type = { |
| 62 | .type = __constant_htons(ETH_P_IPV6), | 122 | .type = __constant_htons(ETH_P_IPV6), |
| 63 | .func = ipv6_rcv, | 123 | .func = ipv6_rcv, |
| 124 | .gso_segment = ipv6_gso_segment, | ||
| 64 | }; | 125 | }; |
| 65 | 126 | ||
| 66 | struct ip6_ra_chain *ip6_ra_chain; | 127 | struct ip6_ra_chain *ip6_ra_chain; |
