aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig20
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c28
-rw-r--r--net/ipv6/ah6.c10
-rw-r--r--net/ipv6/esp6.c20
-rw-r--r--net/ipv6/ip6_output.c3
-rw-r--r--net/ipv6/ipcomp6.c38
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c10
-rw-r--r--net/ipv6/tcp_ipv6.c12
-rw-r--r--net/ipv6/xfrm6_input.c29
-rw-r--r--net/ipv6/xfrm6_mode_transport.c88
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c121
-rw-r--r--net/ipv6/xfrm6_output.c63
-rw-r--r--net/ipv6/xfrm6_policy.c6
-rw-r--r--net/ipv6/xfrm6_state.c1
17 files changed, 294 insertions, 161 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index f8a107ab5592..e923d4dea418 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -106,6 +106,26 @@ config INET6_TUNNEL
106 tristate 106 tristate
107 default n 107 default n
108 108
109config INET6_XFRM_MODE_TRANSPORT
110 tristate "IPv6: IPsec transport mode"
111 depends on IPV6
112 default IPV6
113 select XFRM
114 ---help---
115 Support for IPsec transport mode.
116
117 If unsure, say Y.
118
119config INET6_XFRM_MODE_TUNNEL
120 tristate "IPv6: IPsec tunnel mode"
121 depends on IPV6
122 default IPV6
123 select XFRM
124 ---help---
125 Support for IPsec tunnel mode.
126
127 If unsure, say Y.
128
109config IPV6_TUNNEL 129config IPV6_TUNNEL
110 tristate "IPv6: IPv6-in-IPv6 tunnel" 130 tristate "IPv6: IPv6-in-IPv6 tunnel"
111 select INET6_TUNNEL 131 select INET6_TUNNEL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index a760b0988fbb..386e0a626948 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_INET6_ESP) += esp6.o
20obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o 20obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
21obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o 21obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
22obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o 22obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
23obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
24obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
23obj-$(CONFIG_NETFILTER) += netfilter/ 25obj-$(CONFIG_NETFILTER) += netfilter/
24 26
25obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 27obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 445006ee4522..c2c26fa0943d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2860,6 +2860,11 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2860 return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); 2860 return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
2861} 2861}
2862 2862
2863/* Maximum length of ifa_cacheinfo attributes */
2864#define INET6_IFADDR_RTA_SPACE \
2865 RTA_SPACE(16) /* IFA_ADDRESS */ + \
2866 RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */
2867
2863static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, 2868static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
2864 u32 pid, u32 seq, int event, unsigned int flags) 2869 u32 pid, u32 seq, int event, unsigned int flags)
2865{ 2870{
@@ -3092,7 +3097,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
3092static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) 3097static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
3093{ 3098{
3094 struct sk_buff *skb; 3099 struct sk_buff *skb;
3095 int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128); 3100 int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
3096 3101
3097 skb = alloc_skb(size, GFP_ATOMIC); 3102 skb = alloc_skb(size, GFP_ATOMIC);
3098 if (!skb) { 3103 if (!skb) {
@@ -3142,6 +3147,17 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
3142#endif 3147#endif
3143} 3148}
3144 3149
3150/* Maximum length of ifinfomsg attributes */
3151#define INET6_IFINFO_RTA_SPACE \
3152 RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \
3153 RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \
3154 RTA_SPACE(sizeof(u32)) /* MTU */ + \
3155 RTA_SPACE(sizeof(int)) /* LINK */ + \
3156 RTA_SPACE(0) /* PROTINFO */ + \
3157 RTA_SPACE(sizeof(u32)) /* FLAGS */ + \
3158 RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \
3159 RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */
3160
3145static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3161static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
3146 u32 pid, u32 seq, int event, unsigned int flags) 3162 u32 pid, u32 seq, int event, unsigned int flags)
3147{ 3163{
@@ -3235,8 +3251,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
3235void inet6_ifinfo_notify(int event, struct inet6_dev *idev) 3251void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
3236{ 3252{
3237 struct sk_buff *skb; 3253 struct sk_buff *skb;
3238 /* 128 bytes ?? */ 3254 int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE);
3239 int size = NLMSG_SPACE(sizeof(struct ifinfomsg)+128);
3240 3255
3241 skb = alloc_skb(size, GFP_ATOMIC); 3256 skb = alloc_skb(size, GFP_ATOMIC);
3242 if (!skb) { 3257 if (!skb) {
@@ -3252,6 +3267,11 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
3252 netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); 3267 netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC);
3253} 3268}
3254 3269
3270/* Maximum length of prefix_cacheinfo attributes */
3271#define INET6_PREFIX_RTA_SPACE \
3272 RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \
3273 RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */
3274
3255static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, 3275static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
3256 struct prefix_info *pinfo, u32 pid, u32 seq, 3276 struct prefix_info *pinfo, u32 pid, u32 seq,
3257 int event, unsigned int flags) 3277 int event, unsigned int flags)
@@ -3296,7 +3316,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
3296 struct prefix_info *pinfo) 3316 struct prefix_info *pinfo)
3297{ 3317{
3298 struct sk_buff *skb; 3318 struct sk_buff *skb;
3299 int size = NLMSG_SPACE(sizeof(struct prefixmsg)+128); 3319 int size = NLMSG_SPACE(sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE);
3300 3320
3301 skb = alloc_skb(size, GFP_ATOMIC); 3321 skb = alloc_skb(size, GFP_ATOMIC);
3302 if (!skb) { 3322 if (!skb) {
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 6778173a3dda..d31c0d6c0448 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -292,7 +292,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
292 292
293 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 293 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
294 memset(ah->auth_data, 0, ahp->icv_trunc_len); 294 memset(ah->auth_data, 0, ahp->icv_trunc_len);
295 skb_push(skb, skb->data - skb->nh.raw); 295 skb_push(skb, hdr_len);
296 ahp->icv(ahp, skb, ah->auth_data); 296 ahp->icv(ahp, skb, ah->auth_data);
297 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { 297 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
298 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 298 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
@@ -301,12 +301,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
301 } 301 }
302 } 302 }
303 303
304 skb->nh.raw = skb_pull(skb, ah_hlen); 304 skb->h.raw = memcpy(skb->nh.raw += ah_hlen, tmp_hdr, hdr_len);
305 memcpy(skb->nh.raw, tmp_hdr, hdr_len); 305 __skb_pull(skb, ah_hlen + hdr_len);
306 skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
307 skb_pull(skb, hdr_len);
308 skb->h.raw = skb->data;
309
310 306
311 kfree(tmp_hdr); 307 kfree(tmp_hdr);
312 308
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 22f046079037..a15a6f320f70 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -142,25 +142,17 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
142 142
143 int hdr_len = skb->h.raw - skb->nh.raw; 143 int hdr_len = skb->h.raw - skb->nh.raw;
144 int nfrags; 144 int nfrags;
145 unsigned char *tmp_hdr = NULL;
146 int ret = 0; 145 int ret = 0;
147 146
148 if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) { 147 if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) {
149 ret = -EINVAL; 148 ret = -EINVAL;
150 goto out_nofree; 149 goto out;
151 } 150 }
152 151
153 if (elen <= 0 || (elen & (blksize-1))) { 152 if (elen <= 0 || (elen & (blksize-1))) {
154 ret = -EINVAL; 153 ret = -EINVAL;
155 goto out_nofree; 154 goto out;
156 }
157
158 tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
159 if (!tmp_hdr) {
160 ret = -ENOMEM;
161 goto out_nofree;
162 } 155 }
163 memcpy(tmp_hdr, skb->nh.raw, hdr_len);
164 156
165 /* If integrity check is required, do this. */ 157 /* If integrity check is required, do this. */
166 if (esp->auth.icv_full_len) { 158 if (esp->auth.icv_full_len) {
@@ -222,16 +214,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
222 /* ... check padding bits here. Silly. :-) */ 214 /* ... check padding bits here. Silly. :-) */
223 215
224 pskb_trim(skb, skb->len - alen - padlen - 2); 216 pskb_trim(skb, skb->len - alen - padlen - 2);
225 skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen);
226 skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen;
227 memcpy(skb->nh.raw, tmp_hdr, hdr_len);
228 skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
229 ret = nexthdr[1]; 217 ret = nexthdr[1];
230 } 218 }
231 219
220 skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - hdr_len;
221
232out: 222out:
233 kfree(tmp_hdr);
234out_nofree:
235 return ret; 223 return ret;
236} 224}
237 225
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e46048974f37..d29620f4910e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -39,6 +39,7 @@
39#include <linux/in6.h> 39#include <linux/in6.h>
40#include <linux/tcp.h> 40#include <linux/tcp.h>
41#include <linux/route.h> 41#include <linux/route.h>
42#include <linux/module.h>
42 43
43#include <linux/netfilter.h> 44#include <linux/netfilter.h>
44#include <linux/netfilter_ipv6.h> 45#include <linux/netfilter_ipv6.h>
@@ -458,6 +459,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
458 nf_bridge_get(to->nf_bridge); 459 nf_bridge_get(to->nf_bridge);
459#endif 460#endif
460#endif 461#endif
462 skb_copy_secmark(to, from);
461} 463}
462 464
463int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) 465int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
@@ -488,6 +490,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
488 490
489 return offset; 491 return offset;
490} 492}
493EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
491 494
492static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 495static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
493{ 496{
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 48636436028a..f28cd37feed3 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -65,38 +65,25 @@ static LIST_HEAD(ipcomp6_tfms_list);
65 65
66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) 66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
67{ 67{
68 int err = 0; 68 int err = -ENOMEM;
69 u8 nexthdr = 0;
70 int hdr_len = skb->h.raw - skb->nh.raw;
71 unsigned char *tmp_hdr = NULL;
72 struct ipv6hdr *iph; 69 struct ipv6hdr *iph;
70 struct ipv6_comp_hdr *ipch;
73 int plen, dlen; 71 int plen, dlen;
74 struct ipcomp_data *ipcd = x->data; 72 struct ipcomp_data *ipcd = x->data;
75 u8 *start, *scratch; 73 u8 *start, *scratch;
76 struct crypto_tfm *tfm; 74 struct crypto_tfm *tfm;
77 int cpu; 75 int cpu;
78 76
79 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 77 if (skb_linearize_cow(skb))
80 skb_linearize(skb, GFP_ATOMIC) != 0) {
81 err = -ENOMEM;
82 goto out; 78 goto out;
83 }
84 79
85 skb->ip_summed = CHECKSUM_NONE; 80 skb->ip_summed = CHECKSUM_NONE;
86 81
87 /* Remove ipcomp header and decompress original payload */ 82 /* Remove ipcomp header and decompress original payload */
88 iph = skb->nh.ipv6h; 83 iph = skb->nh.ipv6h;
89 tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC); 84 ipch = (void *)skb->data;
90 if (!tmp_hdr) 85 skb->h.raw = skb->nh.raw + sizeof(*ipch);
91 goto out; 86 __skb_pull(skb, sizeof(*ipch));
92 memcpy(tmp_hdr, iph, hdr_len);
93 nexthdr = *(u8 *)skb->data;
94 skb_pull(skb, sizeof(struct ipv6_comp_hdr));
95 skb->nh.raw += sizeof(struct ipv6_comp_hdr);
96 memcpy(skb->nh.raw, tmp_hdr, hdr_len);
97 iph = skb->nh.ipv6h;
98 iph->payload_len = htons(ntohs(iph->payload_len) - sizeof(struct ipv6_comp_hdr));
99 skb->h.raw = skb->data;
100 87
101 /* decompression */ 88 /* decompression */
102 plen = skb->len; 89 plen = skb->len;
@@ -125,18 +112,11 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
125 112
126 skb_put(skb, dlen - plen); 113 skb_put(skb, dlen - plen);
127 memcpy(skb->data, scratch, dlen); 114 memcpy(skb->data, scratch, dlen);
115 err = ipch->nexthdr;
128 116
129 iph = skb->nh.ipv6h;
130 iph->payload_len = htons(skb->len);
131
132out_put_cpu: 117out_put_cpu:
133 put_cpu(); 118 put_cpu();
134out: 119out:
135 kfree(tmp_hdr);
136 if (err)
137 goto error_out;
138 return nexthdr;
139error_out:
140 return err; 120 return err;
141} 121}
142 122
@@ -159,10 +139,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
159 goto out_ok; 139 goto out_ok;
160 } 140 }
161 141
162 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 142 if (skb_linearize_cow(skb))
163 skb_linearize(skb, GFP_ATOMIC) != 0) {
164 goto out_ok; 143 goto out_ok;
165 }
166 144
167 /* compression */ 145 /* compression */
168 plen = skb->len - hdr_len; 146 plen = skb->len - hdr_len;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 93bae36f2663..2a71c3b669f1 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -189,7 +189,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
189 189
190 /* This is where we call the helper: as the packet goes out. */ 190 /* This is where we call the helper: as the packet goes out. */
191 ct = nf_ct_get(*pskb, &ctinfo); 191 ct = nf_ct_get(*pskb, &ctinfo);
192 if (!ct) 192 if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
193 goto out; 193 goto out;
194 194
195 help = nfct_help(ct); 195 help = nfct_help(ct);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 86c6703265d0..ef18a7b7014b 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -233,7 +233,7 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
233 return -NF_ACCEPT; 233 return -NF_ACCEPT;
234 } 234 }
235 235
236 if (hooknum == NF_IP6_PRE_ROUTING && 236 if (nf_conntrack_checksum && hooknum == NF_IP6_PRE_ROUTING &&
237 nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { 237 nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
238 nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, 238 nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
239 "nf_ct_icmpv6: ICMPv6 checksum failed\n"); 239 "nf_ct_icmpv6: ICMPv6 checksum failed\n");
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 3e319035f82d..c32a029e43f0 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -456,13 +456,9 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
456 DEBUGP("queue: message is too short.\n"); 456 DEBUGP("queue: message is too short.\n");
457 goto err; 457 goto err;
458 } 458 }
459 if (end-offset < skb->len) { 459 if (pskb_trim_rcsum(skb, end - offset)) {
460 if (pskb_trim(skb, end - offset)) { 460 DEBUGP("Can't trim\n");
461 DEBUGP("Can't trim\n"); 461 goto err;
462 goto err;
463 }
464 if (skb->ip_summed != CHECKSUM_UNNECESSARY)
465 skb->ip_summed = CHECKSUM_NONE;
466 } 462 }
467 463
468 /* Find out which fragments are in front and at the back of us 464 /* Find out which fragments are in front and at the back of us
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 301eee726b0f..a50eb306e9e2 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1218,8 +1218,16 @@ process:
1218 bh_lock_sock(sk); 1218 bh_lock_sock(sk);
1219 ret = 0; 1219 ret = 0;
1220 if (!sock_owned_by_user(sk)) { 1220 if (!sock_owned_by_user(sk)) {
1221 if (!tcp_prequeue(sk, skb)) 1221#ifdef CONFIG_NET_DMA
1222 ret = tcp_v6_do_rcv(sk, skb); 1222 struct tcp_sock *tp = tcp_sk(sk);
1223 if (tp->ucopy.dma_chan)
1224 ret = tcp_v6_do_rcv(sk, skb);
1225 else
1226#endif
1227 {
1228 if (!tcp_prequeue(sk, skb))
1229 ret = tcp_v6_do_rcv(sk, skb);
1230 }
1223 } else 1231 } else
1224 sk_add_backlog(sk, skb); 1232 sk_add_backlog(sk, skb);
1225 bh_unlock_sock(sk); 1233 bh_unlock_sock(sk);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 00cfdee18dca..0405d74ff910 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -13,21 +13,9 @@
13#include <linux/string.h> 13#include <linux/string.h>
14#include <linux/netfilter.h> 14#include <linux/netfilter.h>
15#include <linux/netfilter_ipv6.h> 15#include <linux/netfilter_ipv6.h>
16#include <net/dsfield.h>
17#include <net/inet_ecn.h>
18#include <net/ip.h>
19#include <net/ipv6.h> 16#include <net/ipv6.h>
20#include <net/xfrm.h> 17#include <net/xfrm.h>
21 18
22static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
23{
24 struct ipv6hdr *outer_iph = skb->nh.ipv6h;
25 struct ipv6hdr *inner_iph = skb->h.ipv6h;
26
27 if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
28 IP6_ECN_set_ce(inner_iph);
29}
30
31int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) 19int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
32{ 20{
33 int err; 21 int err;
@@ -81,21 +69,10 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
81 69
82 xfrm_vec[xfrm_nr++] = x; 70 xfrm_vec[xfrm_nr++] = x;
83 71
72 if (x->mode->input(x, skb))
73 goto drop;
74
84 if (x->props.mode) { /* XXX */ 75 if (x->props.mode) { /* XXX */
85 if (nexthdr != IPPROTO_IPV6)
86 goto drop;
87 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
88 goto drop;
89 if (skb_cloned(skb) &&
90 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
91 goto drop;
92 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
93 ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
94 if (!(x->props.flags & XFRM_STATE_NOECN))
95 ipip6_ecn_decapsulate(skb);
96 skb->mac.raw = memmove(skb->data - skb->mac_len,
97 skb->mac.raw, skb->mac_len);
98 skb->nh.raw = skb->data;
99 decaps = 1; 76 decaps = 1;
100 break; 77 break;
101 } 78 }
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
new file mode 100644
index 000000000000..711d713e36d8
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_transport.c
@@ -0,0 +1,88 @@
1/*
2 * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6.
3 *
4 * Copyright (C) 2002 USAGI/WIDE Project
5 * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/skbuff.h>
12#include <linux/stringify.h>
13#include <net/dst.h>
14#include <net/ipv6.h>
15#include <net/xfrm.h>
16
17/* Add encapsulation header.
18 *
19 * The IP header and mutable extension headers will be moved forward to make
20 * space for the encapsulation header.
21 *
22 * On exit, skb->h will be set to the start of the encapsulation header to be
23 * filled in by x->type->output and skb->nh will be set to the nextheader field
24 * of the extension header directly preceding the encapsulation header, or in
25 * its absence, that of the top IP header. The value of skb->data will always
26 * point to the top IP header.
27 */
28static int xfrm6_transport_output(struct sk_buff *skb)
29{
30 struct xfrm_state *x = skb->dst->xfrm;
31 struct ipv6hdr *iph;
32 u8 *prevhdr;
33 int hdr_len;
34
35 skb_push(skb, x->props.header_len);
36 iph = skb->nh.ipv6h;
37
38 hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
39 skb->nh.raw = prevhdr - x->props.header_len;
40 skb->h.raw = skb->data + hdr_len;
41 memmove(skb->data, iph, hdr_len);
42 return 0;
43}
44
45/* Remove encapsulation header.
46 *
47 * The IP header will be moved over the top of the encapsulation header.
48 *
49 * On entry, skb->h shall point to where the IP header should be and skb->nh
50 * shall be set to where the IP header currently is. skb->data shall point
51 * to the start of the payload.
52 */
53static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
54{
55 int ihl = skb->data - skb->h.raw;
56
57 if (skb->h.raw != skb->nh.raw)
58 skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);
59 skb->nh.ipv6h->payload_len = htons(skb->len + ihl -
60 sizeof(struct ipv6hdr));
61 skb->h.raw = skb->data;
62 return 0;
63}
64
65static struct xfrm_mode xfrm6_transport_mode = {
66 .input = xfrm6_transport_input,
67 .output = xfrm6_transport_output,
68 .owner = THIS_MODULE,
69 .encap = XFRM_MODE_TRANSPORT,
70};
71
72static int __init xfrm6_transport_init(void)
73{
74 return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6);
75}
76
77static void __exit xfrm6_transport_exit(void)
78{
79 int err;
80
81 err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6);
82 BUG_ON(err);
83}
84
85module_init(xfrm6_transport_init);
86module_exit(xfrm6_transport_exit);
87MODULE_LICENSE("GPL");
88MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT);
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
new file mode 100644
index 000000000000..8af79be2edca
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -0,0 +1,121 @@
1/*
2 * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6.
3 *
4 * Copyright (C) 2002 USAGI/WIDE Project
5 * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/skbuff.h>
12#include <linux/stringify.h>
13#include <net/dsfield.h>
14#include <net/dst.h>
15#include <net/inet_ecn.h>
16#include <net/ipv6.h>
17#include <net/xfrm.h>
18
19static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
20{
21 struct ipv6hdr *outer_iph = skb->nh.ipv6h;
22 struct ipv6hdr *inner_iph = skb->h.ipv6h;
23
24 if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
25 IP6_ECN_set_ce(inner_iph);
26}
27
28/* Add encapsulation header.
29 *
30 * The top IP header will be constructed per RFC 2401. The following fields
31 * in it shall be filled in by x->type->output:
32 * payload_len
33 *
34 * On exit, skb->h will be set to the start of the encapsulation header to be
35 * filled in by x->type->output and skb->nh will be set to the nextheader field
36 * of the extension header directly preceding the encapsulation header, or in
37 * its absence, that of the top IP header. The value of skb->data will always
38 * point to the top IP header.
39 */
40static int xfrm6_tunnel_output(struct sk_buff *skb)
41{
42 struct dst_entry *dst = skb->dst;
43 struct xfrm_state *x = dst->xfrm;
44 struct ipv6hdr *iph, *top_iph;
45 int dsfield;
46
47 skb_push(skb, x->props.header_len);
48 iph = skb->nh.ipv6h;
49
50 skb->nh.raw = skb->data;
51 top_iph = skb->nh.ipv6h;
52 skb->nh.raw = &top_iph->nexthdr;
53 skb->h.ipv6h = top_iph + 1;
54
55 top_iph->version = 6;
56 top_iph->priority = iph->priority;
57 top_iph->flow_lbl[0] = iph->flow_lbl[0];
58 top_iph->flow_lbl[1] = iph->flow_lbl[1];
59 top_iph->flow_lbl[2] = iph->flow_lbl[2];
60 dsfield = ipv6_get_dsfield(top_iph);
61 dsfield = INET_ECN_encapsulate(dsfield, dsfield);
62 if (x->props.flags & XFRM_STATE_NOECN)
63 dsfield &= ~INET_ECN_MASK;
64 ipv6_change_dsfield(top_iph, 0, dsfield);
65 top_iph->nexthdr = IPPROTO_IPV6;
66 top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
67 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
68 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
69 return 0;
70}
71
72static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
73{
74 int err = -EINVAL;
75
76 if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6)
77 goto out;
78 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
79 goto out;
80
81 if (skb_cloned(skb) &&
82 (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
83 goto out;
84
85 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
86 ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
87 if (!(x->props.flags & XFRM_STATE_NOECN))
88 ipip6_ecn_decapsulate(skb);
89 skb->mac.raw = memmove(skb->data - skb->mac_len,
90 skb->mac.raw, skb->mac_len);
91 skb->nh.raw = skb->data;
92 err = 0;
93
94out:
95 return err;
96}
97
98static struct xfrm_mode xfrm6_tunnel_mode = {
99 .input = xfrm6_tunnel_input,
100 .output = xfrm6_tunnel_output,
101 .owner = THIS_MODULE,
102 .encap = XFRM_MODE_TUNNEL,
103};
104
105static int __init xfrm6_tunnel_init(void)
106{
107 return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
108}
109
110static void __exit xfrm6_tunnel_exit(void)
111{
112 int err;
113
114 err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6);
115 BUG_ON(err);
116}
117
118module_init(xfrm6_tunnel_init);
119module_exit(xfrm6_tunnel_exit);
120MODULE_LICENSE("GPL");
121MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 80242172a5df..16e84254a252 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -14,68 +14,9 @@
14#include <linux/spinlock.h> 14#include <linux/spinlock.h>
15#include <linux/icmpv6.h> 15#include <linux/icmpv6.h>
16#include <linux/netfilter_ipv6.h> 16#include <linux/netfilter_ipv6.h>
17#include <net/dsfield.h>
18#include <net/inet_ecn.h>
19#include <net/ipv6.h> 17#include <net/ipv6.h>
20#include <net/xfrm.h> 18#include <net/xfrm.h>
21 19
22/* Add encapsulation header.
23 *
24 * In transport mode, the IP header and mutable extension headers will be moved
25 * forward to make space for the encapsulation header.
26 *
27 * In tunnel mode, the top IP header will be constructed per RFC 2401.
28 * The following fields in it shall be filled in by x->type->output:
29 * payload_len
30 *
31 * On exit, skb->h will be set to the start of the encapsulation header to be
32 * filled in by x->type->output and skb->nh will be set to the nextheader field
33 * of the extension header directly preceding the encapsulation header, or in
34 * its absence, that of the top IP header. The value of skb->data will always
35 * point to the top IP header.
36 */
37static void xfrm6_encap(struct sk_buff *skb)
38{
39 struct dst_entry *dst = skb->dst;
40 struct xfrm_state *x = dst->xfrm;
41 struct ipv6hdr *iph, *top_iph;
42 int dsfield;
43
44 skb_push(skb, x->props.header_len);
45 iph = skb->nh.ipv6h;
46
47 if (!x->props.mode) {
48 u8 *prevhdr;
49 int hdr_len;
50
51 hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
52 skb->nh.raw = prevhdr - x->props.header_len;
53 skb->h.raw = skb->data + hdr_len;
54 memmove(skb->data, iph, hdr_len);
55 return;
56 }
57
58 skb->nh.raw = skb->data;
59 top_iph = skb->nh.ipv6h;
60 skb->nh.raw = &top_iph->nexthdr;
61 skb->h.ipv6h = top_iph + 1;
62
63 top_iph->version = 6;
64 top_iph->priority = iph->priority;
65 top_iph->flow_lbl[0] = iph->flow_lbl[0];
66 top_iph->flow_lbl[1] = iph->flow_lbl[1];
67 top_iph->flow_lbl[2] = iph->flow_lbl[2];
68 dsfield = ipv6_get_dsfield(top_iph);
69 dsfield = INET_ECN_encapsulate(dsfield, dsfield);
70 if (x->props.flags & XFRM_STATE_NOECN)
71 dsfield &= ~INET_ECN_MASK;
72 ipv6_change_dsfield(top_iph, 0, dsfield);
73 top_iph->nexthdr = IPPROTO_IPV6;
74 top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
75 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
76 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
77}
78
79static int xfrm6_tunnel_check_size(struct sk_buff *skb) 20static int xfrm6_tunnel_check_size(struct sk_buff *skb)
80{ 21{
81 int mtu, ret = 0; 22 int mtu, ret = 0;
@@ -118,7 +59,9 @@ static int xfrm6_output_one(struct sk_buff *skb)
118 if (err) 59 if (err)
119 goto error; 60 goto error;
120 61
121 xfrm6_encap(skb); 62 err = x->mode->output(skb);
63 if (err)
64 goto error;
122 65
123 err = x->type->output(x, skb); 66 err = x->type->output(x, skb);
124 if (err) 67 if (err)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 88c840f1beb6..ee715f2691e9 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -23,8 +23,6 @@
23static struct dst_ops xfrm6_dst_ops; 23static struct dst_ops xfrm6_dst_ops;
24static struct xfrm_policy_afinfo xfrm6_policy_afinfo; 24static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
25 25
26static struct xfrm_type_map xfrm6_type_map = { .lock = RW_LOCK_UNLOCKED };
27
28static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) 26static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
29{ 27{
30 int err = 0; 28 int err = 0;
@@ -249,9 +247,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
249 247
250static inline int xfrm6_garbage_collect(void) 248static inline int xfrm6_garbage_collect(void)
251{ 249{
252 read_lock(&xfrm6_policy_afinfo.lock);
253 xfrm6_policy_afinfo.garbage_collect(); 250 xfrm6_policy_afinfo.garbage_collect();
254 read_unlock(&xfrm6_policy_afinfo.lock);
255 return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); 251 return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2);
256} 252}
257 253
@@ -311,8 +307,6 @@ static struct dst_ops xfrm6_dst_ops = {
311 307
312static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { 308static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
313 .family = AF_INET6, 309 .family = AF_INET6,
314 .lock = RW_LOCK_UNLOCKED,
315 .type_map = &xfrm6_type_map,
316 .dst_ops = &xfrm6_dst_ops, 310 .dst_ops = &xfrm6_dst_ops,
317 .dst_lookup = xfrm6_dst_lookup, 311 .dst_lookup = xfrm6_dst_lookup,
318 .find_bundle = __xfrm6_find_bundle, 312 .find_bundle = __xfrm6_find_bundle,
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index a5723024d3b3..b33296b3f6de 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -135,7 +135,6 @@ __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
135 135
136static struct xfrm_state_afinfo xfrm6_state_afinfo = { 136static struct xfrm_state_afinfo xfrm6_state_afinfo = {
137 .family = AF_INET6, 137 .family = AF_INET6,
138 .lock = RW_LOCK_UNLOCKED,
139 .init_tempsel = __xfrm6_init_tempsel, 138 .init_tempsel = __xfrm6_init_tempsel,
140 .state_lookup = __xfrm6_state_lookup, 139 .state_lookup = __xfrm6_state_lookup,
141 .find_acq = __xfrm6_find_acq, 140 .find_acq = __xfrm6_find_acq,